diff --git a/Source/3rd Party/wx/include/msvc/wx/setup.h b/Source/3rd Party/wx/include/msvc/wx/setup.h index 7cc58760b..827a5c227 100644 --- a/Source/3rd Party/wx/include/msvc/wx/setup.h +++ b/Source/3rd Party/wx/include/msvc/wx/setup.h @@ -145,8 +145,6 @@ #ifdef _DEBUG #pragma comment(lib,"wxbase28d") - #pragma comment(lib,"wxbase28d_net") - #pragma comment(lib,"wxbase28d_xml") #if wxUSE_REGEX #pragma comment(lib,"wxregexd") #endif @@ -167,9 +165,7 @@ #if wxUSE_ZLIB #pragma comment(lib,"wxzlibd") #endif - #pragma comment(lib,"wxmsw28d_adv") #pragma comment(lib,"wxmsw28d_core") - #pragma comment(lib,"wxmsw28d_html") #if wxUSE_GLCANVAS #pragma comment(lib,"wxmsw28d_gl") #endif diff --git a/Source/3rd Party/wx/include/wx/msw/gsockmsw.h b/Source/3rd Party/wx/include/wx/msw/gsockmsw.h index 6b5149ebb..6e5486992 100644 --- a/Source/3rd Party/wx/include/wx/msw/gsockmsw.h +++ b/Source/3rd Party/wx/include/wx/msw/gsockmsw.h @@ -31,7 +31,7 @@ # include #endif -#if defined(__WXWINCE__) || defined(__CYGWIN__) +#if defined(__WXWINCE__) || defined(__CYGWIN__) || defined(__WXMSW__) #include #endif diff --git a/Source/3rd Party/wx/include/wx/msw/setup.h b/Source/3rd Party/wx/include/wx/msw/setup.h index 2497beddc..36147b18f 100644 --- a/Source/3rd Party/wx/include/wx/msw/setup.h +++ b/Source/3rd Party/wx/include/wx/msw/setup.h @@ -139,7 +139,7 @@ // // Recommended setting: 1, it is compiled into a separate library so there // is no overhead if you don't use it -#define wxUSE_DEBUGREPORT 1 +#define wxUSE_DEBUGREPORT 0 // ---------------------------------------------------------------------------- // Unicode support @@ -520,7 +520,7 @@ // // Recommended setting: 1 if your compiler supports it, if it doesn't please // contribute us a makefile for src/regex for it -#define wxUSE_REGEX 1 +#define wxUSE_REGEX 0 // wxSystemOptions class #define wxUSE_SYSTEM_OPTIONS 1 @@ -533,7 +533,7 @@ // Default is 1. // // Recommended setting: 1 -#define wxUSE_MEDIACTRL 1 +#define wxUSE_MEDIACTRL 0 // Use GStreamer for Unix (req a lot of dependancies) // @@ -547,7 +547,7 @@ // Default is 1 // // Recommended setting: 1 (requires wxUSE_XML) -#define wxUSE_XRC 1 +#define wxUSE_XRC 0 // XML parsing classes. Note that their API will change in the future, so // using wxXmlDocument and wxXmlNode in your app is not recommended. @@ -562,7 +562,7 @@ // Default is 1 // // Recommended setting: 1 -#define wxUSE_AUI 1 +#define wxUSE_AUI 0 // Enable the new wxGraphicsPath and wxGraphicsContext classes for an advanced @@ -1011,7 +1011,7 @@ // // Recommended setting: 1, set to 0 if you want compile a // smaller library. -#define wxUSE_RICHTEXT 1 +#define wxUSE_RICHTEXT 0 // ---------------------------------------------------------------------------- // Data transfer @@ -1170,25 +1170,25 @@ #define wxUSE_LIBJPEG 1 // Set to 1 for TIFF format support (requires libtiff) -#define wxUSE_LIBTIFF 1 +#define wxUSE_LIBTIFF 0 // Set to 1 for TGA format support (loading only) -#define wxUSE_TGA 1 +#define wxUSE_TGA 0 // Set to 1 for GIF format support -#define wxUSE_GIF 1 +#define wxUSE_GIF 0 // Set to 1 for PNM format support -#define wxUSE_PNM 1 +#define wxUSE_PNM 0 // Set to 1 for PCX format support -#define wxUSE_PCX 1 +#define wxUSE_PCX 0 // Set to 1 for IFF format support (Amiga format) #define wxUSE_IFF 0 // Set to 1 for XPM format support -#define wxUSE_XPM 1 +#define wxUSE_XPM 0 // Set to 1 for MS Icons and Cursors format support #define wxUSE_ICO_CUR 1 diff --git a/Source/3rd Party/wx/include/wx/private/browserhack28.h b/Source/3rd Party/wx/include/wx/private/browserhack28.h new file mode 100644 index 000000000..28d6da71b --- /dev/null +++ b/Source/3rd Party/wx/include/wx/private/browserhack28.h @@ -0,0 +1,20 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: wx/private/browserhack28.h +// Purpose: Allows GUI library to override base wxLaunchDefaultBrowser. +// Author: David Elliott +// Modified by: +// Created: 2007-08-19 +// RCS-ID: $Id: browserhack28.h 48184 2007-08-19 19:22:09Z DE $ +// Copyright: (c) David Elliott +// Licence: wxWidgets licence +///////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_PRIVATE_BROWSERHACK28_H_ +#define _WX_PRIVATE_BROWSERHACK28_H_ + +typedef bool (*wxLaunchDefaultBrowserImpl_t)(const wxString& url, int flags); + +// Function the GUI library can call to provide a better implementation +WXDLLIMPEXP_BASE void wxSetLaunchDefaultBrowserImpl(wxLaunchDefaultBrowserImpl_t newImpl); + +#endif //ndef _WX_PRIVATE_BROWSERHACK28_H_ diff --git a/Source/3rd Party/wx/include/wx/utils.h b/Source/3rd Party/wx/include/wx/utils.h index 04a30ec3b..3ceca747a 100644 --- a/Source/3rd Party/wx/include/wx/utils.h +++ b/Source/3rd Party/wx/include/wx/utils.h @@ -8,7 +8,6 @@ // Copyright: (c) 1998 Julian Smart // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// - #ifndef _WX_UTILSH__ #define _WX_UTILSH__ diff --git a/Source/3rd Party/wx/lib/vc_lib/mswd/wx/setup.h b/Source/3rd Party/wx/lib/vc_lib/mswd/wx/setup.h index 2497beddc..36147b18f 100644 --- a/Source/3rd Party/wx/lib/vc_lib/mswd/wx/setup.h +++ b/Source/3rd Party/wx/lib/vc_lib/mswd/wx/setup.h @@ -139,7 +139,7 @@ // // Recommended setting: 1, it is compiled into a separate library so there // is no overhead if you don't use it -#define wxUSE_DEBUGREPORT 1 +#define wxUSE_DEBUGREPORT 0 // ---------------------------------------------------------------------------- // Unicode support @@ -520,7 +520,7 @@ // // Recommended setting: 1 if your compiler supports it, if it doesn't please // contribute us a makefile for src/regex for it -#define wxUSE_REGEX 1 +#define wxUSE_REGEX 0 // wxSystemOptions class #define wxUSE_SYSTEM_OPTIONS 1 @@ -533,7 +533,7 @@ // Default is 1. // // Recommended setting: 1 -#define wxUSE_MEDIACTRL 1 +#define wxUSE_MEDIACTRL 0 // Use GStreamer for Unix (req a lot of dependancies) // @@ -547,7 +547,7 @@ // Default is 1 // // Recommended setting: 1 (requires wxUSE_XML) -#define wxUSE_XRC 1 +#define wxUSE_XRC 0 // XML parsing classes. Note that their API will change in the future, so // using wxXmlDocument and wxXmlNode in your app is not recommended. @@ -562,7 +562,7 @@ // Default is 1 // // Recommended setting: 1 -#define wxUSE_AUI 1 +#define wxUSE_AUI 0 // Enable the new wxGraphicsPath and wxGraphicsContext classes for an advanced @@ -1011,7 +1011,7 @@ // // Recommended setting: 1, set to 0 if you want compile a // smaller library. -#define wxUSE_RICHTEXT 1 +#define wxUSE_RICHTEXT 0 // ---------------------------------------------------------------------------- // Data transfer @@ -1170,25 +1170,25 @@ #define wxUSE_LIBJPEG 1 // Set to 1 for TIFF format support (requires libtiff) -#define wxUSE_LIBTIFF 1 +#define wxUSE_LIBTIFF 0 // Set to 1 for TGA format support (loading only) -#define wxUSE_TGA 1 +#define wxUSE_TGA 0 // Set to 1 for GIF format support -#define wxUSE_GIF 1 +#define wxUSE_GIF 0 // Set to 1 for PNM format support -#define wxUSE_PNM 1 +#define wxUSE_PNM 0 // Set to 1 for PCX format support -#define wxUSE_PCX 1 +#define wxUSE_PCX 0 // Set to 1 for IFF format support (Amiga format) #define wxUSE_IFF 0 // Set to 1 for XPM format support -#define wxUSE_XPM 1 +#define wxUSE_XPM 0 // Set to 1 for MS Icons and Cursors format support #define wxUSE_ICO_CUR 1 diff --git a/Source/3rd Party/wx/lib/vc_lib/mswud/wx/setup.h b/Source/3rd Party/wx/lib/vc_lib/mswud/wx/setup.h index 2497beddc..36147b18f 100644 --- a/Source/3rd Party/wx/lib/vc_lib/mswud/wx/setup.h +++ b/Source/3rd Party/wx/lib/vc_lib/mswud/wx/setup.h @@ -139,7 +139,7 @@ // // Recommended setting: 1, it is compiled into a separate library so there // is no overhead if you don't use it -#define wxUSE_DEBUGREPORT 1 +#define wxUSE_DEBUGREPORT 0 // ---------------------------------------------------------------------------- // Unicode support @@ -520,7 +520,7 @@ // // Recommended setting: 1 if your compiler supports it, if it doesn't please // contribute us a makefile for src/regex for it -#define wxUSE_REGEX 1 +#define wxUSE_REGEX 0 // wxSystemOptions class #define wxUSE_SYSTEM_OPTIONS 1 @@ -533,7 +533,7 @@ // Default is 1. // // Recommended setting: 1 -#define wxUSE_MEDIACTRL 1 +#define wxUSE_MEDIACTRL 0 // Use GStreamer for Unix (req a lot of dependancies) // @@ -547,7 +547,7 @@ // Default is 1 // // Recommended setting: 1 (requires wxUSE_XML) -#define wxUSE_XRC 1 +#define wxUSE_XRC 0 // XML parsing classes. Note that their API will change in the future, so // using wxXmlDocument and wxXmlNode in your app is not recommended. @@ -562,7 +562,7 @@ // Default is 1 // // Recommended setting: 1 -#define wxUSE_AUI 1 +#define wxUSE_AUI 0 // Enable the new wxGraphicsPath and wxGraphicsContext classes for an advanced @@ -1011,7 +1011,7 @@ // // Recommended setting: 1, set to 0 if you want compile a // smaller library. -#define wxUSE_RICHTEXT 1 +#define wxUSE_RICHTEXT 0 // ---------------------------------------------------------------------------- // Data transfer @@ -1170,25 +1170,25 @@ #define wxUSE_LIBJPEG 1 // Set to 1 for TIFF format support (requires libtiff) -#define wxUSE_LIBTIFF 1 +#define wxUSE_LIBTIFF 0 // Set to 1 for TGA format support (loading only) -#define wxUSE_TGA 1 +#define wxUSE_TGA 0 // Set to 1 for GIF format support -#define wxUSE_GIF 1 +#define wxUSE_GIF 0 // Set to 1 for PNM format support -#define wxUSE_PNM 1 +#define wxUSE_PNM 0 // Set to 1 for PCX format support -#define wxUSE_PCX 1 +#define wxUSE_PCX 0 // Set to 1 for IFF format support (Amiga format) #define wxUSE_IFF 0 // Set to 1 for XPM format support -#define wxUSE_XPM 1 +#define wxUSE_XPM 0 // Set to 1 for MS Icons and Cursors format support #define wxUSE_ICO_CUR 1 diff --git a/Source/3rd Party/wx/src/common/accesscmn.cpp b/Source/3rd Party/wx/src/common/accesscmn.cpp index 14135977e..168425822 100644 --- a/Source/3rd Party/wx/src/common/accesscmn.cpp +++ b/Source/3rd Party/wx/src/common/accesscmn.cpp @@ -1,26 +1,26 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: common/accesscmn.cpp -// Author: Julian Smart -// Modified by: -// Created: 2003-02-12 -// RCS-ID: $Id: accesscmn.cpp 35650 2005-09-23 12:56:45Z MR $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ACCESSIBILITY - -#include "wx/access.h" - -#endif - +/////////////////////////////////////////////////////////////////////////////// +// Name: common/accesscmn.cpp +// Author: Julian Smart +// Modified by: +// Created: 2003-02-12 +// RCS-ID: $Id: accesscmn.cpp 35650 2005-09-23 12:56:45Z MR $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ACCESSIBILITY + +#include "wx/access.h" + +#endif + diff --git a/Source/3rd Party/wx/src/common/anidecod.cpp b/Source/3rd Party/wx/src/common/anidecod.cpp index f10817c58..4a905f802 100644 --- a/Source/3rd Party/wx/src/common/anidecod.cpp +++ b/Source/3rd Party/wx/src/common/anidecod.cpp @@ -1,345 +1,345 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/anidecod.cpp -// Purpose: wxANIDecoder, ANI reader for wxImage and wxAnimation -// Author: Francesco Montorsi -// RCS-ID: $Id: anidecod.cpp 43898 2006-12-10 14:18:37Z VZ $ -// Copyright: (c) Francesco Montorsi -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS && wxUSE_ICO_CUR - -#include "wx/anidecod.h" - -#ifndef WX_PRECOMP - #include "wx/palette.h" -#endif - -#include -#include - -// static -wxCURHandler wxANIDecoder::sm_handler; - -//--------------------------------------------------------------------------- -// wxANIFrameInfo -//--------------------------------------------------------------------------- - -class wxANIFrameInfo -{ -public: - wxANIFrameInfo(unsigned int delay = 0, int idx = -1) - { m_delay=delay; m_imageIndex=idx; } - - unsigned int m_delay; - int m_imageIndex; -}; - -#include "wx/arrimpl.cpp" // this is a magic incantation which must be done! -WX_DEFINE_OBJARRAY(wxImageArray) - -#include "wx/arrimpl.cpp" // this is a magic incantation which must be done! -WX_DEFINE_OBJARRAY(wxANIFrameInfoArray) - - -//--------------------------------------------------------------------------- -// wxANIDecoder -//--------------------------------------------------------------------------- - -wxANIDecoder::wxANIDecoder() -{ -} - -wxANIDecoder::~wxANIDecoder() -{ -} - -bool wxANIDecoder::ConvertToImage(unsigned int frame, wxImage *image) const -{ - unsigned int idx = m_info[frame].m_imageIndex; - *image = m_images[idx]; // copy - return image->IsOk(); -} - - -//--------------------------------------------------------------------------- -// Data accessors -//--------------------------------------------------------------------------- - -wxSize wxANIDecoder::GetFrameSize(unsigned int WXUNUSED(frame)) const -{ - // all frames are of the same size... - return m_szAnimation; -} - -wxPoint wxANIDecoder::GetFramePosition(unsigned int WXUNUSED(frame)) const -{ - // all frames are of the same size... - return wxPoint(0,0); -} - -wxAnimationDisposal wxANIDecoder::GetDisposalMethod(unsigned int WXUNUSED(frame)) const -{ - // this disposal is implicit for all frames inside an ANI file - return wxANIM_TOBACKGROUND; -} - -long wxANIDecoder::GetDelay(unsigned int frame) const -{ - return m_info[frame].m_delay; -} - -wxColour wxANIDecoder::GetTransparentColour(unsigned int frame) const -{ - unsigned int idx = m_info[frame].m_imageIndex; - - if (!m_images[idx].HasMask()) - return wxNullColour; - - return wxColour(m_images[idx].GetMaskRed(), - m_images[idx].GetMaskGreen(), - m_images[idx].GetMaskBlue()); -} - - -//--------------------------------------------------------------------------- -// ANI reading and decoding -//--------------------------------------------------------------------------- - -bool wxANIDecoder::CanRead(wxInputStream& stream) const -{ - wxInt32 FCC1, FCC2; - wxUint32 datalen ; - - wxInt32 riff32; - memcpy( &riff32, "RIFF", 4 ); - wxInt32 list32; - memcpy( &list32, "LIST", 4 ); - wxInt32 ico32; - memcpy( &ico32, "icon", 4 ); - wxInt32 anih32; - memcpy( &anih32, "anih", 4 ); - - stream.SeekI(0); - if ( !stream.Read(&FCC1, 4) ) - return false; - - if ( FCC1 != riff32 ) - return false; - - // we have a riff file: - while ( stream.IsOk() ) - { - if ( FCC1 == anih32 ) - return true; // found the ANIH chunk - this should be an ANI file - - // we always have a data size: - stream.Read(&datalen, 4); - datalen = wxINT32_SWAP_ON_BE(datalen) ; - - // data should be padded to make even number of bytes - if (datalen % 2 == 1) datalen ++ ; - - // now either data or a FCC: - if ( (FCC1 == riff32) || (FCC1 == list32) ) - { - stream.Read(&FCC2, 4); - } - else - { - stream.SeekI(stream.TellI() + datalen); - } - - // try to read next data chunk: - if ( !stream.Read(&FCC1, 4) ) - { - // reading failed -- either EOF or IO error, bail out anyhow - return false; - } - } - - return false; -} - -// the "anih" RIFF chunk -struct wxANIHeader -{ - wxInt32 cbSizeOf; // Num bytes in AniHeader (36 bytes) - wxInt32 cFrames; // Number of unique Icons in this cursor - wxInt32 cSteps; // Number of Blits before the animation cycles - wxInt32 cx; // width of the frames - wxInt32 cy; // height of the frames - wxInt32 cBitCount; // bit depth - wxInt32 cPlanes; // 1 - wxInt32 JifRate; // Default Jiffies (1/60th of a second) if rate chunk not present. - wxInt32 flags; // Animation Flag (see AF_ constants) - - // ANI files are always little endian so we need to swap bytes on big - // endian architectures -#ifdef WORDS_BIGENDIAN - void AdjustEndianness() - { - // this works because all our fields are wxInt32 and they must be - // packed without holes between them (if they're not, they wouldn't map - // to the file header!) - wxInt32 * const start = (wxInt32 *)this; - wxInt32 * const end = start + sizeof(wxANIHeader)/sizeof(wxInt32); - for ( wxInt32 *p = start; p != end; p++ ) - { - *p = wxINT32_SWAP_ALWAYS(*p); - } - } -#else - void AdjustEndianness() { } -#endif -}; - -bool wxANIDecoder::Load( wxInputStream& stream ) -{ - wxInt32 FCC1, FCC2; - wxUint32 datalen; - unsigned int globaldelay=0; - - wxInt32 riff32; - memcpy( &riff32, "RIFF", 4 ); - wxInt32 list32; - memcpy( &list32, "LIST", 4 ); - wxInt32 ico32; - memcpy( &ico32, "icon", 4 ); - wxInt32 anih32; - memcpy( &anih32, "anih", 4 ); - wxInt32 rate32; - memcpy( &rate32, "rate", 4 ); - wxInt32 seq32; - memcpy( &seq32, "seq ", 4 ); - - stream.SeekI(0); - stream.Read(&FCC1, 4); - if ( FCC1 != riff32 ) - return false; - - m_nFrames = 0; - m_szAnimation = wxDefaultSize; - - m_images.Clear(); - m_info.Clear(); - - // we have a riff file: - while ( stream.IsOk() ) - { - // we always have a data size: - stream.Read(&datalen, 4); - datalen = wxINT32_SWAP_ON_BE(datalen); - - //data should be padded to make even number of bytes - if (datalen % 2 == 1) datalen++; - - // now either data or a FCC: - if ( (FCC1 == riff32) || (FCC1 == list32) ) - { - stream.Read(&FCC2, 4); - } - else if ( FCC1 == anih32 ) - { - if ( datalen != sizeof(wxANIHeader) ) - return false; - - if (m_nFrames > 0) - return false; // already parsed an ani header? - - struct wxANIHeader header; - stream.Read(&header, sizeof(wxANIHeader)); - header.AdjustEndianness(); - - // we should have a global frame size - m_szAnimation = wxSize(header.cx, header.cy); - - // save interesting info from the header - m_nFrames = header.cSteps; // NB: not cFrames!! - if ( m_nFrames == 0 ) - return false; - - globaldelay = header.JifRate * 1000 / 60; - - m_images.Alloc(header.cFrames); - m_info.Add(wxANIFrameInfo(), m_nFrames); - } - else if ( FCC1 == rate32 ) - { - // did we already process the anih32 chunk? - if (m_nFrames == 0) - return false; // rate chunks should always be placed after anih chunk - - wxASSERT(m_info.GetCount() == m_nFrames); - for (unsigned int i=0; i +#include + +// static +wxCURHandler wxANIDecoder::sm_handler; + +//--------------------------------------------------------------------------- +// wxANIFrameInfo +//--------------------------------------------------------------------------- + +class wxANIFrameInfo +{ +public: + wxANIFrameInfo(unsigned int delay = 0, int idx = -1) + { m_delay=delay; m_imageIndex=idx; } + + unsigned int m_delay; + int m_imageIndex; +}; + +#include "wx/arrimpl.cpp" // this is a magic incantation which must be done! +WX_DEFINE_OBJARRAY(wxImageArray) + +#include "wx/arrimpl.cpp" // this is a magic incantation which must be done! +WX_DEFINE_OBJARRAY(wxANIFrameInfoArray) + + +//--------------------------------------------------------------------------- +// wxANIDecoder +//--------------------------------------------------------------------------- + +wxANIDecoder::wxANIDecoder() +{ +} + +wxANIDecoder::~wxANIDecoder() +{ +} + +bool wxANIDecoder::ConvertToImage(unsigned int frame, wxImage *image) const +{ + unsigned int idx = m_info[frame].m_imageIndex; + *image = m_images[idx]; // copy + return image->IsOk(); +} + + +//--------------------------------------------------------------------------- +// Data accessors +//--------------------------------------------------------------------------- + +wxSize wxANIDecoder::GetFrameSize(unsigned int WXUNUSED(frame)) const +{ + // all frames are of the same size... + return m_szAnimation; +} + +wxPoint wxANIDecoder::GetFramePosition(unsigned int WXUNUSED(frame)) const +{ + // all frames are of the same size... + return wxPoint(0,0); +} + +wxAnimationDisposal wxANIDecoder::GetDisposalMethod(unsigned int WXUNUSED(frame)) const +{ + // this disposal is implicit for all frames inside an ANI file + return wxANIM_TOBACKGROUND; +} + +long wxANIDecoder::GetDelay(unsigned int frame) const +{ + return m_info[frame].m_delay; +} + +wxColour wxANIDecoder::GetTransparentColour(unsigned int frame) const +{ + unsigned int idx = m_info[frame].m_imageIndex; + + if (!m_images[idx].HasMask()) + return wxNullColour; + + return wxColour(m_images[idx].GetMaskRed(), + m_images[idx].GetMaskGreen(), + m_images[idx].GetMaskBlue()); +} + + +//--------------------------------------------------------------------------- +// ANI reading and decoding +//--------------------------------------------------------------------------- + +bool wxANIDecoder::CanRead(wxInputStream& stream) const +{ + wxInt32 FCC1, FCC2; + wxUint32 datalen ; + + wxInt32 riff32; + memcpy( &riff32, "RIFF", 4 ); + wxInt32 list32; + memcpy( &list32, "LIST", 4 ); + wxInt32 ico32; + memcpy( &ico32, "icon", 4 ); + wxInt32 anih32; + memcpy( &anih32, "anih", 4 ); + + stream.SeekI(0); + if ( !stream.Read(&FCC1, 4) ) + return false; + + if ( FCC1 != riff32 ) + return false; + + // we have a riff file: + while ( stream.IsOk() ) + { + if ( FCC1 == anih32 ) + return true; // found the ANIH chunk - this should be an ANI file + + // we always have a data size: + stream.Read(&datalen, 4); + datalen = wxINT32_SWAP_ON_BE(datalen) ; + + // data should be padded to make even number of bytes + if (datalen % 2 == 1) datalen ++ ; + + // now either data or a FCC: + if ( (FCC1 == riff32) || (FCC1 == list32) ) + { + stream.Read(&FCC2, 4); + } + else + { + stream.SeekI(stream.TellI() + datalen); + } + + // try to read next data chunk: + if ( !stream.Read(&FCC1, 4) ) + { + // reading failed -- either EOF or IO error, bail out anyhow + return false; + } + } + + return false; +} + +// the "anih" RIFF chunk +struct wxANIHeader +{ + wxInt32 cbSizeOf; // Num bytes in AniHeader (36 bytes) + wxInt32 cFrames; // Number of unique Icons in this cursor + wxInt32 cSteps; // Number of Blits before the animation cycles + wxInt32 cx; // width of the frames + wxInt32 cy; // height of the frames + wxInt32 cBitCount; // bit depth + wxInt32 cPlanes; // 1 + wxInt32 JifRate; // Default Jiffies (1/60th of a second) if rate chunk not present. + wxInt32 flags; // Animation Flag (see AF_ constants) + + // ANI files are always little endian so we need to swap bytes on big + // endian architectures +#ifdef WORDS_BIGENDIAN + void AdjustEndianness() + { + // this works because all our fields are wxInt32 and they must be + // packed without holes between them (if they're not, they wouldn't map + // to the file header!) + wxInt32 * const start = (wxInt32 *)this; + wxInt32 * const end = start + sizeof(wxANIHeader)/sizeof(wxInt32); + for ( wxInt32 *p = start; p != end; p++ ) + { + *p = wxINT32_SWAP_ALWAYS(*p); + } + } +#else + void AdjustEndianness() { } +#endif +}; + +bool wxANIDecoder::Load( wxInputStream& stream ) +{ + wxInt32 FCC1, FCC2; + wxUint32 datalen; + unsigned int globaldelay=0; + + wxInt32 riff32; + memcpy( &riff32, "RIFF", 4 ); + wxInt32 list32; + memcpy( &list32, "LIST", 4 ); + wxInt32 ico32; + memcpy( &ico32, "icon", 4 ); + wxInt32 anih32; + memcpy( &anih32, "anih", 4 ); + wxInt32 rate32; + memcpy( &rate32, "rate", 4 ); + wxInt32 seq32; + memcpy( &seq32, "seq ", 4 ); + + stream.SeekI(0); + stream.Read(&FCC1, 4); + if ( FCC1 != riff32 ) + return false; + + m_nFrames = 0; + m_szAnimation = wxDefaultSize; + + m_images.Clear(); + m_info.Clear(); + + // we have a riff file: + while ( stream.IsOk() ) + { + // we always have a data size: + stream.Read(&datalen, 4); + datalen = wxINT32_SWAP_ON_BE(datalen); + + //data should be padded to make even number of bytes + if (datalen % 2 == 1) datalen++; + + // now either data or a FCC: + if ( (FCC1 == riff32) || (FCC1 == list32) ) + { + stream.Read(&FCC2, 4); + } + else if ( FCC1 == anih32 ) + { + if ( datalen != sizeof(wxANIHeader) ) + return false; + + if (m_nFrames > 0) + return false; // already parsed an ani header? + + struct wxANIHeader header; + stream.Read(&header, sizeof(wxANIHeader)); + header.AdjustEndianness(); + + // we should have a global frame size + m_szAnimation = wxSize(header.cx, header.cy); + + // save interesting info from the header + m_nFrames = header.cSteps; // NB: not cFrames!! + if ( m_nFrames == 0 ) + return false; + + globaldelay = header.JifRate * 1000 / 60; + + m_images.Alloc(header.cFrames); + m_info.Add(wxANIFrameInfo(), m_nFrames); + } + else if ( FCC1 == rate32 ) + { + // did we already process the anih32 chunk? + if (m_nFrames == 0) + return false; // rate chunks should always be placed after anih chunk + + wxASSERT(m_info.GetCount() == m_nFrames); + for (unsigned int i=0; i -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/wrapwin.h" // includes windows.h for MessageBox() - #endif - #include "wx/list.h" - #include "wx/app.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" -#endif //WX_PRECOMP - -#include "wx/apptrait.h" -#include "wx/cmdline.h" -#include "wx/confbase.h" -#include "wx/filename.h" -#include "wx/msgout.h" -#include "wx/tokenzr.h" - -#if !defined(__WXMSW__) || defined(__WXMICROWIN__) - #include // for SIGTRAP used by wxTrap() -#endif //Win/Unix - -#if wxUSE_FONTMAP - #include "wx/fontmap.h" -#endif // wxUSE_FONTMAP - -#if defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS - // For MacTypes.h for Debugger function - #include -#endif - -#if defined(__WXMAC__) - #ifdef __DARWIN__ - #include - #else - #include "wx/mac/private.h" // includes mac headers - #endif -#endif // __WXMAC__ - -#ifdef __WXDEBUG__ - #if wxUSE_STACKWALKER - #include "wx/stackwalk.h" - #ifdef __WXMSW__ - #include "wx/msw/debughlp.h" - #endif - #endif // wxUSE_STACKWALKER - - #include "wx/recguard.h" -#endif // __WXDEBUG__ - -// wxABI_VERSION can be defined when compiling applications but it should be -// left undefined when compiling the library itself, it is then set to its -// default value in version.h -#if wxABI_VERSION != wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + 99 -#error "wxABI_VERSION should not be defined when compiling the library" -#endif - -// ---------------------------------------------------------------------------- -// private functions prototypes -// ---------------------------------------------------------------------------- - -#ifdef __WXDEBUG__ - // really just show the assert dialog - static bool DoShowAssertDialog(const wxString& msg); - - // prepare for showing the assert dialog, use the given traits or - // DoShowAssertDialog() as last fallback to really show it - static - void ShowAssertDialog(const wxChar *szFile, - int nLine, - const wxChar *szFunc, - const wxChar *szCond, - const wxChar *szMsg, - wxAppTraits *traits = NULL); - - // turn on the trace masks specified in the env variable WXTRACE - static void LINKAGEMODE SetTraceMasks(); -#endif // __WXDEBUG__ - -// ---------------------------------------------------------------------------- -// global vars -// ---------------------------------------------------------------------------- - -wxAppConsole *wxAppConsole::ms_appInstance = NULL; - -wxAppInitializerFunction wxAppConsole::ms_appInitFn = NULL; - -// ============================================================================ -// wxAppConsole implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// ctor/dtor -// ---------------------------------------------------------------------------- - -wxAppConsole::wxAppConsole() -{ - m_traits = NULL; - - ms_appInstance = this; - -#ifdef __WXDEBUG__ - SetTraceMasks(); -#if wxUSE_UNICODE - // In unicode mode the SetTraceMasks call can cause an apptraits to be - // created, but since we are still in the constructor the wrong kind will - // be created for GUI apps. Destroy it so it can be created again later. - delete m_traits; - m_traits = NULL; -#endif -#endif -} - -wxAppConsole::~wxAppConsole() -{ - delete m_traits; -} - -// ---------------------------------------------------------------------------- -// initilization/cleanup -// ---------------------------------------------------------------------------- - -bool wxAppConsole::Initialize(int& argcOrig, wxChar **argvOrig) -{ - // remember the command line arguments - argc = argcOrig; - argv = argvOrig; - -#ifndef __WXPALMOS__ - if ( m_appName.empty() && argv ) - { - // the application name is, by default, the name of its executable file - wxFileName::SplitPath(argv[0], NULL, &m_appName, NULL); - } -#endif - - return true; -} - -void wxAppConsole::CleanUp() -{ -} - -// ---------------------------------------------------------------------------- -// OnXXX() callbacks -// ---------------------------------------------------------------------------- - -bool wxAppConsole::OnInit() -{ -#if wxUSE_CMDLINE_PARSER - wxCmdLineParser parser(argc, argv); - - OnInitCmdLine(parser); - - bool cont; - switch ( parser.Parse(false /* don't show usage */) ) - { - case -1: - cont = OnCmdLineHelp(parser); - break; - - case 0: - cont = OnCmdLineParsed(parser); - break; - - default: - cont = OnCmdLineError(parser); - break; - } - - if ( !cont ) - return false; -#endif // wxUSE_CMDLINE_PARSER - - return true; -} - -int wxAppConsole::OnExit() -{ -#if wxUSE_CONFIG - // delete the config object if any (don't use Get() here, but Set() - // because Get() could create a new config object) - delete wxConfigBase::Set((wxConfigBase *) NULL); -#endif // wxUSE_CONFIG - - return 0; -} - -void wxAppConsole::Exit() -{ - exit(-1); -} - -// ---------------------------------------------------------------------------- -// traits stuff -// ---------------------------------------------------------------------------- - -wxAppTraits *wxAppConsole::CreateTraits() -{ - return new wxConsoleAppTraits; -} - -wxAppTraits *wxAppConsole::GetTraits() -{ - // FIXME-MT: protect this with a CS? - if ( !m_traits ) - { - m_traits = CreateTraits(); - - wxASSERT_MSG( m_traits, _T("wxApp::CreateTraits() failed?") ); - } - - return m_traits; -} - -// we must implement CreateXXX() in wxApp itself for backwards compatibility -#if WXWIN_COMPATIBILITY_2_4 - -#if wxUSE_LOG - -wxLog *wxAppConsole::CreateLogTarget() -{ - wxAppTraits *traits = GetTraits(); - return traits ? traits->CreateLogTarget() : NULL; -} - -#endif // wxUSE_LOG - -wxMessageOutput *wxAppConsole::CreateMessageOutput() -{ - wxAppTraits *traits = GetTraits(); - return traits ? traits->CreateMessageOutput() : NULL; -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -// ---------------------------------------------------------------------------- -// event processing -// ---------------------------------------------------------------------------- - -void wxAppConsole::ProcessPendingEvents() -{ -#if wxUSE_THREADS - if ( !wxPendingEventsLocker ) - return; -#endif - - // ensure that we're the only thread to modify the pending events list - wxENTER_CRIT_SECT( *wxPendingEventsLocker ); - - if ( !wxPendingEvents ) - { - wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); - return; - } - - // iterate until the list becomes empty - wxList::compatibility_iterator node = wxPendingEvents->GetFirst(); - while (node) - { - wxEvtHandler *handler = (wxEvtHandler *)node->GetData(); - wxPendingEvents->Erase(node); - - // In ProcessPendingEvents(), new handlers might be add - // and we can safely leave the critical section here. - wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); - - handler->ProcessPendingEvents(); - - wxENTER_CRIT_SECT( *wxPendingEventsLocker ); - - node = wxPendingEvents->GetFirst(); - } - - wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); -} - -int wxAppConsole::FilterEvent(wxEvent& WXUNUSED(event)) -{ - // process the events normally by default - return -1; -} - -// ---------------------------------------------------------------------------- -// exception handling -// ---------------------------------------------------------------------------- - -#if wxUSE_EXCEPTIONS - -void -wxAppConsole::HandleEvent(wxEvtHandler *handler, - wxEventFunction func, - wxEvent& event) const -{ - // by default, simply call the handler - (handler->*func)(event); -} - -#endif // wxUSE_EXCEPTIONS - -// ---------------------------------------------------------------------------- -// cmd line parsing -// ---------------------------------------------------------------------------- - -#if wxUSE_CMDLINE_PARSER - -#define OPTION_VERBOSE _T("verbose") - -void wxAppConsole::OnInitCmdLine(wxCmdLineParser& parser) -{ - // the standard command line options - static const wxCmdLineEntryDesc cmdLineDesc[] = - { - { - wxCMD_LINE_SWITCH, - _T("h"), - _T("help"), - gettext_noop("show this help message"), - wxCMD_LINE_VAL_NONE, - wxCMD_LINE_OPTION_HELP - }, - -#if wxUSE_LOG - { - wxCMD_LINE_SWITCH, - wxEmptyString, - OPTION_VERBOSE, - gettext_noop("generate verbose log messages"), - wxCMD_LINE_VAL_NONE, - 0x0 - }, -#endif // wxUSE_LOG - - // terminator - { - wxCMD_LINE_NONE, - wxEmptyString, - wxEmptyString, - wxEmptyString, - wxCMD_LINE_VAL_NONE, - 0x0 - } - }; - - parser.SetDesc(cmdLineDesc); -} - -bool wxAppConsole::OnCmdLineParsed(wxCmdLineParser& parser) -{ -#if wxUSE_LOG - if ( parser.Found(OPTION_VERBOSE) ) - { - wxLog::SetVerbose(true); - } -#else - wxUnusedVar(parser); -#endif // wxUSE_LOG - - return true; -} - -bool wxAppConsole::OnCmdLineHelp(wxCmdLineParser& parser) -{ - parser.Usage(); - - return false; -} - -bool wxAppConsole::OnCmdLineError(wxCmdLineParser& parser) -{ - parser.Usage(); - - return false; -} - -#endif // wxUSE_CMDLINE_PARSER - -// ---------------------------------------------------------------------------- -// debugging support -// ---------------------------------------------------------------------------- - -/* static */ -bool wxAppConsole::CheckBuildOptions(const char *optionsSignature, - const char *componentName) -{ -#if 0 // can't use wxLogTrace, not up and running yet - printf("checking build options object '%s' (ptr %p) in '%s'\n", - optionsSignature, optionsSignature, componentName); -#endif - - if ( strcmp(optionsSignature, WX_BUILD_OPTIONS_SIGNATURE) != 0 ) - { - wxString lib = wxString::FromAscii(WX_BUILD_OPTIONS_SIGNATURE); - wxString prog = wxString::FromAscii(optionsSignature); - wxString progName = wxString::FromAscii(componentName); - wxString msg; - - msg.Printf(_T("Mismatch between the program and library build versions detected.\nThe library used %s,\nand %s used %s."), - lib.c_str(), progName.c_str(), prog.c_str()); - - wxLogFatalError(msg.c_str()); - - // normally wxLogFatalError doesn't return - return false; - } -#undef wxCMP - - return true; -} - -#ifdef __WXDEBUG__ - -void wxAppConsole::OnAssertFailure(const wxChar *file, - int line, - const wxChar *func, - const wxChar *cond, - const wxChar *msg) -{ - ShowAssertDialog(file, line, func, cond, msg, GetTraits()); -} - -void wxAppConsole::OnAssert(const wxChar *file, - int line, - const wxChar *cond, - const wxChar *msg) -{ - OnAssertFailure(file, line, NULL, cond, msg); -} - -#endif // __WXDEBUG__ - -#if WXWIN_COMPATIBILITY_2_4 - -bool wxAppConsole::CheckBuildOptions(const wxBuildOptions& buildOptions) -{ - return CheckBuildOptions(buildOptions.m_signature, "your program"); -} - -#endif - -// ============================================================================ -// other classes implementations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxConsoleAppTraitsBase -// ---------------------------------------------------------------------------- - -#if wxUSE_LOG - -wxLog *wxConsoleAppTraitsBase::CreateLogTarget() -{ - return new wxLogStderr; -} - -#endif // wxUSE_LOG - -wxMessageOutput *wxConsoleAppTraitsBase::CreateMessageOutput() -{ - return new wxMessageOutputStderr; -} - -#if wxUSE_FONTMAP - -wxFontMapper *wxConsoleAppTraitsBase::CreateFontMapper() -{ - return (wxFontMapper *)new wxFontMapperBase; -} - -#endif // wxUSE_FONTMAP - -wxRendererNative *wxConsoleAppTraitsBase::CreateRenderer() -{ - // console applications don't use renderers - return NULL; -} - -#ifdef __WXDEBUG__ -bool wxConsoleAppTraitsBase::ShowAssertDialog(const wxString& msg) -{ - return wxAppTraitsBase::ShowAssertDialog(msg); -} -#endif - -bool wxConsoleAppTraitsBase::HasStderr() -{ - // console applications always have stderr, even under Mac/Windows - return true; -} - -void wxConsoleAppTraitsBase::ScheduleForDestroy(wxObject *object) -{ - delete object; -} - -void wxConsoleAppTraitsBase::RemoveFromPendingDelete(wxObject * WXUNUSED(object)) -{ - // nothing to do -} - -#if wxUSE_SOCKETS -GSocketGUIFunctionsTable* wxConsoleAppTraitsBase::GetSocketGUIFunctionsTable() -{ - return NULL; -} -#endif - -// ---------------------------------------------------------------------------- -// wxAppTraits -// ---------------------------------------------------------------------------- - -#ifdef __WXDEBUG__ - -bool wxAppTraitsBase::ShowAssertDialog(const wxString& msgOriginal) -{ - wxString msg = msgOriginal; - -#if wxUSE_STACKWALKER -#if !defined(__WXMSW__) - // on Unix stack frame generation may take some time, depending on the - // size of the executable mainly... warn the user that we are working - wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait")); - fflush(stderr); -#endif - - const wxString stackTrace = GetAssertStackTrace(); - if ( !stackTrace.empty() ) - msg << _T("\n\nCall stack:\n") << stackTrace; -#endif // wxUSE_STACKWALKER - - return DoShowAssertDialog(msg); -} - -#if wxUSE_STACKWALKER -wxString wxAppTraitsBase::GetAssertStackTrace() -{ - wxString stackTrace; - - class StackDump : public wxStackWalker - { - public: - StackDump() { } - - const wxString& GetStackTrace() const { return m_stackTrace; } - - protected: - virtual void OnStackFrame(const wxStackFrame& frame) - { - m_stackTrace << wxString::Format - ( - _T("[%02d] "), - wx_truncate_cast(int, frame.GetLevel()) - ); - - wxString name = frame.GetName(); - if ( !name.empty() ) - { - m_stackTrace << wxString::Format(_T("%-40s"), name.c_str()); - } - else - { - m_stackTrace << wxString::Format(_T("%p"), frame.GetAddress()); - } - - if ( frame.HasSourceLocation() ) - { - m_stackTrace << _T('\t') - << frame.GetFileName() - << _T(':') - << frame.GetLine(); - } - - m_stackTrace << _T('\n'); - } - - private: - wxString m_stackTrace; - }; - - // don't show more than maxLines or we could get a dialog too tall to be - // shown on screen: 20 should be ok everywhere as even with 15 pixel high - // characters it is still only 300 pixels... - static const int maxLines = 20; - - StackDump dump; - dump.Walk(2, maxLines); // don't show OnAssert() call itself - stackTrace = dump.GetStackTrace(); - - const int count = stackTrace.Freq(wxT('\n')); - for ( int i = 0; i < count - maxLines; i++ ) - stackTrace = stackTrace.BeforeLast(wxT('\n')); - - return stackTrace; -} -#endif // wxUSE_STACKWALKER - - -#endif // __WXDEBUG__ - -// ============================================================================ -// global functions implementation -// ============================================================================ - -void wxExit() -{ - if ( wxTheApp ) - { - wxTheApp->Exit(); - } - else - { - // what else can we do? - exit(-1); - } -} - -void wxWakeUpIdle() -{ - if ( wxTheApp ) - { - wxTheApp->WakeUpIdle(); - } - //else: do nothing, what can we do? -} - -#ifdef __WXDEBUG__ - -// wxASSERT() helper -bool wxAssertIsEqual(int x, int y) -{ - return x == y; -} - -// break into the debugger -void wxTrap() -{ -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - DebugBreak(); -#elif defined(__WXMAC__) && !defined(__DARWIN__) - #if __powerc - Debugger(); - #else - SysBreak(); - #endif -#elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS - Debugger(); -#elif defined(__UNIX__) - raise(SIGTRAP); -#else - // TODO -#endif // Win/Unix -} - -// this function is called when an assert fails -void wxOnAssert(const wxChar *szFile, - int nLine, - const char *szFunc, - const wxChar *szCond, - const wxChar *szMsg) -{ - // FIXME MT-unsafe - static int s_bInAssert = 0; - - wxRecursionGuard guard(s_bInAssert); - if ( guard.IsInside() ) - { - // can't use assert here to avoid infinite loops, so just trap - wxTrap(); - - return; - } - - // __FUNCTION__ is always in ASCII, convert it to wide char if needed - const wxString strFunc = wxString::FromAscii(szFunc); - - if ( !wxTheApp ) - { - // by default, show the assert dialog box -- we can't customize this - // behaviour - ShowAssertDialog(szFile, nLine, strFunc, szCond, szMsg); - } - else - { - // let the app process it as it wants - wxTheApp->OnAssertFailure(szFile, nLine, strFunc, szCond, szMsg); - } -} - -#endif // __WXDEBUG__ - -// ============================================================================ -// private functions implementation -// ============================================================================ - -#ifdef __WXDEBUG__ - -static void LINKAGEMODE SetTraceMasks() -{ -#if wxUSE_LOG - wxString mask; - if ( wxGetEnv(wxT("WXTRACE"), &mask) ) - { - wxStringTokenizer tkn(mask, wxT(",;:")); - while ( tkn.HasMoreTokens() ) - wxLog::AddTraceMask(tkn.GetNextToken()); - } -#endif // wxUSE_LOG -} - -bool DoShowAssertDialog(const wxString& msg) -{ - // under MSW we can show the dialog even in the console mode -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - wxString msgDlg(msg); - - // this message is intentionally not translated -- it is for - // developpers only - msgDlg += wxT("\nDo you want to stop the program?\n") - wxT("You can also choose [Cancel] to suppress ") - wxT("further warnings."); - - switch ( ::MessageBox(NULL, msgDlg, _T("wxWidgets Debug Alert"), - MB_YESNOCANCEL | MB_ICONSTOP ) ) - { - case IDYES: - wxTrap(); - break; - - case IDCANCEL: - // stop the asserts - return true; - - //case IDNO: nothing to do - } -#else // !__WXMSW__ - wxFprintf(stderr, wxT("%s\n"), msg.c_str()); - fflush(stderr); - - // TODO: ask the user to enter "Y" or "N" on the console? - wxTrap(); -#endif // __WXMSW__/!__WXMSW__ - - // continue with the asserts - return false; -} - -// show the assert modal dialog -static -void ShowAssertDialog(const wxChar *szFile, - int nLine, - const wxChar *szFunc, - const wxChar *szCond, - const wxChar *szMsg, - wxAppTraits *traits) -{ - // this variable can be set to true to suppress "assert failure" messages - static bool s_bNoAsserts = false; - - wxString msg; - msg.reserve(2048); - - // make life easier for people using VC++ IDE by using this format: like - // this, clicking on the message will take us immediately to the place of - // the failed assert - msg.Printf(wxT("%s(%d): assert \"%s\" failed"), szFile, nLine, szCond); - - // add the function name, if any - if ( szFunc && *szFunc ) - msg << _T(" in ") << szFunc << _T("()"); - - // and the message itself - if ( szMsg ) - { - msg << _T(": ") << szMsg; - } - else // no message given - { - msg << _T('.'); - } - -#if wxUSE_THREADS - // if we are not in the main thread, output the assert directly and trap - // since dialogs cannot be displayed - if ( !wxThread::IsMain() ) - { - msg += wxT(" [in child thread]"); - -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - msg << wxT("\r\n"); - OutputDebugString(msg ); -#else - // send to stderr - wxFprintf(stderr, wxT("%s\n"), msg.c_str()); - fflush(stderr); -#endif - // He-e-e-e-elp!! we're asserting in a child thread - wxTrap(); - } - else -#endif // wxUSE_THREADS - - if ( !s_bNoAsserts ) - { - // send it to the normal log destination - wxLogDebug(_T("%s"), msg.c_str()); - - if ( traits ) - { - // delegate showing assert dialog (if possible) to that class - s_bNoAsserts = traits->ShowAssertDialog(msg); - } - else // no traits object - { - // fall back to the function of last resort - s_bNoAsserts = DoShowAssertDialog(msg); - } - } -} - -#endif // __WXDEBUG__ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/appbase.cpp +// Purpose: implements wxAppConsole class +// Author: Vadim Zeitlin +// Modified by: +// Created: 19.06.2003 (extracted from common/appcmn.cpp) +// RCS-ID: $Id: appbase.cpp 52093 2008-02-25 13:43:07Z VZ $ +// Copyright: (c) 2003 Vadim Zeitlin +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" // includes windows.h for MessageBox() + #endif + #include "wx/list.h" + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" +#endif //WX_PRECOMP + +#include "wx/apptrait.h" +#include "wx/cmdline.h" +#include "wx/confbase.h" +#include "wx/filename.h" +#include "wx/msgout.h" +#include "wx/tokenzr.h" + +#if !defined(__WXMSW__) || defined(__WXMICROWIN__) + #include // for SIGTRAP used by wxTrap() +#endif //Win/Unix + +#if wxUSE_FONTMAP + #include "wx/fontmap.h" +#endif // wxUSE_FONTMAP + +#if defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS + // For MacTypes.h for Debugger function + #include +#endif + +#if defined(__WXMAC__) + #ifdef __DARWIN__ + #include + #else + #include "wx/mac/private.h" // includes mac headers + #endif +#endif // __WXMAC__ + +#ifdef __WXDEBUG__ + #if wxUSE_STACKWALKER + #include "wx/stackwalk.h" + #ifdef __WXMSW__ + #include "wx/msw/debughlp.h" + #endif + #endif // wxUSE_STACKWALKER + + #include "wx/recguard.h" +#endif // __WXDEBUG__ + +// wxABI_VERSION can be defined when compiling applications but it should be +// left undefined when compiling the library itself, it is then set to its +// default value in version.h +#if wxABI_VERSION != wxMAJOR_VERSION * 10000 + wxMINOR_VERSION * 100 + 99 +#error "wxABI_VERSION should not be defined when compiling the library" +#endif + +// ---------------------------------------------------------------------------- +// private functions prototypes +// ---------------------------------------------------------------------------- + +#ifdef __WXDEBUG__ + // really just show the assert dialog + static bool DoShowAssertDialog(const wxString& msg); + + // prepare for showing the assert dialog, use the given traits or + // DoShowAssertDialog() as last fallback to really show it + static + void ShowAssertDialog(const wxChar *szFile, + int nLine, + const wxChar *szFunc, + const wxChar *szCond, + const wxChar *szMsg, + wxAppTraits *traits = NULL); + + // turn on the trace masks specified in the env variable WXTRACE + static void LINKAGEMODE SetTraceMasks(); +#endif // __WXDEBUG__ + +// ---------------------------------------------------------------------------- +// global vars +// ---------------------------------------------------------------------------- + +wxAppConsole *wxAppConsole::ms_appInstance = NULL; + +wxAppInitializerFunction wxAppConsole::ms_appInitFn = NULL; + +// ============================================================================ +// wxAppConsole implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// ctor/dtor +// ---------------------------------------------------------------------------- + +wxAppConsole::wxAppConsole() +{ + m_traits = NULL; + + ms_appInstance = this; + +#ifdef __WXDEBUG__ + SetTraceMasks(); +#if wxUSE_UNICODE + // In unicode mode the SetTraceMasks call can cause an apptraits to be + // created, but since we are still in the constructor the wrong kind will + // be created for GUI apps. Destroy it so it can be created again later. + delete m_traits; + m_traits = NULL; +#endif +#endif +} + +wxAppConsole::~wxAppConsole() +{ + delete m_traits; +} + +// ---------------------------------------------------------------------------- +// initilization/cleanup +// ---------------------------------------------------------------------------- + +bool wxAppConsole::Initialize(int& argcOrig, wxChar **argvOrig) +{ + // remember the command line arguments + argc = argcOrig; + argv = argvOrig; + +#ifndef __WXPALMOS__ + if ( m_appName.empty() && argv ) + { + // the application name is, by default, the name of its executable file + wxFileName::SplitPath(argv[0], NULL, &m_appName, NULL); + } +#endif + + return true; +} + +void wxAppConsole::CleanUp() +{ +} + +// ---------------------------------------------------------------------------- +// OnXXX() callbacks +// ---------------------------------------------------------------------------- + +bool wxAppConsole::OnInit() +{ +#if wxUSE_CMDLINE_PARSER + wxCmdLineParser parser(argc, argv); + + OnInitCmdLine(parser); + + bool cont; + switch ( parser.Parse(false /* don't show usage */) ) + { + case -1: + cont = OnCmdLineHelp(parser); + break; + + case 0: + cont = OnCmdLineParsed(parser); + break; + + default: + cont = OnCmdLineError(parser); + break; + } + + if ( !cont ) + return false; +#endif // wxUSE_CMDLINE_PARSER + + return true; +} + +int wxAppConsole::OnExit() +{ +#if wxUSE_CONFIG + // delete the config object if any (don't use Get() here, but Set() + // because Get() could create a new config object) + delete wxConfigBase::Set((wxConfigBase *) NULL); +#endif // wxUSE_CONFIG + + return 0; +} + +void wxAppConsole::Exit() +{ + exit(-1); +} + +// ---------------------------------------------------------------------------- +// traits stuff +// ---------------------------------------------------------------------------- + +wxAppTraits *wxAppConsole::CreateTraits() +{ + return new wxConsoleAppTraits; +} + +wxAppTraits *wxAppConsole::GetTraits() +{ + // FIXME-MT: protect this with a CS? + if ( !m_traits ) + { + m_traits = CreateTraits(); + + wxASSERT_MSG( m_traits, _T("wxApp::CreateTraits() failed?") ); + } + + return m_traits; +} + +// we must implement CreateXXX() in wxApp itself for backwards compatibility +#if WXWIN_COMPATIBILITY_2_4 + +#if wxUSE_LOG + +wxLog *wxAppConsole::CreateLogTarget() +{ + wxAppTraits *traits = GetTraits(); + return traits ? traits->CreateLogTarget() : NULL; +} + +#endif // wxUSE_LOG + +wxMessageOutput *wxAppConsole::CreateMessageOutput() +{ + wxAppTraits *traits = GetTraits(); + return traits ? traits->CreateMessageOutput() : NULL; +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +// ---------------------------------------------------------------------------- +// event processing +// ---------------------------------------------------------------------------- + +void wxAppConsole::ProcessPendingEvents() +{ +#if wxUSE_THREADS + if ( !wxPendingEventsLocker ) + return; +#endif + + // ensure that we're the only thread to modify the pending events list + wxENTER_CRIT_SECT( *wxPendingEventsLocker ); + + if ( !wxPendingEvents ) + { + wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); + return; + } + + // iterate until the list becomes empty + wxList::compatibility_iterator node = wxPendingEvents->GetFirst(); + while (node) + { + wxEvtHandler *handler = (wxEvtHandler *)node->GetData(); + wxPendingEvents->Erase(node); + + // In ProcessPendingEvents(), new handlers might be add + // and we can safely leave the critical section here. + wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); + + handler->ProcessPendingEvents(); + + wxENTER_CRIT_SECT( *wxPendingEventsLocker ); + + node = wxPendingEvents->GetFirst(); + } + + wxLEAVE_CRIT_SECT( *wxPendingEventsLocker ); +} + +int wxAppConsole::FilterEvent(wxEvent& WXUNUSED(event)) +{ + // process the events normally by default + return -1; +} + +// ---------------------------------------------------------------------------- +// exception handling +// ---------------------------------------------------------------------------- + +#if wxUSE_EXCEPTIONS + +void +wxAppConsole::HandleEvent(wxEvtHandler *handler, + wxEventFunction func, + wxEvent& event) const +{ + // by default, simply call the handler + (handler->*func)(event); +} + +#endif // wxUSE_EXCEPTIONS + +// ---------------------------------------------------------------------------- +// cmd line parsing +// ---------------------------------------------------------------------------- + +#if wxUSE_CMDLINE_PARSER + +#define OPTION_VERBOSE _T("verbose") + +void wxAppConsole::OnInitCmdLine(wxCmdLineParser& parser) +{ + // the standard command line options + static const wxCmdLineEntryDesc cmdLineDesc[] = + { + { + wxCMD_LINE_SWITCH, + _T("h"), + _T("help"), + gettext_noop("show this help message"), + wxCMD_LINE_VAL_NONE, + wxCMD_LINE_OPTION_HELP + }, + +#if wxUSE_LOG + { + wxCMD_LINE_SWITCH, + wxEmptyString, + OPTION_VERBOSE, + gettext_noop("generate verbose log messages"), + wxCMD_LINE_VAL_NONE, + 0x0 + }, +#endif // wxUSE_LOG + + // terminator + { + wxCMD_LINE_NONE, + wxEmptyString, + wxEmptyString, + wxEmptyString, + wxCMD_LINE_VAL_NONE, + 0x0 + } + }; + + parser.SetDesc(cmdLineDesc); +} + +bool wxAppConsole::OnCmdLineParsed(wxCmdLineParser& parser) +{ +#if wxUSE_LOG + if ( parser.Found(OPTION_VERBOSE) ) + { + wxLog::SetVerbose(true); + } +#else + wxUnusedVar(parser); +#endif // wxUSE_LOG + + return true; +} + +bool wxAppConsole::OnCmdLineHelp(wxCmdLineParser& parser) +{ + parser.Usage(); + + return false; +} + +bool wxAppConsole::OnCmdLineError(wxCmdLineParser& parser) +{ + parser.Usage(); + + return false; +} + +#endif // wxUSE_CMDLINE_PARSER + +// ---------------------------------------------------------------------------- +// debugging support +// ---------------------------------------------------------------------------- + +/* static */ +bool wxAppConsole::CheckBuildOptions(const char *optionsSignature, + const char *componentName) +{ +#if 0 // can't use wxLogTrace, not up and running yet + printf("checking build options object '%s' (ptr %p) in '%s'\n", + optionsSignature, optionsSignature, componentName); +#endif + + if ( strcmp(optionsSignature, WX_BUILD_OPTIONS_SIGNATURE) != 0 ) + { + wxString lib = wxString::FromAscii(WX_BUILD_OPTIONS_SIGNATURE); + wxString prog = wxString::FromAscii(optionsSignature); + wxString progName = wxString::FromAscii(componentName); + wxString msg; + + msg.Printf(_T("Mismatch between the program and library build versions detected.\nThe library used %s,\nand %s used %s."), + lib.c_str(), progName.c_str(), prog.c_str()); + + wxLogFatalError(msg.c_str()); + + // normally wxLogFatalError doesn't return + return false; + } +#undef wxCMP + + return true; +} + +#ifdef __WXDEBUG__ + +void wxAppConsole::OnAssertFailure(const wxChar *file, + int line, + const wxChar *func, + const wxChar *cond, + const wxChar *msg) +{ + ShowAssertDialog(file, line, func, cond, msg, GetTraits()); +} + +void wxAppConsole::OnAssert(const wxChar *file, + int line, + const wxChar *cond, + const wxChar *msg) +{ + OnAssertFailure(file, line, NULL, cond, msg); +} + +#endif // __WXDEBUG__ + +#if WXWIN_COMPATIBILITY_2_4 + +bool wxAppConsole::CheckBuildOptions(const wxBuildOptions& buildOptions) +{ + return CheckBuildOptions(buildOptions.m_signature, "your program"); +} + +#endif + +// ============================================================================ +// other classes implementations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxConsoleAppTraitsBase +// ---------------------------------------------------------------------------- + +#if wxUSE_LOG + +wxLog *wxConsoleAppTraitsBase::CreateLogTarget() +{ + return new wxLogStderr; +} + +#endif // wxUSE_LOG + +wxMessageOutput *wxConsoleAppTraitsBase::CreateMessageOutput() +{ + return new wxMessageOutputStderr; +} + +#if wxUSE_FONTMAP + +wxFontMapper *wxConsoleAppTraitsBase::CreateFontMapper() +{ + return (wxFontMapper *)new wxFontMapperBase; +} + +#endif // wxUSE_FONTMAP + +wxRendererNative *wxConsoleAppTraitsBase::CreateRenderer() +{ + // console applications don't use renderers + return NULL; +} + +#ifdef __WXDEBUG__ +bool wxConsoleAppTraitsBase::ShowAssertDialog(const wxString& msg) +{ + return wxAppTraitsBase::ShowAssertDialog(msg); +} +#endif + +bool wxConsoleAppTraitsBase::HasStderr() +{ + // console applications always have stderr, even under Mac/Windows + return true; +} + +void wxConsoleAppTraitsBase::ScheduleForDestroy(wxObject *object) +{ + delete object; +} + +void wxConsoleAppTraitsBase::RemoveFromPendingDelete(wxObject * WXUNUSED(object)) +{ + // nothing to do +} + +#if wxUSE_SOCKETS +GSocketGUIFunctionsTable* wxConsoleAppTraitsBase::GetSocketGUIFunctionsTable() +{ + return NULL; +} +#endif + +// ---------------------------------------------------------------------------- +// wxAppTraits +// ---------------------------------------------------------------------------- + +#ifdef __WXDEBUG__ + +bool wxAppTraitsBase::ShowAssertDialog(const wxString& msgOriginal) +{ + wxString msg = msgOriginal; + +#if wxUSE_STACKWALKER +#if !defined(__WXMSW__) + // on Unix stack frame generation may take some time, depending on the + // size of the executable mainly... warn the user that we are working + wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait")); + fflush(stderr); +#endif + + const wxString stackTrace = GetAssertStackTrace(); + if ( !stackTrace.empty() ) + msg << _T("\n\nCall stack:\n") << stackTrace; +#endif // wxUSE_STACKWALKER + + return DoShowAssertDialog(msg); +} + +#if wxUSE_STACKWALKER +wxString wxAppTraitsBase::GetAssertStackTrace() +{ + wxString stackTrace; + + class StackDump : public wxStackWalker + { + public: + StackDump() { } + + const wxString& GetStackTrace() const { return m_stackTrace; } + + protected: + virtual void OnStackFrame(const wxStackFrame& frame) + { + m_stackTrace << wxString::Format + ( + _T("[%02d] "), + wx_truncate_cast(int, frame.GetLevel()) + ); + + wxString name = frame.GetName(); + if ( !name.empty() ) + { + m_stackTrace << wxString::Format(_T("%-40s"), name.c_str()); + } + else + { + m_stackTrace << wxString::Format(_T("%p"), frame.GetAddress()); + } + + if ( frame.HasSourceLocation() ) + { + m_stackTrace << _T('\t') + << frame.GetFileName() + << _T(':') + << frame.GetLine(); + } + + m_stackTrace << _T('\n'); + } + + private: + wxString m_stackTrace; + }; + + // don't show more than maxLines or we could get a dialog too tall to be + // shown on screen: 20 should be ok everywhere as even with 15 pixel high + // characters it is still only 300 pixels... + static const int maxLines = 20; + + StackDump dump; + dump.Walk(2, maxLines); // don't show OnAssert() call itself + stackTrace = dump.GetStackTrace(); + + const int count = stackTrace.Freq(wxT('\n')); + for ( int i = 0; i < count - maxLines; i++ ) + stackTrace = stackTrace.BeforeLast(wxT('\n')); + + return stackTrace; +} +#endif // wxUSE_STACKWALKER + + +#endif // __WXDEBUG__ + +// ============================================================================ +// global functions implementation +// ============================================================================ + +void wxExit() +{ + if ( wxTheApp ) + { + wxTheApp->Exit(); + } + else + { + // what else can we do? + exit(-1); + } +} + +void wxWakeUpIdle() +{ + if ( wxTheApp ) + { + wxTheApp->WakeUpIdle(); + } + //else: do nothing, what can we do? +} + +#ifdef __WXDEBUG__ + +// wxASSERT() helper +bool wxAssertIsEqual(int x, int y) +{ + return x == y; +} + +// break into the debugger +void wxTrap() +{ +#if defined(__WXMSW__) && !defined(__WXMICROWIN__) + DebugBreak(); +#elif defined(__WXMAC__) && !defined(__DARWIN__) + #if __powerc + Debugger(); + #else + SysBreak(); + #endif +#elif defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS + Debugger(); +#elif defined(__UNIX__) + raise(SIGTRAP); +#else + // TODO +#endif // Win/Unix +} + +// this function is called when an assert fails +void wxOnAssert(const wxChar *szFile, + int nLine, + const char *szFunc, + const wxChar *szCond, + const wxChar *szMsg) +{ + // FIXME MT-unsafe + static int s_bInAssert = 0; + + wxRecursionGuard guard(s_bInAssert); + if ( guard.IsInside() ) + { + // can't use assert here to avoid infinite loops, so just trap + wxTrap(); + + return; + } + + // __FUNCTION__ is always in ASCII, convert it to wide char if needed + const wxString strFunc = wxString::FromAscii(szFunc); + + if ( !wxTheApp ) + { + // by default, show the assert dialog box -- we can't customize this + // behaviour + ShowAssertDialog(szFile, nLine, strFunc, szCond, szMsg); + } + else + { + // let the app process it as it wants + wxTheApp->OnAssertFailure(szFile, nLine, strFunc, szCond, szMsg); + } +} + +#endif // __WXDEBUG__ + +// ============================================================================ +// private functions implementation +// ============================================================================ + +#ifdef __WXDEBUG__ + +static void LINKAGEMODE SetTraceMasks() +{ +#if wxUSE_LOG + wxString mask; + if ( wxGetEnv(wxT("WXTRACE"), &mask) ) + { + wxStringTokenizer tkn(mask, wxT(",;:")); + while ( tkn.HasMoreTokens() ) + wxLog::AddTraceMask(tkn.GetNextToken()); + } +#endif // wxUSE_LOG +} + +bool DoShowAssertDialog(const wxString& msg) +{ + // under MSW we can show the dialog even in the console mode +#if defined(__WXMSW__) && !defined(__WXMICROWIN__) + wxString msgDlg(msg); + + // this message is intentionally not translated -- it is for + // developpers only + msgDlg += wxT("\nDo you want to stop the program?\n") + wxT("You can also choose [Cancel] to suppress ") + wxT("further warnings."); + + switch ( ::MessageBox(NULL, msgDlg, _T("wxWidgets Debug Alert"), + MB_YESNOCANCEL | MB_ICONSTOP ) ) + { + case IDYES: + wxTrap(); + break; + + case IDCANCEL: + // stop the asserts + return true; + + //case IDNO: nothing to do + } +#else // !__WXMSW__ + wxFprintf(stderr, wxT("%s\n"), msg.c_str()); + fflush(stderr); + + // TODO: ask the user to enter "Y" or "N" on the console? + wxTrap(); +#endif // __WXMSW__/!__WXMSW__ + + // continue with the asserts + return false; +} + +// show the assert modal dialog +static +void ShowAssertDialog(const wxChar *szFile, + int nLine, + const wxChar *szFunc, + const wxChar *szCond, + const wxChar *szMsg, + wxAppTraits *traits) +{ + // this variable can be set to true to suppress "assert failure" messages + static bool s_bNoAsserts = false; + + wxString msg; + msg.reserve(2048); + + // make life easier for people using VC++ IDE by using this format: like + // this, clicking on the message will take us immediately to the place of + // the failed assert + msg.Printf(wxT("%s(%d): assert \"%s\" failed"), szFile, nLine, szCond); + + // add the function name, if any + if ( szFunc && *szFunc ) + msg << _T(" in ") << szFunc << _T("()"); + + // and the message itself + if ( szMsg ) + { + msg << _T(": ") << szMsg; + } + else // no message given + { + msg << _T('.'); + } + +#if wxUSE_THREADS + // if we are not in the main thread, output the assert directly and trap + // since dialogs cannot be displayed + if ( !wxThread::IsMain() ) + { + msg += wxT(" [in child thread]"); + +#if defined(__WXMSW__) && !defined(__WXMICROWIN__) + msg << wxT("\r\n"); + OutputDebugString(msg ); +#else + // send to stderr + wxFprintf(stderr, wxT("%s\n"), msg.c_str()); + fflush(stderr); +#endif + // He-e-e-e-elp!! we're asserting in a child thread + wxTrap(); + } + else +#endif // wxUSE_THREADS + + if ( !s_bNoAsserts ) + { + // send it to the normal log destination + wxLogDebug(_T("%s"), msg.c_str()); + + if ( traits ) + { + // delegate showing assert dialog (if possible) to that class + s_bNoAsserts = traits->ShowAssertDialog(msg); + } + else // no traits object + { + // fall back to the function of last resort + s_bNoAsserts = DoShowAssertDialog(msg); + } + } +} + +#endif // __WXDEBUG__ diff --git a/Source/3rd Party/wx/src/common/appcmn.cpp b/Source/3rd Party/wx/src/common/appcmn.cpp index 670a35d09..bc1a30c11 100644 --- a/Source/3rd Party/wx/src/common/appcmn.cpp +++ b/Source/3rd Party/wx/src/common/appcmn.cpp @@ -1,695 +1,691 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/appcmn.cpp -// Purpose: wxAppConsole and wxAppBase methods common to all platforms -// Author: Vadim Zeitlin -// Modified by: -// Created: 18.10.99 -// RCS-ID: $Id: appcmn.cpp 47229 2007-07-08 05:31:32Z PC $ -// Copyright: (c) Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/window.h" - #include "wx/bitmap.h" - #include "wx/log.h" - #include "wx/msgdlg.h" - #include "wx/confbase.h" - #include "wx/utils.h" -#endif - -#include "wx/apptrait.h" -#include "wx/cmdline.h" -#include "wx/evtloop.h" -#include "wx/msgout.h" -#include "wx/thread.h" -#include "wx/vidmode.h" -#include "wx/ptr_scpd.h" - -#ifdef __WXDEBUG__ - #if wxUSE_STACKWALKER - #include "wx/stackwalk.h" - #endif // wxUSE_STACKWALKER -#endif // __WXDEBUG__ - -#if defined(__WXMSW__) - #include "wx/msw/private.h" // includes windows.h for LOGFONT -#endif - -#ifdef __WXMSW__ -#include -#endif - -#if defined(__WXMAC__) - #include "wx/mac/private.h" -#endif - -#if wxUSE_FONTMAP - #include "wx/fontmap.h" -#endif // wxUSE_FONTMAP - -// DLL options compatibility check: -#include "wx/build.h" -WX_CHECK_BUILD_OPTIONS("wxCore") - -WXDLLIMPEXP_DATA_CORE(wxList) wxPendingDelete; - -// ---------------------------------------------------------------------------- -// wxEventLoopPtr -// ---------------------------------------------------------------------------- - -// this defines wxEventLoopPtr -wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoop) - -// ============================================================================ -// wxAppBase implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// initialization -// ---------------------------------------------------------------------------- - -wxAppBase::wxAppBase() -{ - m_topWindow = (wxWindow *)NULL; - - m_useBestVisual = false; - m_forceTrueColour = false; - - m_isActive = true; - - m_mainLoop = NULL; - - // We don't want to exit the app if the user code shows a dialog from its - // OnInit() -- but this is what would happen if we set m_exitOnFrameDelete - // to Yes initially as this dialog would be the last top level window. - // OTOH, if we set it to No initially we'll have to overwrite it with Yes - // when we enter our OnRun() because we do want the default behaviour from - // then on. But this would be a problem if the user code calls - // SetExitOnFrameDelete(false) from OnInit(). - // - // So we use the special "Later" value which is such that - // GetExitOnFrameDelete() returns false for it but which we know we can - // safely (i.e. without losing the effect of the users SetExitOnFrameDelete - // call) overwrite in OnRun() - m_exitOnFrameDelete = Later; -} - -bool wxAppBase::Initialize(int& argcOrig, wxChar **argvOrig) -{ - if ( !wxAppConsole::Initialize(argcOrig, argvOrig) ) - return false; - -#if wxUSE_THREADS - wxPendingEventsLocker = new wxCriticalSection; -#endif - - wxInitializeStockLists(); - - wxBitmap::InitStandardHandlers(); - - return true; -} - -// ---------------------------------------------------------------------------- -// cleanup -// ---------------------------------------------------------------------------- - -wxAppBase::~wxAppBase() -{ - // this destructor is required for Darwin -} - -void wxAppBase::CleanUp() -{ - // clean up all the pending objects - DeletePendingObjects(); - - // and any remaining TLWs (they remove themselves from wxTopLevelWindows - // when destroyed, so iterate until none are left) - while ( !wxTopLevelWindows.empty() ) - { - // do not use Destroy() here as it only puts the TLW in pending list - // but we want to delete them now - delete wxTopLevelWindows.GetFirst()->GetData(); - } - - // undo everything we did in Initialize() above - wxBitmap::CleanUpHandlers(); - - wxStockGDI::DeleteAll(); - - wxDeleteStockLists(); - - delete wxTheColourDatabase; - wxTheColourDatabase = NULL; - - delete wxPendingEvents; - wxPendingEvents = NULL; - -#if wxUSE_THREADS - delete wxPendingEventsLocker; - wxPendingEventsLocker = NULL; - - #if wxUSE_VALIDATORS - // If we don't do the following, we get an apparent memory leak. - ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker(); - #endif // wxUSE_VALIDATORS -#endif // wxUSE_THREADS -} - -// ---------------------------------------------------------------------------- -// various accessors -// ---------------------------------------------------------------------------- - -wxWindow* wxAppBase::GetTopWindow() const -{ - wxWindow* window = m_topWindow; - if (window == NULL && wxTopLevelWindows.GetCount() > 0) - window = wxTopLevelWindows.GetFirst()->GetData(); - return window; -} - -wxVideoMode wxAppBase::GetDisplayMode() const -{ - return wxVideoMode(); -} - -wxLayoutDirection wxAppBase::GetLayoutDirection() const -{ -#if wxUSE_INTL - const wxLocale *const locale = wxGetLocale(); - if ( locale ) - { - const wxLanguageInfo *const - info = wxLocale::GetLanguageInfo(locale->GetLanguage()); - - if ( info ) - return info->LayoutDirection; - } -#endif // wxUSE_INTL - - // we don't know - return wxLayout_Default; -} - -#if wxUSE_CMDLINE_PARSER - -// ---------------------------------------------------------------------------- -// GUI-specific command line options handling -// ---------------------------------------------------------------------------- - -#define OPTION_THEME _T("theme") -#define OPTION_MODE _T("mode") - -void wxAppBase::OnInitCmdLine(wxCmdLineParser& parser) -{ - // first add the standard non GUI options - wxAppConsole::OnInitCmdLine(parser); - - // the standard command line options - static const wxCmdLineEntryDesc cmdLineGUIDesc[] = - { -#ifdef __WXUNIVERSAL__ - { - wxCMD_LINE_OPTION, - wxEmptyString, - OPTION_THEME, - gettext_noop("specify the theme to use"), - wxCMD_LINE_VAL_STRING, - 0x0 - }, -#endif // __WXUNIVERSAL__ - -#if defined(__WXMGL__) - // VS: this is not specific to wxMGL, all fullscreen (framebuffer) ports - // should provide this option. That's why it is in common/appcmn.cpp - // and not mgl/app.cpp - { - wxCMD_LINE_OPTION, - wxEmptyString, - OPTION_MODE, - gettext_noop("specify display mode to use (e.g. 640x480-16)"), - wxCMD_LINE_VAL_STRING, - 0x0 - }, -#endif // __WXMGL__ - - // terminator - { - wxCMD_LINE_NONE, - wxEmptyString, - wxEmptyString, - wxEmptyString, - wxCMD_LINE_VAL_NONE, - 0x0 - } - }; - - parser.SetDesc(cmdLineGUIDesc); -} - -bool wxAppBase::OnCmdLineParsed(wxCmdLineParser& parser) -{ -#ifdef __WXUNIVERSAL__ - wxString themeName; - if ( parser.Found(OPTION_THEME, &themeName) ) - { - wxTheme *theme = wxTheme::Create(themeName); - if ( !theme ) - { - wxLogError(_("Unsupported theme '%s'."), themeName.c_str()); - return false; - } - - // Delete the defaultly created theme and set the new theme. - delete wxTheme::Get(); - wxTheme::Set(theme); - } -#endif // __WXUNIVERSAL__ - -#if defined(__WXMGL__) - wxString modeDesc; - if ( parser.Found(OPTION_MODE, &modeDesc) ) - { - unsigned w, h, bpp; - if ( wxSscanf(modeDesc.c_str(), _T("%ux%u-%u"), &w, &h, &bpp) != 3 ) - { - wxLogError(_("Invalid display mode specification '%s'."), modeDesc.c_str()); - return false; - } - - if ( !SetDisplayMode(wxVideoMode(w, h, bpp)) ) - return false; - } -#endif // __WXMGL__ - - return wxAppConsole::OnCmdLineParsed(parser); -} - -#endif // wxUSE_CMDLINE_PARSER - -// ---------------------------------------------------------------------------- -// main event loop implementation -// ---------------------------------------------------------------------------- - -int wxAppBase::MainLoop() -{ - wxEventLoopTiedPtr mainLoop(&m_mainLoop, new wxEventLoop); - - return m_mainLoop->Run(); -} - -void wxAppBase::ExitMainLoop() -{ - // we should exit from the main event loop, not just any currently active - // (e.g. modal dialog) event loop - if ( m_mainLoop && m_mainLoop->IsRunning() ) - { - m_mainLoop->Exit(0); - } -} - -bool wxAppBase::Pending() -{ - // use the currently active message loop here, not m_mainLoop, because if - // we're showing a modal dialog (with its own event loop) currently the - // main event loop is not running anyhow - wxEventLoop * const loop = wxEventLoop::GetActive(); - - return loop && loop->Pending(); -} - -bool wxAppBase::Dispatch() -{ - // see comment in Pending() - wxEventLoop * const loop = wxEventLoop::GetActive(); - - return loop && loop->Dispatch(); -} - -// ---------------------------------------------------------------------------- -// OnXXX() hooks -// ---------------------------------------------------------------------------- - -bool wxAppBase::OnInitGui() -{ -#ifdef __WXUNIVERSAL__ - if ( !wxTheme::Get() && !wxTheme::CreateDefault() ) - return false; -#endif // __WXUNIVERSAL__ - - return true; -} - -int wxAppBase::OnRun() -{ - // see the comment in ctor: if the initial value hasn't been changed, use - // the default Yes from now on - if ( m_exitOnFrameDelete == Later ) - { - m_exitOnFrameDelete = Yes; - } - //else: it has been changed, assume the user knows what he is doing - - return MainLoop(); -} - -int wxAppBase::OnExit() -{ -#ifdef __WXUNIVERSAL__ - delete wxTheme::Set(NULL); -#endif // __WXUNIVERSAL__ - - return wxAppConsole::OnExit(); -} - -void wxAppBase::Exit() -{ - ExitMainLoop(); -} - -wxAppTraits *wxAppBase::CreateTraits() -{ - return new wxGUIAppTraits; -} - -// ---------------------------------------------------------------------------- -// misc -// ---------------------------------------------------------------------------- - -void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus)) -{ - if ( active == m_isActive ) - return; - - m_isActive = active; - - wxActivateEvent event(wxEVT_ACTIVATE_APP, active); - event.SetEventObject(this); - - (void)ProcessEvent(event); -} - -// ---------------------------------------------------------------------------- -// idle handling -// ---------------------------------------------------------------------------- - -void wxAppBase::DeletePendingObjects() -{ - wxList::compatibility_iterator node = wxPendingDelete.GetFirst(); - while (node) - { - wxObject *obj = node->GetData(); - - // remove it from the list first so that if we get back here somehow - // during the object deletion (e.g. wxYield called from its dtor) we - // wouldn't try to delete it the second time - if ( wxPendingDelete.Member(obj) ) - wxPendingDelete.Erase(node); - - delete obj; - - // Deleting one object may have deleted other pending - // objects, so start from beginning of list again. - node = wxPendingDelete.GetFirst(); - } -} - -// Returns true if more time is needed. -bool wxAppBase::ProcessIdle() -{ - // process pending wx events before sending idle events - ProcessPendingEvents(); - - wxIdleEvent event; - bool needMore = false; - wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst(); - while (node) - { - wxWindow* win = node->GetData(); - if (SendIdleEvents(win, event)) - needMore = true; - node = node->GetNext(); - } - - event.SetEventObject(this); - (void) ProcessEvent(event); - if (event.MoreRequested()) - needMore = true; - - // 'Garbage' collection of windows deleted with Close(). - DeletePendingObjects(); - -#if wxUSE_LOG - // flush the logged messages if any - wxLog::FlushActive(); -#endif - - wxUpdateUIEvent::ResetUpdateTime(); - - return needMore; -} - -// Send idle event to window and all subwindows -bool wxAppBase::SendIdleEvents(wxWindow* win, wxIdleEvent& event) -{ - bool needMore = false; - - win->OnInternalIdle(); - - if (wxIdleEvent::CanSend(win)) - { - event.SetEventObject(win); - win->GetEventHandler()->ProcessEvent(event); - - if (event.MoreRequested()) - needMore = true; - } - wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); - while ( node ) - { - wxWindow *child = node->GetData(); - if (SendIdleEvents(child, event)) - needMore = true; - - node = node->GetNext(); - } - - return needMore; -} - -void wxAppBase::OnIdle(wxIdleEvent& WXUNUSED(event)) -{ -} - -// ---------------------------------------------------------------------------- -// exceptions support -// ---------------------------------------------------------------------------- - -#if wxUSE_EXCEPTIONS - -bool wxAppBase::OnExceptionInMainLoop() -{ - throw; - - // some compilers are too stupid to know that we never return after throw -#if defined(__DMC__) || (defined(_MSC_VER) && _MSC_VER < 1200) - return false; -#endif -} - -#endif // wxUSE_EXCEPTIONS - -// ---------------------------------------------------------------------------- -// wxGUIAppTraitsBase -// ---------------------------------------------------------------------------- - -#if wxUSE_LOG - -wxLog *wxGUIAppTraitsBase::CreateLogTarget() -{ -#if wxUSE_LOGGUI - return new wxLogGui; -#else - // we must have something! - return new wxLogStderr; -#endif -} - -#endif // wxUSE_LOG - -wxMessageOutput *wxGUIAppTraitsBase::CreateMessageOutput() -{ - // The standard way of printing help on command line arguments (app --help) - // is (according to common practice): - // - console apps: to stderr (on any platform) - // - GUI apps: stderr on Unix platforms (!) - // message box under Windows and others -#ifdef __UNIX__ - return new wxMessageOutputStderr; -#else // !__UNIX__ - // wxMessageOutputMessageBox doesn't work under Motif - #ifdef __WXMOTIF__ - return new wxMessageOutputLog; - #else - return new wxMessageOutputMessageBox; - #endif -#endif // __UNIX__/!__UNIX__ -} - -#if wxUSE_FONTMAP - -wxFontMapper *wxGUIAppTraitsBase::CreateFontMapper() -{ - return new wxFontMapper; -} - -#endif // wxUSE_FONTMAP - -wxRendererNative *wxGUIAppTraitsBase::CreateRenderer() -{ - // use the default native renderer by default - return NULL; -} - -#ifdef __WXDEBUG__ - -bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString& msg) -{ -#if defined(__WXMSW__) || !wxUSE_MSGDLG - // under MSW we prefer to use the base class version using ::MessageBox() - // even if wxMessageBox() is available because it has less chances to - // double fault our app than our wxMessageBox() - return wxAppTraitsBase::ShowAssertDialog(msg); -#else // wxUSE_MSGDLG - wxString msgDlg = msg; - -#if wxUSE_STACKWALKER - // on Unix stack frame generation may take some time, depending on the - // size of the executable mainly... warn the user that we are working - wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait")); - fflush(stderr); - - const wxString stackTrace = GetAssertStackTrace(); - if ( !stackTrace.empty() ) - msgDlg << _T("\n\nCall stack:\n") << stackTrace; -#endif // wxUSE_STACKWALKER - - // this message is intentionally not translated -- it is for - // developpers only - msgDlg += wxT("\nDo you want to stop the program?\n") - wxT("You can also choose [Cancel] to suppress ") - wxT("further warnings."); - -#ifdef __WXMAC__ - // in order to avoid reentrancy problems, use the lowest alert API available - CFOptionFlags exitButton; - wxMacCFStringHolder cfText(msgDlg); - OSStatus err = CFUserNotificationDisplayAlert( - 0, kAlertStopAlert, NULL, NULL, NULL, CFSTR("wxWidgets Debug Alert"), cfText, - CFSTR("Yes"), CFSTR("No"), CFSTR("Cancel"), &exitButton ); - if ( err == noErr ) - { - switch( exitButton ) - { - case 0 : // yes - wxTrap(); - break; - case 2 : // cancel - // no more asserts - return true; - case 1 : // no -> nothing to do - break ; - } - } -#else - switch ( wxMessageBox(msgDlg, wxT("wxWidgets Debug Alert"), - wxYES_NO | wxCANCEL | wxICON_STOP ) ) - { - case wxYES: - wxTrap(); - break; - - case wxCANCEL: - // no more asserts - return true; - - //case wxNO: nothing to do - } -#endif - return false; -#endif // !wxUSE_MSGDLG/wxUSE_MSGDLG -} - -#endif // __WXDEBUG__ - -bool wxGUIAppTraitsBase::HasStderr() -{ - // we consider that under Unix stderr always goes somewhere, even if the - // user doesn't always see it under GUI desktops -#ifdef __UNIX__ - return true; -#else - return false; -#endif -} - -void wxGUIAppTraitsBase::ScheduleForDestroy(wxObject *object) -{ - if ( !wxPendingDelete.Member(object) ) - wxPendingDelete.Append(object); -} - -void wxGUIAppTraitsBase::RemoveFromPendingDelete(wxObject *object) -{ - wxPendingDelete.DeleteObject(object); -} - -#if wxUSE_SOCKETS - -#if defined(__WINDOWS__) - #include "wx/msw/gsockmsw.h" -#elif defined(__UNIX__) || defined(__DARWIN__) || defined(__OS2__) - #include "wx/unix/gsockunx.h" -#elif defined(__WXMAC__) - #include - #define OTUNIXERRORS 1 - #include - #include - #include - - #include "wx/mac/gsockmac.h" -#else - #error "Must include correct GSocket header here" -#endif - -GSocketGUIFunctionsTable* wxGUIAppTraitsBase::GetSocketGUIFunctionsTable() -{ -#if defined(__WXMAC__) && !defined(__DARWIN__) - // NB: wxMac CFM does not have any GUI-specific functions in gsocket.c and - // so it doesn't need this table at all - return NULL; -#else // !__WXMAC__ || __DARWIN__ - static GSocketGUIFunctionsTableConcrete table; - return &table; -#endif // !__WXMAC__ || __DARWIN__ -} - -#endif +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/appcmn.cpp +// Purpose: wxAppConsole and wxAppBase methods common to all platforms +// Author: Vadim Zeitlin +// Modified by: +// Created: 18.10.99 +// RCS-ID: $Id: appcmn.cpp 47229 2007-07-08 05:31:32Z PC $ +// Copyright: (c) Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/window.h" + #include "wx/bitmap.h" + #include "wx/log.h" + #include "wx/msgdlg.h" + #include "wx/confbase.h" + #include "wx/utils.h" +#endif + +#include "wx/apptrait.h" +#include "wx/cmdline.h" +#include "wx/evtloop.h" +#include "wx/msgout.h" +#include "wx/thread.h" +#include "wx/vidmode.h" +#include "wx/ptr_scpd.h" + +#ifdef __WXDEBUG__ + #if wxUSE_STACKWALKER + #include "wx/stackwalk.h" + #endif // wxUSE_STACKWALKER +#endif // __WXDEBUG__ + +#if defined(__WXMSW__) + #include "wx/msw/private.h" // includes windows.h for LOGFONT +#endif + +#if defined(__WXMAC__) + #include "wx/mac/private.h" +#endif + +#if wxUSE_FONTMAP + #include "wx/fontmap.h" +#endif // wxUSE_FONTMAP + +// DLL options compatibility check: +#include "wx/build.h" +WX_CHECK_BUILD_OPTIONS("wxCore") + +WXDLLIMPEXP_DATA_CORE(wxList) wxPendingDelete; + +// ---------------------------------------------------------------------------- +// wxEventLoopPtr +// ---------------------------------------------------------------------------- + +// this defines wxEventLoopPtr +wxDEFINE_TIED_SCOPED_PTR_TYPE(wxEventLoop) + +// ============================================================================ +// wxAppBase implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// initialization +// ---------------------------------------------------------------------------- + +wxAppBase::wxAppBase() +{ + m_topWindow = (wxWindow *)NULL; + + m_useBestVisual = false; + m_forceTrueColour = false; + + m_isActive = true; + + m_mainLoop = NULL; + + // We don't want to exit the app if the user code shows a dialog from its + // OnInit() -- but this is what would happen if we set m_exitOnFrameDelete + // to Yes initially as this dialog would be the last top level window. + // OTOH, if we set it to No initially we'll have to overwrite it with Yes + // when we enter our OnRun() because we do want the default behaviour from + // then on. But this would be a problem if the user code calls + // SetExitOnFrameDelete(false) from OnInit(). + // + // So we use the special "Later" value which is such that + // GetExitOnFrameDelete() returns false for it but which we know we can + // safely (i.e. without losing the effect of the users SetExitOnFrameDelete + // call) overwrite in OnRun() + m_exitOnFrameDelete = Later; +} + +bool wxAppBase::Initialize(int& argcOrig, wxChar **argvOrig) +{ + if ( !wxAppConsole::Initialize(argcOrig, argvOrig) ) + return false; + +#if wxUSE_THREADS + wxPendingEventsLocker = new wxCriticalSection; +#endif + + wxInitializeStockLists(); + + wxBitmap::InitStandardHandlers(); + + return true; +} + +// ---------------------------------------------------------------------------- +// cleanup +// ---------------------------------------------------------------------------- + +wxAppBase::~wxAppBase() +{ + // this destructor is required for Darwin +} + +void wxAppBase::CleanUp() +{ + // clean up all the pending objects + DeletePendingObjects(); + + // and any remaining TLWs (they remove themselves from wxTopLevelWindows + // when destroyed, so iterate until none are left) + while ( !wxTopLevelWindows.empty() ) + { + // do not use Destroy() here as it only puts the TLW in pending list + // but we want to delete them now + delete wxTopLevelWindows.GetFirst()->GetData(); + } + + // undo everything we did in Initialize() above + wxBitmap::CleanUpHandlers(); + + wxStockGDI::DeleteAll(); + + wxDeleteStockLists(); + + delete wxTheColourDatabase; + wxTheColourDatabase = NULL; + + delete wxPendingEvents; + wxPendingEvents = NULL; + +#if wxUSE_THREADS + delete wxPendingEventsLocker; + wxPendingEventsLocker = NULL; + + #if wxUSE_VALIDATORS + // If we don't do the following, we get an apparent memory leak. + ((wxEvtHandler&) wxDefaultValidator).ClearEventLocker(); + #endif // wxUSE_VALIDATORS +#endif // wxUSE_THREADS +} + +// ---------------------------------------------------------------------------- +// various accessors +// ---------------------------------------------------------------------------- + +wxWindow* wxAppBase::GetTopWindow() const +{ + wxWindow* window = m_topWindow; + if (window == NULL && wxTopLevelWindows.GetCount() > 0) + window = wxTopLevelWindows.GetFirst()->GetData(); + return window; +} + +wxVideoMode wxAppBase::GetDisplayMode() const +{ + return wxVideoMode(); +} + +wxLayoutDirection wxAppBase::GetLayoutDirection() const +{ +#if wxUSE_INTL + const wxLocale *const locale = wxGetLocale(); + if ( locale ) + { + const wxLanguageInfo *const + info = wxLocale::GetLanguageInfo(locale->GetLanguage()); + + if ( info ) + return info->LayoutDirection; + } +#endif // wxUSE_INTL + + // we don't know + return wxLayout_Default; +} + +#if wxUSE_CMDLINE_PARSER + +// ---------------------------------------------------------------------------- +// GUI-specific command line options handling +// ---------------------------------------------------------------------------- + +#define OPTION_THEME _T("theme") +#define OPTION_MODE _T("mode") + +void wxAppBase::OnInitCmdLine(wxCmdLineParser& parser) +{ + // first add the standard non GUI options + wxAppConsole::OnInitCmdLine(parser); + + // the standard command line options + static const wxCmdLineEntryDesc cmdLineGUIDesc[] = + { +#ifdef __WXUNIVERSAL__ + { + wxCMD_LINE_OPTION, + wxEmptyString, + OPTION_THEME, + gettext_noop("specify the theme to use"), + wxCMD_LINE_VAL_STRING, + 0x0 + }, +#endif // __WXUNIVERSAL__ + +#if defined(__WXMGL__) + // VS: this is not specific to wxMGL, all fullscreen (framebuffer) ports + // should provide this option. That's why it is in common/appcmn.cpp + // and not mgl/app.cpp + { + wxCMD_LINE_OPTION, + wxEmptyString, + OPTION_MODE, + gettext_noop("specify display mode to use (e.g. 640x480-16)"), + wxCMD_LINE_VAL_STRING, + 0x0 + }, +#endif // __WXMGL__ + + // terminator + { + wxCMD_LINE_NONE, + wxEmptyString, + wxEmptyString, + wxEmptyString, + wxCMD_LINE_VAL_NONE, + 0x0 + } + }; + + parser.SetDesc(cmdLineGUIDesc); +} + +bool wxAppBase::OnCmdLineParsed(wxCmdLineParser& parser) +{ +#ifdef __WXUNIVERSAL__ + wxString themeName; + if ( parser.Found(OPTION_THEME, &themeName) ) + { + wxTheme *theme = wxTheme::Create(themeName); + if ( !theme ) + { + wxLogError(_("Unsupported theme '%s'."), themeName.c_str()); + return false; + } + + // Delete the defaultly created theme and set the new theme. + delete wxTheme::Get(); + wxTheme::Set(theme); + } +#endif // __WXUNIVERSAL__ + +#if defined(__WXMGL__) + wxString modeDesc; + if ( parser.Found(OPTION_MODE, &modeDesc) ) + { + unsigned w, h, bpp; + if ( wxSscanf(modeDesc.c_str(), _T("%ux%u-%u"), &w, &h, &bpp) != 3 ) + { + wxLogError(_("Invalid display mode specification '%s'."), modeDesc.c_str()); + return false; + } + + if ( !SetDisplayMode(wxVideoMode(w, h, bpp)) ) + return false; + } +#endif // __WXMGL__ + + return wxAppConsole::OnCmdLineParsed(parser); +} + +#endif // wxUSE_CMDLINE_PARSER + +// ---------------------------------------------------------------------------- +// main event loop implementation +// ---------------------------------------------------------------------------- + +int wxAppBase::MainLoop() +{ + wxEventLoopTiedPtr mainLoop(&m_mainLoop, new wxEventLoop); + + return m_mainLoop->Run(); +} + +void wxAppBase::ExitMainLoop() +{ + // we should exit from the main event loop, not just any currently active + // (e.g. modal dialog) event loop + if ( m_mainLoop && m_mainLoop->IsRunning() ) + { + m_mainLoop->Exit(0); + } +} + +bool wxAppBase::Pending() +{ + // use the currently active message loop here, not m_mainLoop, because if + // we're showing a modal dialog (with its own event loop) currently the + // main event loop is not running anyhow + wxEventLoop * const loop = wxEventLoop::GetActive(); + + return loop && loop->Pending(); +} + +bool wxAppBase::Dispatch() +{ + // see comment in Pending() + wxEventLoop * const loop = wxEventLoop::GetActive(); + + return loop && loop->Dispatch(); +} + +// ---------------------------------------------------------------------------- +// OnXXX() hooks +// ---------------------------------------------------------------------------- + +bool wxAppBase::OnInitGui() +{ +#ifdef __WXUNIVERSAL__ + if ( !wxTheme::Get() && !wxTheme::CreateDefault() ) + return false; +#endif // __WXUNIVERSAL__ + + return true; +} + +int wxAppBase::OnRun() +{ + // see the comment in ctor: if the initial value hasn't been changed, use + // the default Yes from now on + if ( m_exitOnFrameDelete == Later ) + { + m_exitOnFrameDelete = Yes; + } + //else: it has been changed, assume the user knows what he is doing + + return MainLoop(); +} + +int wxAppBase::OnExit() +{ +#ifdef __WXUNIVERSAL__ + delete wxTheme::Set(NULL); +#endif // __WXUNIVERSAL__ + + return wxAppConsole::OnExit(); +} + +void wxAppBase::Exit() +{ + ExitMainLoop(); +} + +wxAppTraits *wxAppBase::CreateTraits() +{ + return new wxGUIAppTraits; +} + +// ---------------------------------------------------------------------------- +// misc +// ---------------------------------------------------------------------------- + +void wxAppBase::SetActive(bool active, wxWindow * WXUNUSED(lastFocus)) +{ + if ( active == m_isActive ) + return; + + m_isActive = active; + + wxActivateEvent event(wxEVT_ACTIVATE_APP, active); + event.SetEventObject(this); + + (void)ProcessEvent(event); +} + +// ---------------------------------------------------------------------------- +// idle handling +// ---------------------------------------------------------------------------- + +void wxAppBase::DeletePendingObjects() +{ + wxList::compatibility_iterator node = wxPendingDelete.GetFirst(); + while (node) + { + wxObject *obj = node->GetData(); + + // remove it from the list first so that if we get back here somehow + // during the object deletion (e.g. wxYield called from its dtor) we + // wouldn't try to delete it the second time + if ( wxPendingDelete.Member(obj) ) + wxPendingDelete.Erase(node); + + delete obj; + + // Deleting one object may have deleted other pending + // objects, so start from beginning of list again. + node = wxPendingDelete.GetFirst(); + } +} + +// Returns true if more time is needed. +bool wxAppBase::ProcessIdle() +{ + // process pending wx events before sending idle events + ProcessPendingEvents(); + + wxIdleEvent event; + bool needMore = false; + wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst(); + while (node) + { + wxWindow* win = node->GetData(); + if (SendIdleEvents(win, event)) + needMore = true; + node = node->GetNext(); + } + + event.SetEventObject(this); + (void) ProcessEvent(event); + if (event.MoreRequested()) + needMore = true; + + // 'Garbage' collection of windows deleted with Close(). + DeletePendingObjects(); + +#if wxUSE_LOG + // flush the logged messages if any + wxLog::FlushActive(); +#endif + + wxUpdateUIEvent::ResetUpdateTime(); + + return needMore; +} + +// Send idle event to window and all subwindows +bool wxAppBase::SendIdleEvents(wxWindow* win, wxIdleEvent& event) +{ + bool needMore = false; + + win->OnInternalIdle(); + + if (wxIdleEvent::CanSend(win)) + { + event.SetEventObject(win); + win->GetEventHandler()->ProcessEvent(event); + + if (event.MoreRequested()) + needMore = true; + } + wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); + while ( node ) + { + wxWindow *child = node->GetData(); + if (SendIdleEvents(child, event)) + needMore = true; + + node = node->GetNext(); + } + + return needMore; +} + +void wxAppBase::OnIdle(wxIdleEvent& WXUNUSED(event)) +{ +} + +// ---------------------------------------------------------------------------- +// exceptions support +// ---------------------------------------------------------------------------- + +#if wxUSE_EXCEPTIONS + +bool wxAppBase::OnExceptionInMainLoop() +{ + throw; + + // some compilers are too stupid to know that we never return after throw +#if defined(__DMC__) || (defined(_MSC_VER) && _MSC_VER < 1200) + return false; +#endif +} + +#endif // wxUSE_EXCEPTIONS + +// ---------------------------------------------------------------------------- +// wxGUIAppTraitsBase +// ---------------------------------------------------------------------------- + +#if wxUSE_LOG + +wxLog *wxGUIAppTraitsBase::CreateLogTarget() +{ +#if wxUSE_LOGGUI + return new wxLogGui; +#else + // we must have something! + return new wxLogStderr; +#endif +} + +#endif // wxUSE_LOG + +wxMessageOutput *wxGUIAppTraitsBase::CreateMessageOutput() +{ + // The standard way of printing help on command line arguments (app --help) + // is (according to common practice): + // - console apps: to stderr (on any platform) + // - GUI apps: stderr on Unix platforms (!) + // message box under Windows and others +#ifdef __UNIX__ + return new wxMessageOutputStderr; +#else // !__UNIX__ + // wxMessageOutputMessageBox doesn't work under Motif + #ifdef __WXMOTIF__ + return new wxMessageOutputLog; + #else + return new wxMessageOutputMessageBox; + #endif +#endif // __UNIX__/!__UNIX__ +} + +#if wxUSE_FONTMAP + +wxFontMapper *wxGUIAppTraitsBase::CreateFontMapper() +{ + return new wxFontMapper; +} + +#endif // wxUSE_FONTMAP + +wxRendererNative *wxGUIAppTraitsBase::CreateRenderer() +{ + // use the default native renderer by default + return NULL; +} + +#ifdef __WXDEBUG__ + +bool wxGUIAppTraitsBase::ShowAssertDialog(const wxString& msg) +{ +#if defined(__WXMSW__) || !wxUSE_MSGDLG + // under MSW we prefer to use the base class version using ::MessageBox() + // even if wxMessageBox() is available because it has less chances to + // double fault our app than our wxMessageBox() + return wxAppTraitsBase::ShowAssertDialog(msg); +#else // wxUSE_MSGDLG + wxString msgDlg = msg; + +#if wxUSE_STACKWALKER + // on Unix stack frame generation may take some time, depending on the + // size of the executable mainly... warn the user that we are working + wxFprintf(stderr, wxT("[Debug] Generating a stack trace... please wait")); + fflush(stderr); + + const wxString stackTrace = GetAssertStackTrace(); + if ( !stackTrace.empty() ) + msgDlg << _T("\n\nCall stack:\n") << stackTrace; +#endif // wxUSE_STACKWALKER + + // this message is intentionally not translated -- it is for + // developpers only + msgDlg += wxT("\nDo you want to stop the program?\n") + wxT("You can also choose [Cancel] to suppress ") + wxT("further warnings."); + +#ifdef __WXMAC__ + // in order to avoid reentrancy problems, use the lowest alert API available + CFOptionFlags exitButton; + wxMacCFStringHolder cfText(msgDlg); + OSStatus err = CFUserNotificationDisplayAlert( + 0, kAlertStopAlert, NULL, NULL, NULL, CFSTR("wxWidgets Debug Alert"), cfText, + CFSTR("Yes"), CFSTR("No"), CFSTR("Cancel"), &exitButton ); + if ( err == noErr ) + { + switch( exitButton ) + { + case 0 : // yes + wxTrap(); + break; + case 2 : // cancel + // no more asserts + return true; + case 1 : // no -> nothing to do + break ; + } + } +#else + switch ( wxMessageBox(msgDlg, wxT("wxWidgets Debug Alert"), + wxYES_NO | wxCANCEL | wxICON_STOP ) ) + { + case wxYES: + wxTrap(); + break; + + case wxCANCEL: + // no more asserts + return true; + + //case wxNO: nothing to do + } +#endif + return false; +#endif // !wxUSE_MSGDLG/wxUSE_MSGDLG +} + +#endif // __WXDEBUG__ + +bool wxGUIAppTraitsBase::HasStderr() +{ + // we consider that under Unix stderr always goes somewhere, even if the + // user doesn't always see it under GUI desktops +#ifdef __UNIX__ + return true; +#else + return false; +#endif +} + +void wxGUIAppTraitsBase::ScheduleForDestroy(wxObject *object) +{ + if ( !wxPendingDelete.Member(object) ) + wxPendingDelete.Append(object); +} + +void wxGUIAppTraitsBase::RemoveFromPendingDelete(wxObject *object) +{ + wxPendingDelete.DeleteObject(object); +} + +#if wxUSE_SOCKETS + +#if defined(__WINDOWS__) + #include "wx/msw/gsockmsw.h" +#elif defined(__UNIX__) || defined(__DARWIN__) || defined(__OS2__) + #include "wx/unix/gsockunx.h" +#elif defined(__WXMAC__) + #include + #define OTUNIXERRORS 1 + #include + #include + #include + + #include "wx/mac/gsockmac.h" +#else + #error "Must include correct GSocket header here" +#endif + +GSocketGUIFunctionsTable* wxGUIAppTraitsBase::GetSocketGUIFunctionsTable() +{ +#if defined(__WXMAC__) && !defined(__DARWIN__) + // NB: wxMac CFM does not have any GUI-specific functions in gsocket.c and + // so it doesn't need this table at all + return NULL; +#else // !__WXMAC__ || __DARWIN__ + static GSocketGUIFunctionsTableConcrete table; + return &table; +#endif // !__WXMAC__ || __DARWIN__ +} + +#endif diff --git a/Source/3rd Party/wx/src/common/arcall.cpp b/Source/3rd Party/wx/src/common/arcall.cpp index a66ea703d..bedf19bec 100644 --- a/Source/3rd Party/wx/src/common/arcall.cpp +++ b/Source/3rd Party/wx/src/common/arcall.cpp @@ -1,41 +1,41 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/arcall.cpp -// Purpose: wxArchive link all archive streams -// Author: Mike Wetherell -// RCS-ID: $Id: arcall.cpp 42508 2006-10-27 09:53:38Z MW $ -// Copyright: (c) 2006 Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ARCHIVE_STREAMS - -#if wxUSE_ZIPSTREAM -#include "wx/zipstrm.h" -#endif -#if wxUSE_TARSTREAM -#include "wx/tarstrm.h" -#endif - -// Reference archive classes to ensure they are linked into a statically -// linked program that uses Find or GetFirst to look for an archive handler. -// It is in its own file so that the user can override this behaviour by -// providing their own implementation. - -void wxUseArchiveClasses() -{ -#if wxUSE_ZIPSTREAM - wxZipClassFactory(); -#endif -#if wxUSE_TARSTREAM - wxTarClassFactory(); -#endif -} - -#endif // wxUSE_ARCHIVE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/arcall.cpp +// Purpose: wxArchive link all archive streams +// Author: Mike Wetherell +// RCS-ID: $Id: arcall.cpp 42508 2006-10-27 09:53:38Z MW $ +// Copyright: (c) 2006 Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ARCHIVE_STREAMS + +#if wxUSE_ZIPSTREAM +#include "wx/zipstrm.h" +#endif +#if wxUSE_TARSTREAM +#include "wx/tarstrm.h" +#endif + +// Reference archive classes to ensure they are linked into a statically +// linked program that uses Find or GetFirst to look for an archive handler. +// It is in its own file so that the user can override this behaviour by +// providing their own implementation. + +void wxUseArchiveClasses() +{ +#if wxUSE_ZIPSTREAM + wxZipClassFactory(); +#endif +#if wxUSE_TARSTREAM + wxTarClassFactory(); +#endif +} + +#endif // wxUSE_ARCHIVE_STREAMS diff --git a/Source/3rd Party/wx/src/common/arcfind.cpp b/Source/3rd Party/wx/src/common/arcfind.cpp index f983993fc..c105dc640 100644 --- a/Source/3rd Party/wx/src/common/arcfind.cpp +++ b/Source/3rd Party/wx/src/common/arcfind.cpp @@ -1,43 +1,43 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/arcfind.cpp -// Purpose: Streams for archive formats -// Author: Mike Wetherell -// RCS-ID: $Id: arcfind.cpp 42508 2006-10-27 09:53:38Z MW $ -// Copyright: (c) Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ARCHIVE_STREAMS - -#include "wx/archive.h" - -// These functions are in a separate file so that statically linked apps -// that do not call them to search for archive handlers will only link in -// the archive classes they use. - -const wxArchiveClassFactory * -wxArchiveClassFactory::Find(const wxChar *protocol, wxStreamProtocolType type) -{ - for (const wxArchiveClassFactory *f = GetFirst(); f; f = f->GetNext()) - if (f->CanHandle(protocol, type)) - return f; - - return NULL; -} - -// static -const wxArchiveClassFactory *wxArchiveClassFactory::GetFirst() -{ - if (!sm_first) - wxUseArchiveClasses(); - return sm_first; -} - -#endif // wxUSE_ARCHIVE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/arcfind.cpp +// Purpose: Streams for archive formats +// Author: Mike Wetherell +// RCS-ID: $Id: arcfind.cpp 42508 2006-10-27 09:53:38Z MW $ +// Copyright: (c) Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ARCHIVE_STREAMS + +#include "wx/archive.h" + +// These functions are in a separate file so that statically linked apps +// that do not call them to search for archive handlers will only link in +// the archive classes they use. + +const wxArchiveClassFactory * +wxArchiveClassFactory::Find(const wxChar *protocol, wxStreamProtocolType type) +{ + for (const wxArchiveClassFactory *f = GetFirst(); f; f = f->GetNext()) + if (f->CanHandle(protocol, type)) + return f; + + return NULL; +} + +// static +const wxArchiveClassFactory *wxArchiveClassFactory::GetFirst() +{ + if (!sm_first) + wxUseArchiveClasses(); + return sm_first; +} + +#endif // wxUSE_ARCHIVE_STREAMS diff --git a/Source/3rd Party/wx/src/common/archive.cpp b/Source/3rd Party/wx/src/common/archive.cpp index 512e3d738..1c2dfdb44 100644 --- a/Source/3rd Party/wx/src/common/archive.cpp +++ b/Source/3rd Party/wx/src/common/archive.cpp @@ -1,98 +1,98 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/archive.cpp -// Purpose: Streams for archive formats -// Author: Mike Wetherell -// RCS-ID: $Id: archive.cpp 42508 2006-10-27 09:53:38Z MW $ -// Copyright: (c) Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS - -#include "wx/archive.h" - -IMPLEMENT_ABSTRACT_CLASS(wxArchiveEntry, wxObject) -IMPLEMENT_ABSTRACT_CLASS(wxArchiveClassFactory, wxFilterClassFactoryBase) - - -///////////////////////////////////////////////////////////////////////////// -// wxArchiveInputStream - -wxArchiveInputStream::wxArchiveInputStream(wxInputStream& stream, - wxMBConv& conv) - : wxFilterInputStream(stream), - m_conv(conv) -{ -} - -wxArchiveInputStream::wxArchiveInputStream(wxInputStream *stream, - wxMBConv& conv) - : wxFilterInputStream(stream), - m_conv(conv) -{ -} - - -///////////////////////////////////////////////////////////////////////////// -// wxArchiveOutputStream - -wxArchiveOutputStream::wxArchiveOutputStream(wxOutputStream& stream, - wxMBConv& conv) - : wxFilterOutputStream(stream), - m_conv(conv) -{ -} - -wxArchiveOutputStream::wxArchiveOutputStream(wxOutputStream *stream, - wxMBConv& conv) - : wxFilterOutputStream(stream), - m_conv(conv) -{ -} - - -///////////////////////////////////////////////////////////////////////////// -// wxArchiveEntry - -void wxArchiveEntry::SetNotifier(wxArchiveNotifier& notifier) -{ - UnsetNotifier(); - m_notifier = ¬ifier; - m_notifier->OnEntryUpdated(*this); -} - -wxArchiveEntry& wxArchiveEntry::operator=(const wxArchiveEntry& WXUNUSED(e)) -{ - m_notifier = NULL; - return *this; -} - - -///////////////////////////////////////////////////////////////////////////// -// wxArchiveClassFactory - -wxArchiveClassFactory *wxArchiveClassFactory::sm_first = NULL; - -void wxArchiveClassFactory::Remove() -{ - if (m_next != this) - { - wxArchiveClassFactory **pp = &sm_first; - - while (*pp != this) - pp = &(*pp)->m_next; - - *pp = m_next; - - m_next = this; - } -} - -#endif // wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/archive.cpp +// Purpose: Streams for archive formats +// Author: Mike Wetherell +// RCS-ID: $Id: archive.cpp 42508 2006-10-27 09:53:38Z MW $ +// Copyright: (c) Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS + +#include "wx/archive.h" + +IMPLEMENT_ABSTRACT_CLASS(wxArchiveEntry, wxObject) +IMPLEMENT_ABSTRACT_CLASS(wxArchiveClassFactory, wxFilterClassFactoryBase) + + +///////////////////////////////////////////////////////////////////////////// +// wxArchiveInputStream + +wxArchiveInputStream::wxArchiveInputStream(wxInputStream& stream, + wxMBConv& conv) + : wxFilterInputStream(stream), + m_conv(conv) +{ +} + +wxArchiveInputStream::wxArchiveInputStream(wxInputStream *stream, + wxMBConv& conv) + : wxFilterInputStream(stream), + m_conv(conv) +{ +} + + +///////////////////////////////////////////////////////////////////////////// +// wxArchiveOutputStream + +wxArchiveOutputStream::wxArchiveOutputStream(wxOutputStream& stream, + wxMBConv& conv) + : wxFilterOutputStream(stream), + m_conv(conv) +{ +} + +wxArchiveOutputStream::wxArchiveOutputStream(wxOutputStream *stream, + wxMBConv& conv) + : wxFilterOutputStream(stream), + m_conv(conv) +{ +} + + +///////////////////////////////////////////////////////////////////////////// +// wxArchiveEntry + +void wxArchiveEntry::SetNotifier(wxArchiveNotifier& notifier) +{ + UnsetNotifier(); + m_notifier = ¬ifier; + m_notifier->OnEntryUpdated(*this); +} + +wxArchiveEntry& wxArchiveEntry::operator=(const wxArchiveEntry& WXUNUSED(e)) +{ + m_notifier = NULL; + return *this; +} + + +///////////////////////////////////////////////////////////////////////////// +// wxArchiveClassFactory + +wxArchiveClassFactory *wxArchiveClassFactory::sm_first = NULL; + +void wxArchiveClassFactory::Remove() +{ + if (m_next != this) + { + wxArchiveClassFactory **pp = &sm_first; + + while (*pp != this) + pp = &(*pp)->m_next; + + *pp = m_next; + + m_next = this; + } +} + +#endif // wxUSE_STREAMS && wxUSE_ARCHIVE_STREAMS diff --git a/Source/3rd Party/wx/src/common/artprov.cpp b/Source/3rd Party/wx/src/common/artprov.cpp index 15a6415cd..5fec0e1c9 100644 --- a/Source/3rd Party/wx/src/common/artprov.cpp +++ b/Source/3rd Party/wx/src/common/artprov.cpp @@ -1,354 +1,354 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/artprov.cpp -// Purpose: wxArtProvider class -// Author: Vaclav Slavik -// Modified by: -// Created: 18/03/2002 -// RCS-ID: $Id: artprov.cpp 57701 2008-12-31 23:40:06Z VS $ -// Copyright: (c) Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#include "wx/artprov.h" - -#ifndef WX_PRECOMP - #include "wx/list.h" - #include "wx/log.h" - #include "wx/hashmap.h" - #include "wx/image.h" - #include "wx/module.h" -#endif - -#ifdef __WXMSW__ - #include "wx/msw/wrapwin.h" -#endif - -// =========================================================================== -// implementation -// =========================================================================== - -#include "wx/listimpl.cpp" -WX_DECLARE_LIST(wxArtProvider, wxArtProvidersList); -WX_DEFINE_LIST(wxArtProvidersList) - -// ---------------------------------------------------------------------------- -// Cache class - stores already requested bitmaps -// ---------------------------------------------------------------------------- - -WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxBitmap, wxArtProviderBitmapsHash); - -class WXDLLEXPORT wxArtProviderCache -{ -public: - bool GetBitmap(const wxString& full_id, wxBitmap* bmp); - void PutBitmap(const wxString& full_id, const wxBitmap& bmp) - { m_bitmapsHash[full_id] = bmp; } - - void Clear(); - - static wxString ConstructHashID(const wxArtID& id, - const wxArtClient& client, - const wxSize& size); - -private: - wxArtProviderBitmapsHash m_bitmapsHash; -}; - -bool wxArtProviderCache::GetBitmap(const wxString& full_id, wxBitmap* bmp) -{ - wxArtProviderBitmapsHash::iterator entry = m_bitmapsHash.find(full_id); - if ( entry == m_bitmapsHash.end() ) - { - return false; - } - else - { - *bmp = entry->second; - return true; - } -} - -void wxArtProviderCache::Clear() -{ - m_bitmapsHash.clear(); -} - -/*static*/ wxString wxArtProviderCache::ConstructHashID( - const wxArtID& id, const wxArtClient& client, - const wxSize& size) -{ - wxString str; - str.Printf(wxT("%s-%s-%i-%i"), id.c_str(), client.c_str(), size.x, size.y); - return str; -} - - -// ============================================================================ -// wxArtProvider class -// ============================================================================ - -IMPLEMENT_ABSTRACT_CLASS(wxArtProvider, wxObject) - -wxArtProvidersList *wxArtProvider::sm_providers = NULL; -wxArtProviderCache *wxArtProvider::sm_cache = NULL; - -// ---------------------------------------------------------------------------- -// wxArtProvider ctors/dtor -// ---------------------------------------------------------------------------- - -wxArtProvider::~wxArtProvider() -{ - Remove(this); -} - -// ---------------------------------------------------------------------------- -// wxArtProvider operations on provider stack -// ---------------------------------------------------------------------------- - -/*static*/ void wxArtProvider::CommonAddingProvider() -{ - if ( !sm_providers ) - { - sm_providers = new wxArtProvidersList; - sm_cache = new wxArtProviderCache; - } - - sm_cache->Clear(); -} - -/*static*/ void wxArtProvider::Push(wxArtProvider *provider) -{ - CommonAddingProvider(); - sm_providers->Insert(provider); -} - -/*static*/ void wxArtProvider::Insert(wxArtProvider *provider) -{ - CommonAddingProvider(); - sm_providers->Append(provider); -} - -/*static*/ void wxArtProvider::PushBack(wxArtProvider *provider) -{ - Insert(provider); -} - -/*static*/ bool wxArtProvider::Pop() -{ - wxCHECK_MSG( sm_providers, false, _T("no wxArtProvider exists") ); - wxCHECK_MSG( !sm_providers->empty(), false, _T("wxArtProviders stack is empty") ); - - delete sm_providers->GetFirst()->GetData(); - sm_cache->Clear(); - return true; -} - -/*static*/ bool wxArtProvider::Remove(wxArtProvider *provider) -{ - wxCHECK_MSG( sm_providers, false, _T("no wxArtProvider exists") ); - - if ( sm_providers->DeleteObject(provider) ) - { - sm_cache->Clear(); - return true; - } - - return false; -} - -/*static*/ bool wxArtProvider::Delete(wxArtProvider *provider) -{ - // provider will remove itself from the stack in its dtor - delete provider; - - return true; -} - -/*static*/ void wxArtProvider::CleanUpProviders() -{ - if ( sm_providers ) - { - while ( !sm_providers->empty() ) - delete *sm_providers->begin(); - - delete sm_providers; - sm_providers = NULL; - - delete sm_cache; - sm_cache = NULL; - } -} - -// ---------------------------------------------------------------------------- -// wxArtProvider: retrieving bitmaps/icons -// ---------------------------------------------------------------------------- - -/*static*/ wxBitmap wxArtProvider::GetBitmap(const wxArtID& id, - const wxArtClient& client, - const wxSize& size) -{ - // safety-check against writing client,id,size instead of id,client,size: - wxASSERT_MSG( client.Last() == _T('C'), _T("invalid 'client' parameter") ); - - wxCHECK_MSG( sm_providers, wxNullBitmap, _T("no wxArtProvider exists") ); - - wxString hashId = wxArtProviderCache::ConstructHashID(id, client, size); - - wxBitmap bmp; - if ( !sm_cache->GetBitmap(hashId, &bmp) ) - { - for (wxArtProvidersList::compatibility_iterator node = sm_providers->GetFirst(); - node; node = node->GetNext()) - { - bmp = node->GetData()->CreateBitmap(id, client, size); - if ( bmp.Ok() ) - { -#if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) - if ( size != wxDefaultSize && - (bmp.GetWidth() != size.x || bmp.GetHeight() != size.y) ) - { - wxImage img = bmp.ConvertToImage(); - img.Rescale(size.x, size.y); - bmp = wxBitmap(img); - } -#endif - break; - } - } - - sm_cache->PutBitmap(hashId, bmp); - } - - return bmp; -} - -/*static*/ wxIcon wxArtProvider::GetIcon(const wxArtID& id, - const wxArtClient& client, - const wxSize& size) -{ - wxCHECK_MSG( sm_providers, wxNullIcon, _T("no wxArtProvider exists") ); - - wxBitmap bmp = GetBitmap(id, client, size); - if ( !bmp.Ok() ) - return wxNullIcon; - - wxIcon icon; - icon.CopyFromBitmap(bmp); - return icon; -} - -#if defined(__WXGTK20__) && !defined(__WXUNIVERSAL__) - #include "wx/gtk/private.h" - extern GtkIconSize wxArtClientToIconSize(const wxArtClient& client); -#endif // defined(__WXGTK20__) && !defined(__WXUNIVERSAL__) - -/*static*/ wxSize wxArtProvider::GetSizeHint(const wxArtClient& client, - bool platform_dependent) -{ - if (!platform_dependent) - { - wxArtProvidersList::compatibility_iterator node = sm_providers->GetFirst(); - if (node) - return node->GetData()->DoGetSizeHint(client); - } - - // else return platform dependent size - -#if defined(__WXGTK20__) && !defined(__WXUNIVERSAL__) - // Gtk has specific sizes for each client, see artgtk.cpp - GtkIconSize gtk_size = wxArtClientToIconSize(client); - // no size hints for this client - if (gtk_size == GTK_ICON_SIZE_INVALID) - return wxDefaultSize; - gint width, height; - gtk_icon_size_lookup( gtk_size, &width, &height); - return wxSize(width, height); -#else // !GTK+ 2 - // NB: These size hints may have to be adjusted per platform - if (client == wxART_TOOLBAR) - return wxSize(16, 15); - else if (client == wxART_MENU) - return wxSize(16, 15); - else if (client == wxART_FRAME_ICON) - { -#ifdef __WXMSW__ - return wxSize(::GetSystemMetrics(SM_CXSMICON), - ::GetSystemMetrics(SM_CYSMICON)); -#else - return wxSize(16, 16); -#endif // __WXMSW__/!__WXMSW__ - } - else if (client == wxART_CMN_DIALOG || client == wxART_MESSAGE_BOX) - return wxSize(32, 32); - else if (client == wxART_HELP_BROWSER) - return wxSize(16, 15); - else if (client == wxART_BUTTON) - return wxSize(16, 15); - else // wxART_OTHER or perhaps a user's client, no specified size - return wxDefaultSize; -#endif // GTK+ 2/else -} - -// ---------------------------------------------------------------------------- -// deprecated wxArtProvider methods -// ---------------------------------------------------------------------------- - -#if WXWIN_COMPATIBILITY_2_6 - -/* static */ void wxArtProvider::PushProvider(wxArtProvider *provider) -{ - Push(provider); -} - -/* static */ void wxArtProvider::InsertProvider(wxArtProvider *provider) -{ - Insert(provider); -} - -/* static */ bool wxArtProvider::PopProvider() -{ - return Pop(); -} - -/* static */ bool wxArtProvider::RemoveProvider(wxArtProvider *provider) -{ - // RemoveProvider() used to delete the provider being removed so this is - // not a typo, we must call Delete() and not Remove() here - return Delete(provider); -} - -#endif // WXWIN_COMPATIBILITY_2_6 - -// ============================================================================ -// wxArtProviderModule -// ============================================================================ - -class wxArtProviderModule: public wxModule -{ -public: - bool OnInit() - { - wxArtProvider::InitStdProvider(); - wxArtProvider::InitNativeProvider(); - return true; - } - void OnExit() - { - wxArtProvider::CleanUpProviders(); - } - - DECLARE_DYNAMIC_CLASS(wxArtProviderModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxArtProviderModule, wxModule) +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/artprov.cpp +// Purpose: wxArtProvider class +// Author: Vaclav Slavik +// Modified by: +// Created: 18/03/2002 +// RCS-ID: $Id: artprov.cpp 57701 2008-12-31 23:40:06Z VS $ +// Copyright: (c) Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#include "wx/artprov.h" + +#ifndef WX_PRECOMP + #include "wx/list.h" + #include "wx/log.h" + #include "wx/hashmap.h" + #include "wx/image.h" + #include "wx/module.h" +#endif + +#ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" +#endif + +// =========================================================================== +// implementation +// =========================================================================== + +#include "wx/listimpl.cpp" +WX_DECLARE_LIST(wxArtProvider, wxArtProvidersList); +WX_DEFINE_LIST(wxArtProvidersList) + +// ---------------------------------------------------------------------------- +// Cache class - stores already requested bitmaps +// ---------------------------------------------------------------------------- + +WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxBitmap, wxArtProviderBitmapsHash); + +class WXDLLEXPORT wxArtProviderCache +{ +public: + bool GetBitmap(const wxString& full_id, wxBitmap* bmp); + void PutBitmap(const wxString& full_id, const wxBitmap& bmp) + { m_bitmapsHash[full_id] = bmp; } + + void Clear(); + + static wxString ConstructHashID(const wxArtID& id, + const wxArtClient& client, + const wxSize& size); + +private: + wxArtProviderBitmapsHash m_bitmapsHash; +}; + +bool wxArtProviderCache::GetBitmap(const wxString& full_id, wxBitmap* bmp) +{ + wxArtProviderBitmapsHash::iterator entry = m_bitmapsHash.find(full_id); + if ( entry == m_bitmapsHash.end() ) + { + return false; + } + else + { + *bmp = entry->second; + return true; + } +} + +void wxArtProviderCache::Clear() +{ + m_bitmapsHash.clear(); +} + +/*static*/ wxString wxArtProviderCache::ConstructHashID( + const wxArtID& id, const wxArtClient& client, + const wxSize& size) +{ + wxString str; + str.Printf(wxT("%s-%s-%i-%i"), id.c_str(), client.c_str(), size.x, size.y); + return str; +} + + +// ============================================================================ +// wxArtProvider class +// ============================================================================ + +IMPLEMENT_ABSTRACT_CLASS(wxArtProvider, wxObject) + +wxArtProvidersList *wxArtProvider::sm_providers = NULL; +wxArtProviderCache *wxArtProvider::sm_cache = NULL; + +// ---------------------------------------------------------------------------- +// wxArtProvider ctors/dtor +// ---------------------------------------------------------------------------- + +wxArtProvider::~wxArtProvider() +{ + Remove(this); +} + +// ---------------------------------------------------------------------------- +// wxArtProvider operations on provider stack +// ---------------------------------------------------------------------------- + +/*static*/ void wxArtProvider::CommonAddingProvider() +{ + if ( !sm_providers ) + { + sm_providers = new wxArtProvidersList; + sm_cache = new wxArtProviderCache; + } + + sm_cache->Clear(); +} + +/*static*/ void wxArtProvider::Push(wxArtProvider *provider) +{ + CommonAddingProvider(); + sm_providers->Insert(provider); +} + +/*static*/ void wxArtProvider::Insert(wxArtProvider *provider) +{ + CommonAddingProvider(); + sm_providers->Append(provider); +} + +/*static*/ void wxArtProvider::PushBack(wxArtProvider *provider) +{ + Insert(provider); +} + +/*static*/ bool wxArtProvider::Pop() +{ + wxCHECK_MSG( sm_providers, false, _T("no wxArtProvider exists") ); + wxCHECK_MSG( !sm_providers->empty(), false, _T("wxArtProviders stack is empty") ); + + delete sm_providers->GetFirst()->GetData(); + sm_cache->Clear(); + return true; +} + +/*static*/ bool wxArtProvider::Remove(wxArtProvider *provider) +{ + wxCHECK_MSG( sm_providers, false, _T("no wxArtProvider exists") ); + + if ( sm_providers->DeleteObject(provider) ) + { + sm_cache->Clear(); + return true; + } + + return false; +} + +/*static*/ bool wxArtProvider::Delete(wxArtProvider *provider) +{ + // provider will remove itself from the stack in its dtor + delete provider; + + return true; +} + +/*static*/ void wxArtProvider::CleanUpProviders() +{ + if ( sm_providers ) + { + while ( !sm_providers->empty() ) + delete *sm_providers->begin(); + + delete sm_providers; + sm_providers = NULL; + + delete sm_cache; + sm_cache = NULL; + } +} + +// ---------------------------------------------------------------------------- +// wxArtProvider: retrieving bitmaps/icons +// ---------------------------------------------------------------------------- + +/*static*/ wxBitmap wxArtProvider::GetBitmap(const wxArtID& id, + const wxArtClient& client, + const wxSize& size) +{ + // safety-check against writing client,id,size instead of id,client,size: + wxASSERT_MSG( client.Last() == _T('C'), _T("invalid 'client' parameter") ); + + wxCHECK_MSG( sm_providers, wxNullBitmap, _T("no wxArtProvider exists") ); + + wxString hashId = wxArtProviderCache::ConstructHashID(id, client, size); + + wxBitmap bmp; + if ( !sm_cache->GetBitmap(hashId, &bmp) ) + { + for (wxArtProvidersList::compatibility_iterator node = sm_providers->GetFirst(); + node; node = node->GetNext()) + { + bmp = node->GetData()->CreateBitmap(id, client, size); + if ( bmp.Ok() ) + { +#if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) + if ( size != wxDefaultSize && + (bmp.GetWidth() != size.x || bmp.GetHeight() != size.y) ) + { + wxImage img = bmp.ConvertToImage(); + img.Rescale(size.x, size.y); + bmp = wxBitmap(img); + } +#endif + break; + } + } + + sm_cache->PutBitmap(hashId, bmp); + } + + return bmp; +} + +/*static*/ wxIcon wxArtProvider::GetIcon(const wxArtID& id, + const wxArtClient& client, + const wxSize& size) +{ + wxCHECK_MSG( sm_providers, wxNullIcon, _T("no wxArtProvider exists") ); + + wxBitmap bmp = GetBitmap(id, client, size); + if ( !bmp.Ok() ) + return wxNullIcon; + + wxIcon icon; + icon.CopyFromBitmap(bmp); + return icon; +} + +#if defined(__WXGTK20__) && !defined(__WXUNIVERSAL__) + #include "wx/gtk/private.h" + extern GtkIconSize wxArtClientToIconSize(const wxArtClient& client); +#endif // defined(__WXGTK20__) && !defined(__WXUNIVERSAL__) + +/*static*/ wxSize wxArtProvider::GetSizeHint(const wxArtClient& client, + bool platform_dependent) +{ + if (!platform_dependent) + { + wxArtProvidersList::compatibility_iterator node = sm_providers->GetFirst(); + if (node) + return node->GetData()->DoGetSizeHint(client); + } + + // else return platform dependent size + +#if defined(__WXGTK20__) && !defined(__WXUNIVERSAL__) + // Gtk has specific sizes for each client, see artgtk.cpp + GtkIconSize gtk_size = wxArtClientToIconSize(client); + // no size hints for this client + if (gtk_size == GTK_ICON_SIZE_INVALID) + return wxDefaultSize; + gint width, height; + gtk_icon_size_lookup( gtk_size, &width, &height); + return wxSize(width, height); +#else // !GTK+ 2 + // NB: These size hints may have to be adjusted per platform + if (client == wxART_TOOLBAR) + return wxSize(16, 15); + else if (client == wxART_MENU) + return wxSize(16, 15); + else if (client == wxART_FRAME_ICON) + { +#ifdef __WXMSW__ + return wxSize(::GetSystemMetrics(SM_CXSMICON), + ::GetSystemMetrics(SM_CYSMICON)); +#else + return wxSize(16, 16); +#endif // __WXMSW__/!__WXMSW__ + } + else if (client == wxART_CMN_DIALOG || client == wxART_MESSAGE_BOX) + return wxSize(32, 32); + else if (client == wxART_HELP_BROWSER) + return wxSize(16, 15); + else if (client == wxART_BUTTON) + return wxSize(16, 15); + else // wxART_OTHER or perhaps a user's client, no specified size + return wxDefaultSize; +#endif // GTK+ 2/else +} + +// ---------------------------------------------------------------------------- +// deprecated wxArtProvider methods +// ---------------------------------------------------------------------------- + +#if WXWIN_COMPATIBILITY_2_6 + +/* static */ void wxArtProvider::PushProvider(wxArtProvider *provider) +{ + Push(provider); +} + +/* static */ void wxArtProvider::InsertProvider(wxArtProvider *provider) +{ + Insert(provider); +} + +/* static */ bool wxArtProvider::PopProvider() +{ + return Pop(); +} + +/* static */ bool wxArtProvider::RemoveProvider(wxArtProvider *provider) +{ + // RemoveProvider() used to delete the provider being removed so this is + // not a typo, we must call Delete() and not Remove() here + return Delete(provider); +} + +#endif // WXWIN_COMPATIBILITY_2_6 + +// ============================================================================ +// wxArtProviderModule +// ============================================================================ + +class wxArtProviderModule: public wxModule +{ +public: + bool OnInit() + { + wxArtProvider::InitStdProvider(); + wxArtProvider::InitNativeProvider(); + return true; + } + void OnExit() + { + wxArtProvider::CleanUpProviders(); + } + + DECLARE_DYNAMIC_CLASS(wxArtProviderModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxArtProviderModule, wxModule) diff --git a/Source/3rd Party/wx/src/common/artstd.cpp b/Source/3rd Party/wx/src/common/artstd.cpp index 6075ae8f2..c50aae5f6 100644 --- a/Source/3rd Party/wx/src/common/artstd.cpp +++ b/Source/3rd Party/wx/src/common/artstd.cpp @@ -1,267 +1,267 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/artstd.cpp -// Purpose: stock wxArtProvider instance with default wxWin art -// Author: Vaclav Slavik -// Modified by: -// Created: 18/03/2002 -// RCS-ID: $Id: artstd.cpp 52561 2008-03-16 00:36:37Z VS $ -// Copyright: (c) Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/image.h" -#endif - -#include "wx/artprov.h" - -// ---------------------------------------------------------------------------- -// wxDefaultArtProvider -// ---------------------------------------------------------------------------- - -class wxDefaultArtProvider : public wxArtProvider -{ -protected: - virtual wxBitmap CreateBitmap(const wxArtID& id, const wxArtClient& client, - const wxSize& size); -}; - -// ---------------------------------------------------------------------------- -// helper macros -// ---------------------------------------------------------------------------- - -// Standard macro for getting a resource from XPM file: -#define ART(artId, xpmRc) \ - if ( id == artId ) return wxBitmap(xpmRc##_xpm); - -// There are two ways of getting the standard icon: either via XPMs or via -// wxIcon ctor. This depends on the platform: -#if defined(__WXUNIVERSAL__) - #define CREATE_STD_ICON(iconId, xpmRc) return wxNullBitmap; -#elif defined(__WXGTK__) || defined(__WXMOTIF__) - #define CREATE_STD_ICON(iconId, xpmRc) return wxBitmap(xpmRc##_xpm); -#else - #define CREATE_STD_ICON(iconId, xpmRc) \ - { \ - wxIcon icon(_T(iconId)); \ - wxBitmap bmp; \ - bmp.CopyFromIcon(icon); \ - return bmp; \ - } -#endif - -// Macro used in CreateBitmap to get wxICON_FOO icons: -#define ART_MSGBOX(artId, iconId, xpmRc) \ - if ( id == artId ) \ - { \ - CREATE_STD_ICON(#iconId, xpmRc) \ - } - -// ---------------------------------------------------------------------------- -// wxArtProvider::InitStdProvider -// ---------------------------------------------------------------------------- - -/*static*/ void wxArtProvider::InitStdProvider() -{ - wxArtProvider::Push(new wxDefaultArtProvider); -} - -#if !defined(__WXGTK20__) || defined(__WXUNIVERSAL__) -/*static*/ void wxArtProvider::InitNativeProvider() -{ -} -#endif - - -// ---------------------------------------------------------------------------- -// XPMs with the art -// ---------------------------------------------------------------------------- - - -#if defined(__WXGTK__) - #include "../../art/gtk/info.xpm" - #include "../../art/gtk/error.xpm" - #include "../../art/gtk/warning.xpm" - #include "../../art/gtk/question.xpm" -#elif defined(__WXMOTIF__) - #include "../../art/motif/info.xpm" - #include "../../art/motif/error.xpm" - #include "../../art/motif/warning.xpm" - #include "../../art/motif/question.xpm" -#endif - -#if wxUSE_HTML - #include "../../art/htmsidep.xpm" - #include "../../art/htmoptns.xpm" - #include "../../art/htmbook.xpm" - #include "../../art/htmfoldr.xpm" - #include "../../art/htmpage.xpm" -#endif // wxUSE_HTML - -#include "../../art/missimg.xpm" -#include "../../art/addbookm.xpm" -#include "../../art/delbookm.xpm" -#include "../../art/back.xpm" -#include "../../art/forward.xpm" -#include "../../art/up.xpm" -#include "../../art/down.xpm" -#include "../../art/toparent.xpm" -#include "../../art/fileopen.xpm" -#include "../../art/print.xpm" -#include "../../art/helpicon.xpm" -#include "../../art/tipicon.xpm" -#include "../../art/home.xpm" -#include "../../art/repview.xpm" -#include "../../art/listview.xpm" -#include "../../art/new_dir.xpm" -#include "../../art/harddisk.xpm" -#include "../../art/cdrom.xpm" -#include "../../art/floppy.xpm" -#include "../../art/removable.xpm" -#include "../../art/folder.xpm" -#include "../../art/folder_open.xpm" -#include "../../art/dir_up.xpm" -#include "../../art/exefile.xpm" -#include "../../art/deffile.xpm" -#include "../../art/tick.xpm" -#include "../../art/cross.xpm" - -#include "../../art/filesave.xpm" -#include "../../art/filesaveas.xpm" -#include "../../art/copy.xpm" -#include "../../art/cut.xpm" -#include "../../art/paste.xpm" -#include "../../art/delete.xpm" -#include "../../art/new.xpm" -#include "../../art/undo.xpm" -#include "../../art/redo.xpm" -#include "../../art/quit.xpm" -#include "../../art/find.xpm" -#include "../../art/findrepl.xpm" - - - -wxBitmap wxDefaultArtProvider_CreateBitmap(const wxArtID& id) -{ - // wxMessageBox icons: - ART_MSGBOX(wxART_ERROR, wxICON_ERROR, error) - ART_MSGBOX(wxART_INFORMATION, wxICON_INFORMATION, info) - ART_MSGBOX(wxART_WARNING, wxICON_WARNING, warning) - ART_MSGBOX(wxART_QUESTION, wxICON_QUESTION, question) - - // standard icons: -#if wxUSE_HTML - ART(wxART_HELP_SIDE_PANEL, htmsidep) - ART(wxART_HELP_SETTINGS, htmoptns) - ART(wxART_HELP_BOOK, htmbook) - ART(wxART_HELP_FOLDER, htmfoldr) - ART(wxART_HELP_PAGE, htmpage) -#endif // wxUSE_HTML - ART(wxART_MISSING_IMAGE, missimg) - ART(wxART_ADD_BOOKMARK, addbookm) - ART(wxART_DEL_BOOKMARK, delbookm) - ART(wxART_GO_BACK, back) - ART(wxART_GO_FORWARD, forward) - ART(wxART_GO_UP, up) - ART(wxART_GO_DOWN, down) - ART(wxART_GO_TO_PARENT, toparent) - ART(wxART_GO_HOME, home) - ART(wxART_FILE_OPEN, fileopen) - ART(wxART_PRINT, print) - ART(wxART_HELP, helpicon) - ART(wxART_TIP, tipicon) - ART(wxART_REPORT_VIEW, repview) - ART(wxART_LIST_VIEW, listview) - ART(wxART_NEW_DIR, new_dir) - ART(wxART_HARDDISK, harddisk) - ART(wxART_FLOPPY, floppy) - ART(wxART_CDROM, cdrom) - ART(wxART_REMOVABLE, removable) - ART(wxART_FOLDER, folder) - ART(wxART_FOLDER_OPEN, folder_open) - ART(wxART_GO_DIR_UP, dir_up) - ART(wxART_EXECUTABLE_FILE, exefile) - ART(wxART_NORMAL_FILE, deffile) - ART(wxART_TICK_MARK, tick) - ART(wxART_CROSS_MARK, cross) - - ART(wxART_FILE_SAVE, filesave) - ART(wxART_FILE_SAVE_AS, filesaveas) - ART(wxART_COPY, copy) - ART(wxART_CUT, cut) - ART(wxART_PASTE, paste) - ART(wxART_DELETE, delete) - ART(wxART_UNDO, undo) - ART(wxART_REDO, redo) - ART(wxART_QUIT, quit) - ART(wxART_FIND, find) - ART(wxART_FIND_AND_REPLACE, findrepl) - ART(wxART_NEW, new) - - - return wxNullBitmap; -} - -// ---------------------------------------------------------------------------- -// CreateBitmap routine -// ---------------------------------------------------------------------------- - -wxBitmap wxDefaultArtProvider::CreateBitmap(const wxArtID& id, - const wxArtClient& client, - const wxSize& reqSize) -{ - wxBitmap bmp = wxDefaultArtProvider_CreateBitmap(id); - -#if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) - if (bmp.Ok()) - { - // fit into transparent image with desired size hint from the client - if (reqSize == wxDefaultSize) - { - // find out if there is a desired size for this client - wxSize bestSize = GetSizeHint(client); - if (bestSize != wxDefaultSize) - { - int bmp_w = bmp.GetWidth(); - int bmp_h = bmp.GetHeight(); - - if ((bmp_h < bestSize.x) && (bmp_w < bestSize.y)) - { - // the caller wants default size, which is larger than - // the image we have; to avoid degrading it visually by - // scaling it up, paste it into transparent image instead: - wxPoint offset((bestSize.x - bmp_w)/2, (bestSize.y - bmp_h)/2); - wxImage img = bmp.ConvertToImage(); - img.Resize(bestSize, offset); - bmp = wxBitmap(img); - } - else // scale (down or mixed, but not up) - { - wxImage img = bmp.ConvertToImage(); - bmp = wxBitmap - ( - img.Scale(bestSize.x, bestSize.y, - wxIMAGE_QUALITY_HIGH) - ); - } - } - } - } -#else - wxUnusedVar(client); - wxUnusedVar(reqSize); -#endif // wxUSE_IMAGE - - return bmp; -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/artstd.cpp +// Purpose: stock wxArtProvider instance with default wxWin art +// Author: Vaclav Slavik +// Modified by: +// Created: 18/03/2002 +// RCS-ID: $Id: artstd.cpp 52561 2008-03-16 00:36:37Z VS $ +// Copyright: (c) Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/image.h" +#endif + +#include "wx/artprov.h" + +// ---------------------------------------------------------------------------- +// wxDefaultArtProvider +// ---------------------------------------------------------------------------- + +class wxDefaultArtProvider : public wxArtProvider +{ +protected: + virtual wxBitmap CreateBitmap(const wxArtID& id, const wxArtClient& client, + const wxSize& size); +}; + +// ---------------------------------------------------------------------------- +// helper macros +// ---------------------------------------------------------------------------- + +// Standard macro for getting a resource from XPM file: +#define ART(artId, xpmRc) \ + if ( id == artId ) return wxBitmap(xpmRc##_xpm); + +// There are two ways of getting the standard icon: either via XPMs or via +// wxIcon ctor. This depends on the platform: +#if defined(__WXUNIVERSAL__) + #define CREATE_STD_ICON(iconId, xpmRc) return wxNullBitmap; +#elif defined(__WXGTK__) || defined(__WXMOTIF__) + #define CREATE_STD_ICON(iconId, xpmRc) return wxBitmap(xpmRc##_xpm); +#else + #define CREATE_STD_ICON(iconId, xpmRc) \ + { \ + wxIcon icon(_T(iconId)); \ + wxBitmap bmp; \ + bmp.CopyFromIcon(icon); \ + return bmp; \ + } +#endif + +// Macro used in CreateBitmap to get wxICON_FOO icons: +#define ART_MSGBOX(artId, iconId, xpmRc) \ + if ( id == artId ) \ + { \ + CREATE_STD_ICON(#iconId, xpmRc) \ + } + +// ---------------------------------------------------------------------------- +// wxArtProvider::InitStdProvider +// ---------------------------------------------------------------------------- + +/*static*/ void wxArtProvider::InitStdProvider() +{ + wxArtProvider::Push(new wxDefaultArtProvider); +} + +#if !defined(__WXGTK20__) || defined(__WXUNIVERSAL__) +/*static*/ void wxArtProvider::InitNativeProvider() +{ +} +#endif + + +// ---------------------------------------------------------------------------- +// XPMs with the art +// ---------------------------------------------------------------------------- + + +#if defined(__WXGTK__) + #include "../../art/gtk/info.xpm" + #include "../../art/gtk/error.xpm" + #include "../../art/gtk/warning.xpm" + #include "../../art/gtk/question.xpm" +#elif defined(__WXMOTIF__) + #include "../../art/motif/info.xpm" + #include "../../art/motif/error.xpm" + #include "../../art/motif/warning.xpm" + #include "../../art/motif/question.xpm" +#endif + +#if wxUSE_HTML + #include "../../art/htmsidep.xpm" + #include "../../art/htmoptns.xpm" + #include "../../art/htmbook.xpm" + #include "../../art/htmfoldr.xpm" + #include "../../art/htmpage.xpm" +#endif // wxUSE_HTML + +#include "../../art/missimg.xpm" +#include "../../art/addbookm.xpm" +#include "../../art/delbookm.xpm" +#include "../../art/back.xpm" +#include "../../art/forward.xpm" +#include "../../art/up.xpm" +#include "../../art/down.xpm" +#include "../../art/toparent.xpm" +#include "../../art/fileopen.xpm" +#include "../../art/print.xpm" +#include "../../art/helpicon.xpm" +#include "../../art/tipicon.xpm" +#include "../../art/home.xpm" +#include "../../art/repview.xpm" +#include "../../art/listview.xpm" +#include "../../art/new_dir.xpm" +#include "../../art/harddisk.xpm" +#include "../../art/cdrom.xpm" +#include "../../art/floppy.xpm" +#include "../../art/removable.xpm" +#include "../../art/folder.xpm" +#include "../../art/folder_open.xpm" +#include "../../art/dir_up.xpm" +#include "../../art/exefile.xpm" +#include "../../art/deffile.xpm" +#include "../../art/tick.xpm" +#include "../../art/cross.xpm" + +#include "../../art/filesave.xpm" +#include "../../art/filesaveas.xpm" +#include "../../art/copy.xpm" +#include "../../art/cut.xpm" +#include "../../art/paste.xpm" +#include "../../art/delete.xpm" +#include "../../art/new.xpm" +#include "../../art/undo.xpm" +#include "../../art/redo.xpm" +#include "../../art/quit.xpm" +#include "../../art/find.xpm" +#include "../../art/findrepl.xpm" + + + +wxBitmap wxDefaultArtProvider_CreateBitmap(const wxArtID& id) +{ + // wxMessageBox icons: + ART_MSGBOX(wxART_ERROR, wxICON_ERROR, error) + ART_MSGBOX(wxART_INFORMATION, wxICON_INFORMATION, info) + ART_MSGBOX(wxART_WARNING, wxICON_WARNING, warning) + ART_MSGBOX(wxART_QUESTION, wxICON_QUESTION, question) + + // standard icons: +#if wxUSE_HTML + ART(wxART_HELP_SIDE_PANEL, htmsidep) + ART(wxART_HELP_SETTINGS, htmoptns) + ART(wxART_HELP_BOOK, htmbook) + ART(wxART_HELP_FOLDER, htmfoldr) + ART(wxART_HELP_PAGE, htmpage) +#endif // wxUSE_HTML + ART(wxART_MISSING_IMAGE, missimg) + ART(wxART_ADD_BOOKMARK, addbookm) + ART(wxART_DEL_BOOKMARK, delbookm) + ART(wxART_GO_BACK, back) + ART(wxART_GO_FORWARD, forward) + ART(wxART_GO_UP, up) + ART(wxART_GO_DOWN, down) + ART(wxART_GO_TO_PARENT, toparent) + ART(wxART_GO_HOME, home) + ART(wxART_FILE_OPEN, fileopen) + ART(wxART_PRINT, print) + ART(wxART_HELP, helpicon) + ART(wxART_TIP, tipicon) + ART(wxART_REPORT_VIEW, repview) + ART(wxART_LIST_VIEW, listview) + ART(wxART_NEW_DIR, new_dir) + ART(wxART_HARDDISK, harddisk) + ART(wxART_FLOPPY, floppy) + ART(wxART_CDROM, cdrom) + ART(wxART_REMOVABLE, removable) + ART(wxART_FOLDER, folder) + ART(wxART_FOLDER_OPEN, folder_open) + ART(wxART_GO_DIR_UP, dir_up) + ART(wxART_EXECUTABLE_FILE, exefile) + ART(wxART_NORMAL_FILE, deffile) + ART(wxART_TICK_MARK, tick) + ART(wxART_CROSS_MARK, cross) + + ART(wxART_FILE_SAVE, filesave) + ART(wxART_FILE_SAVE_AS, filesaveas) + ART(wxART_COPY, copy) + ART(wxART_CUT, cut) + ART(wxART_PASTE, paste) + ART(wxART_DELETE, delete) + ART(wxART_UNDO, undo) + ART(wxART_REDO, redo) + ART(wxART_QUIT, quit) + ART(wxART_FIND, find) + ART(wxART_FIND_AND_REPLACE, findrepl) + ART(wxART_NEW, new) + + + return wxNullBitmap; +} + +// ---------------------------------------------------------------------------- +// CreateBitmap routine +// ---------------------------------------------------------------------------- + +wxBitmap wxDefaultArtProvider::CreateBitmap(const wxArtID& id, + const wxArtClient& client, + const wxSize& reqSize) +{ + wxBitmap bmp = wxDefaultArtProvider_CreateBitmap(id); + +#if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) + if (bmp.Ok()) + { + // fit into transparent image with desired size hint from the client + if (reqSize == wxDefaultSize) + { + // find out if there is a desired size for this client + wxSize bestSize = GetSizeHint(client); + if (bestSize != wxDefaultSize) + { + int bmp_w = bmp.GetWidth(); + int bmp_h = bmp.GetHeight(); + + if ((bmp_h < bestSize.x) && (bmp_w < bestSize.y)) + { + // the caller wants default size, which is larger than + // the image we have; to avoid degrading it visually by + // scaling it up, paste it into transparent image instead: + wxPoint offset((bestSize.x - bmp_w)/2, (bestSize.y - bmp_h)/2); + wxImage img = bmp.ConvertToImage(); + img.Resize(bestSize, offset); + bmp = wxBitmap(img); + } + else // scale (down or mixed, but not up) + { + wxImage img = bmp.ConvertToImage(); + bmp = wxBitmap + ( + img.Scale(bestSize.x, bestSize.y, + wxIMAGE_QUALITY_HIGH) + ); + } + } + } + } +#else + wxUnusedVar(client); + wxUnusedVar(reqSize); +#endif // wxUSE_IMAGE + + return bmp; +} diff --git a/Source/3rd Party/wx/src/common/bmpbase.cpp b/Source/3rd Party/wx/src/common/bmpbase.cpp index a1d7c60aa..0c7edd3ac 100644 --- a/Source/3rd Party/wx/src/common/bmpbase.cpp +++ b/Source/3rd Party/wx/src/common/bmpbase.cpp @@ -1,211 +1,211 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/bmpbase.cpp -// Purpose: wxBitmapBase -// Author: VaclavSlavik -// Created: 2001/04/11 -// RCS-ID: $Id: bmpbase.cpp 42752 2006-10-30 19:26:48Z VZ $ -// Copyright: (c) 2001, Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/bitmap.h" - -#ifndef WX_PRECOMP - #include "wx/colour.h" - #include "wx/icon.h" - #include "wx/image.h" -#endif // WX_PRECOMP - -// ---------------------------------------------------------------------------- -// wxVariant support -// ---------------------------------------------------------------------------- - -#if wxUSE_VARIANT -IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxBitmap,WXDLLEXPORT) -IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxIcon,WXDLLEXPORT) -#endif - -// ---------------------------------------------------------------------------- -// wxBitmapBase -// ---------------------------------------------------------------------------- - -#if wxUSE_BITMAP_BASE - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/utils.h" - #include "wx/palette.h" - #include "wx/module.h" -#endif // WX_PRECOMP - - -IMPLEMENT_ABSTRACT_CLASS(wxBitmapBase, wxGDIObject) -IMPLEMENT_ABSTRACT_CLASS(wxBitmapHandlerBase,wxObject) - -wxList wxBitmapBase::sm_handlers; - -void wxBitmapBase::AddHandler(wxBitmapHandlerBase *handler) -{ - sm_handlers.Append(handler); -} - -void wxBitmapBase::InsertHandler(wxBitmapHandlerBase *handler) -{ - sm_handlers.Insert(handler); -} - -bool wxBitmapBase::RemoveHandler(const wxString& name) -{ - wxBitmapHandler *handler = FindHandler(name); - if ( handler ) - { - sm_handlers.DeleteObject(handler); - return true; - } - else - return false; -} - -wxBitmapHandler *wxBitmapBase::FindHandler(const wxString& name) -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while ( node ) - { - wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); - if ( handler->GetName() == name ) - return handler; - node = node->GetNext(); - } - return NULL; -} - -wxBitmapHandler *wxBitmapBase::FindHandler(const wxString& extension, wxBitmapType bitmapType) -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while ( node ) - { - wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); - if ( handler->GetExtension() == extension && - (bitmapType == wxBITMAP_TYPE_ANY || handler->GetType() == bitmapType) ) - return handler; - node = node->GetNext(); - } - return NULL; -} - -wxBitmapHandler *wxBitmapBase::FindHandler(wxBitmapType bitmapType) -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while ( node ) - { - wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); - if (handler->GetType() == bitmapType) - return handler; - node = node->GetNext(); - } - return NULL; -} - -void wxBitmapBase::CleanUpHandlers() -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while ( node ) - { - wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); - wxList::compatibility_iterator next = node->GetNext(); - delete handler; - sm_handlers.Erase(node); - node = next; - } -} - -bool wxBitmapHandlerBase::Create(wxBitmap*, const void*, long, int, int, int) -{ - return false; -} - -bool wxBitmapHandlerBase::LoadFile(wxBitmap*, const wxString&, long, int, int) -{ - return false; -} - -bool wxBitmapHandlerBase::SaveFile(const wxBitmap*, const wxString&, int, const wxPalette*) -{ - return false; -} - -class wxBitmapBaseModule: public wxModule -{ -DECLARE_DYNAMIC_CLASS(wxBitmapBaseModule) -public: - wxBitmapBaseModule() {} - bool OnInit() { wxBitmap::InitStandardHandlers(); return true; } - void OnExit() { wxBitmap::CleanUpHandlers(); } -}; - -IMPLEMENT_DYNAMIC_CLASS(wxBitmapBaseModule, wxModule) - -#endif // wxUSE_BITMAP_BASE - -// ---------------------------------------------------------------------------- -// wxBitmap common -// ---------------------------------------------------------------------------- - -#if !(defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXX11__)) - -wxBitmap::wxBitmap(const char* const* bits) -{ - wxCHECK2_MSG(bits != NULL, return, wxT("invalid bitmap data")); - -#if wxUSE_IMAGE && wxUSE_XPM - wxImage image(bits); - wxCHECK2_MSG(image.Ok(), return, wxT("invalid bitmap data")); - - *this = wxBitmap(image); -#else - wxFAIL_MSG(_T("creating bitmaps from XPMs not supported")); -#endif // wxUSE_IMAGE && wxUSE_XPM -} -#endif // !(defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXX11__)) - -// ---------------------------------------------------------------------------- -// wxMaskBase -// ---------------------------------------------------------------------------- - -bool wxMaskBase::Create(const wxBitmap& bitmap, const wxColour& colour) -{ - FreeData(); - - return InitFromColour(bitmap, colour); -} - -#if wxUSE_PALETTE - -bool wxMaskBase::Create(const wxBitmap& bitmap, int paletteIndex) -{ - wxPalette *pal = bitmap.GetPalette(); - - wxCHECK_MSG( pal, false, - wxT("Cannot create mask from palette index of a bitmap without palette") ); - - unsigned char r,g,b; - pal->GetRGB(paletteIndex, &r, &g, &b); - - return Create(bitmap, wxColour(r, g, b)); -} - -#endif // wxUSE_PALETTE - -bool wxMaskBase::Create(const wxBitmap& bitmap) -{ - FreeData(); - - return InitFromMonoBitmap(bitmap); -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/bmpbase.cpp +// Purpose: wxBitmapBase +// Author: VaclavSlavik +// Created: 2001/04/11 +// RCS-ID: $Id: bmpbase.cpp 42752 2006-10-30 19:26:48Z VZ $ +// Copyright: (c) 2001, Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/bitmap.h" + +#ifndef WX_PRECOMP + #include "wx/colour.h" + #include "wx/icon.h" + #include "wx/image.h" +#endif // WX_PRECOMP + +// ---------------------------------------------------------------------------- +// wxVariant support +// ---------------------------------------------------------------------------- + +#if wxUSE_VARIANT +IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxBitmap,WXDLLEXPORT) +IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxIcon,WXDLLEXPORT) +#endif + +// ---------------------------------------------------------------------------- +// wxBitmapBase +// ---------------------------------------------------------------------------- + +#if wxUSE_BITMAP_BASE + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/utils.h" + #include "wx/palette.h" + #include "wx/module.h" +#endif // WX_PRECOMP + + +IMPLEMENT_ABSTRACT_CLASS(wxBitmapBase, wxGDIObject) +IMPLEMENT_ABSTRACT_CLASS(wxBitmapHandlerBase,wxObject) + +wxList wxBitmapBase::sm_handlers; + +void wxBitmapBase::AddHandler(wxBitmapHandlerBase *handler) +{ + sm_handlers.Append(handler); +} + +void wxBitmapBase::InsertHandler(wxBitmapHandlerBase *handler) +{ + sm_handlers.Insert(handler); +} + +bool wxBitmapBase::RemoveHandler(const wxString& name) +{ + wxBitmapHandler *handler = FindHandler(name); + if ( handler ) + { + sm_handlers.DeleteObject(handler); + return true; + } + else + return false; +} + +wxBitmapHandler *wxBitmapBase::FindHandler(const wxString& name) +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while ( node ) + { + wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); + if ( handler->GetName() == name ) + return handler; + node = node->GetNext(); + } + return NULL; +} + +wxBitmapHandler *wxBitmapBase::FindHandler(const wxString& extension, wxBitmapType bitmapType) +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while ( node ) + { + wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); + if ( handler->GetExtension() == extension && + (bitmapType == wxBITMAP_TYPE_ANY || handler->GetType() == bitmapType) ) + return handler; + node = node->GetNext(); + } + return NULL; +} + +wxBitmapHandler *wxBitmapBase::FindHandler(wxBitmapType bitmapType) +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while ( node ) + { + wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); + if (handler->GetType() == bitmapType) + return handler; + node = node->GetNext(); + } + return NULL; +} + +void wxBitmapBase::CleanUpHandlers() +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while ( node ) + { + wxBitmapHandler *handler = (wxBitmapHandler *)node->GetData(); + wxList::compatibility_iterator next = node->GetNext(); + delete handler; + sm_handlers.Erase(node); + node = next; + } +} + +bool wxBitmapHandlerBase::Create(wxBitmap*, const void*, long, int, int, int) +{ + return false; +} + +bool wxBitmapHandlerBase::LoadFile(wxBitmap*, const wxString&, long, int, int) +{ + return false; +} + +bool wxBitmapHandlerBase::SaveFile(const wxBitmap*, const wxString&, int, const wxPalette*) +{ + return false; +} + +class wxBitmapBaseModule: public wxModule +{ +DECLARE_DYNAMIC_CLASS(wxBitmapBaseModule) +public: + wxBitmapBaseModule() {} + bool OnInit() { wxBitmap::InitStandardHandlers(); return true; } + void OnExit() { wxBitmap::CleanUpHandlers(); } +}; + +IMPLEMENT_DYNAMIC_CLASS(wxBitmapBaseModule, wxModule) + +#endif // wxUSE_BITMAP_BASE + +// ---------------------------------------------------------------------------- +// wxBitmap common +// ---------------------------------------------------------------------------- + +#if !(defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXX11__)) + +wxBitmap::wxBitmap(const char* const* bits) +{ + wxCHECK2_MSG(bits != NULL, return, wxT("invalid bitmap data")); + +#if wxUSE_IMAGE && wxUSE_XPM + wxImage image(bits); + wxCHECK2_MSG(image.Ok(), return, wxT("invalid bitmap data")); + + *this = wxBitmap(image); +#else + wxFAIL_MSG(_T("creating bitmaps from XPMs not supported")); +#endif // wxUSE_IMAGE && wxUSE_XPM +} +#endif // !(defined(__WXGTK__) || defined(__WXMOTIF__) || defined(__WXX11__)) + +// ---------------------------------------------------------------------------- +// wxMaskBase +// ---------------------------------------------------------------------------- + +bool wxMaskBase::Create(const wxBitmap& bitmap, const wxColour& colour) +{ + FreeData(); + + return InitFromColour(bitmap, colour); +} + +#if wxUSE_PALETTE + +bool wxMaskBase::Create(const wxBitmap& bitmap, int paletteIndex) +{ + wxPalette *pal = bitmap.GetPalette(); + + wxCHECK_MSG( pal, false, + wxT("Cannot create mask from palette index of a bitmap without palette") ); + + unsigned char r,g,b; + pal->GetRGB(paletteIndex, &r, &g, &b); + + return Create(bitmap, wxColour(r, g, b)); +} + +#endif // wxUSE_PALETTE + +bool wxMaskBase::Create(const wxBitmap& bitmap) +{ + FreeData(); + + return InitFromMonoBitmap(bitmap); +} diff --git a/Source/3rd Party/wx/src/common/bookctrl.cpp b/Source/3rd Party/wx/src/common/bookctrl.cpp index a64fc9ead..ca6c2a590 100644 --- a/Source/3rd Party/wx/src/common/bookctrl.cpp +++ b/Source/3rd Party/wx/src/common/bookctrl.cpp @@ -1,497 +1,497 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/bookctrl.cpp -// Purpose: wxBookCtrlBase implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 19.08.03 -// RCS-ID: $Id: bookctrl.cpp 53783 2008-05-27 14:15:14Z SC $ -// Copyright: (c) 2003 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_BOOKCTRL - -#include "wx/imaglist.h" - -#include "wx/bookctrl.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// event table -// ---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxBookCtrlBase, wxControl) - -BEGIN_EVENT_TABLE(wxBookCtrlBase, wxControl) - EVT_SIZE(wxBookCtrlBase::OnSize) -#if wxUSE_HELP - EVT_HELP(wxID_ANY, wxBookCtrlBase::OnHelp) -#endif // wxUSE_HELP -END_EVENT_TABLE() - -// ---------------------------------------------------------------------------- -// constructors and destructors -// ---------------------------------------------------------------------------- - -void wxBookCtrlBase::Init() -{ - m_bookctrl = NULL; - m_imageList = NULL; - m_ownsImageList = false; - m_fitToCurrentPage = false; - -#if defined(__WXWINCE__) - m_internalBorder = 1; -#else - m_internalBorder = 5; -#endif - - m_controlMargin = 0; - m_controlSizer = NULL; -} - -bool -wxBookCtrlBase::Create(wxWindow *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - return wxControl::Create - ( - parent, - id, - pos, - size, - style, - wxDefaultValidator, - name - ); -} - -wxBookCtrlBase::~wxBookCtrlBase() -{ - if ( m_ownsImageList ) - { - // may be NULL, ok - delete m_imageList; - } -} - -// ---------------------------------------------------------------------------- -// image list -// ---------------------------------------------------------------------------- - -void wxBookCtrlBase::SetImageList(wxImageList *imageList) -{ - if ( m_ownsImageList ) - { - // may be NULL, ok - delete m_imageList; - - m_ownsImageList = false; - } - - m_imageList = imageList; -} - -void wxBookCtrlBase::AssignImageList(wxImageList* imageList) -{ - SetImageList(imageList); - - m_ownsImageList = true; -} - -// ---------------------------------------------------------------------------- -// geometry -// ---------------------------------------------------------------------------- - -void wxBookCtrlBase::DoInvalidateBestSize() -{ - // notice that it is not necessary to invalidate our own best size - // explicitly if we have m_bookctrl as it will already invalidate the best - // size of its parent when its own size is invalidated and its parent is - // this control - if ( m_bookctrl ) - m_bookctrl->InvalidateBestSize(); - else - wxControl::InvalidateBestSize(); -} - -void wxBookCtrlBase::SetPageSize(const wxSize& size) -{ - SetClientSize(CalcSizeFromPage(size)); -} - -wxSize wxBookCtrlBase::DoGetBestSize() const -{ - wxSize bestSize; - - // iterate over all pages, get the largest width and height - const size_t nCount = m_pages.size(); - for ( size_t nPage = 0; nPage < nCount; nPage++ ) - { - const wxWindow * const pPage = m_pages[nPage]; - if( pPage ) - { - wxSize childBestSize(pPage->GetBestSize()); - - if ( childBestSize.x > bestSize.x ) - bestSize.x = childBestSize.x; - - if ( childBestSize.y > bestSize.y ) - bestSize.y = childBestSize.y; - } - } - - if (m_fitToCurrentPage && GetCurrentPage()) - bestSize = GetCurrentPage()->GetBestSize(); - - // convert display area to window area, adding the size necessary for the - // tabs - wxSize best = CalcSizeFromPage(bestSize); - CacheBestSize(best); - return best; -} - -wxRect wxBookCtrlBase::GetPageRect() const -{ - const wxSize size = GetControllerSize(); - - wxPoint pt; - wxRect rectPage(pt, GetClientSize()); - - switch ( GetWindowStyle() & wxBK_ALIGN_MASK ) - { - default: - wxFAIL_MSG( _T("unexpected alignment") ); - // fall through - - case wxBK_TOP: - rectPage.y = size.y + GetInternalBorder(); - // fall through - - case wxBK_BOTTOM: - rectPage.height -= size.y + GetInternalBorder(); - if (rectPage.height < 0) - rectPage.height = 0; - break; - - case wxBK_LEFT: - rectPage.x = size.x + GetInternalBorder(); - // fall through - - case wxBK_RIGHT: - rectPage.width -= size.x + GetInternalBorder(); - if (rectPage.width < 0) - rectPage.width = 0; - break; - } - - return rectPage; -} - -// Lay out controls -void wxBookCtrlBase::DoSize() -{ - if ( !m_bookctrl ) - { - // we're not fully created yet or OnSize() should be hidden by derived class - return; - } - - if (GetSizer()) - Layout(); - else - { - // resize controller and the page area to fit inside our new size - const wxSize sizeClient( GetClientSize() ), - sizeBorder( m_bookctrl->GetSize() - m_bookctrl->GetClientSize() ), - sizeCtrl( GetControllerSize() ); - - m_bookctrl->SetClientSize( sizeCtrl.x - sizeBorder.x, sizeCtrl.y - sizeBorder.y ); - // if this changes the visibility of the scrollbars the best size changes, relayout in this case - wxSize sizeCtrl2 = GetControllerSize(); - if ( sizeCtrl != sizeCtrl2 ) - { - wxSize sizeBorder2 = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(); - m_bookctrl->SetClientSize( sizeCtrl2.x - sizeBorder2.x, sizeCtrl2.y - sizeBorder2.y ); - } - - const wxSize sizeNew = m_bookctrl->GetSize(); - wxPoint posCtrl; - switch ( GetWindowStyle() & wxBK_ALIGN_MASK ) - { - default: - wxFAIL_MSG( _T("unexpected alignment") ); - // fall through - - case wxBK_TOP: - case wxBK_LEFT: - // posCtrl is already ok - break; - - case wxBK_BOTTOM: - posCtrl.y = sizeClient.y - sizeNew.y; - break; - - case wxBK_RIGHT: - posCtrl.x = sizeClient.x - sizeNew.x; - break; - } - - if ( m_bookctrl->GetPosition() != posCtrl ) - m_bookctrl->Move(posCtrl); - } - - // resize all pages to fit the new control size - const wxRect pageRect = GetPageRect(); - const unsigned pagesCount = m_pages.Count(); - for ( unsigned int i = 0; i < pagesCount; ++i ) - { - wxWindow * const page = m_pages[i]; - if ( !page ) - { - wxASSERT_MSG( AllowNullPage(), - _T("Null page in a control that does not allow null pages?") ); - continue; - } - - page->SetSize(pageRect); - } -} - -void wxBookCtrlBase::OnSize(wxSizeEvent& event) -{ - event.Skip(); - - DoSize(); -} - -wxSize wxBookCtrlBase::GetControllerSize() const -{ - if(!m_bookctrl) - return wxSize(0,0); - - const wxSize sizeClient = GetClientSize(), - sizeBorder = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(), - sizeCtrl = m_bookctrl->GetBestSize() + sizeBorder; - - wxSize size; - - if ( IsVertical() ) - { - size.x = sizeClient.x; - size.y = sizeCtrl.y; - } - else // left/right aligned - { - size.x = sizeCtrl.x; - size.y = sizeClient.y; - } - - return size; -} - -// ---------------------------------------------------------------------------- -// miscellaneous stuff -// ---------------------------------------------------------------------------- - -#if wxUSE_HELP - -void wxBookCtrlBase::OnHelp(wxHelpEvent& event) -{ - // determine where does this even originate from to avoid redirecting it - // back to the page which generated it (resulting in an infinite loop) - - // notice that we have to check in the hard(er) way instead of just testing - // if the event object == this because the book control can have other - // subcontrols inside it (e.g. wxSpinButton in case of a notebook in wxUniv) - wxWindow *source = wxStaticCast(event.GetEventObject(), wxWindow); - while ( source && source != this && source->GetParent() != this ) - { - source = source->GetParent(); - } - - if ( source && m_pages.Index(source) == wxNOT_FOUND ) - { - // this event is for the book control itself, redirect it to the - // corresponding page - wxWindow *page = NULL; - - if ( event.GetOrigin() == wxHelpEvent::Origin_HelpButton ) - { - // show help for the page under the mouse - const int pagePos = HitTest(ScreenToClient(event.GetPosition())); - - if ( pagePos != wxNOT_FOUND) - { - page = GetPage((size_t)pagePos); - } - } - else // event from keyboard or unknown source - { - // otherwise show the current page help - page = GetCurrentPage(); - } - - if ( page ) - { - // change event object to the page to avoid infinite recursion if - // we get this event ourselves if the page doesn't handle it - event.SetEventObject(page); - - if ( page->GetEventHandler()->ProcessEvent(event) ) - { - // don't call event.Skip() - return; - } - } - } - //else: event coming from one of our pages already - - event.Skip(); -} - -#endif // wxUSE_HELP - -// ---------------------------------------------------------------------------- -// pages management -// ---------------------------------------------------------------------------- - -bool -wxBookCtrlBase::InsertPage(size_t nPage, - wxWindow *page, - const wxString& WXUNUSED(text), - bool WXUNUSED(bSelect), - int WXUNUSED(imageId)) -{ - wxCHECK_MSG( page || AllowNullPage(), false, - _T("NULL page in wxBookCtrlBase::InsertPage()") ); - wxCHECK_MSG( nPage <= m_pages.size(), false, - _T("invalid page index in wxBookCtrlBase::InsertPage()") ); - - m_pages.Insert(page, nPage); - if ( page ) - page->SetSize(GetPageRect()); - - DoInvalidateBestSize(); - - return true; -} - -bool wxBookCtrlBase::DeletePage(size_t nPage) -{ - wxWindow *page = DoRemovePage(nPage); - if ( !(page || AllowNullPage()) ) - return false; - - // delete NULL is harmless - delete page; - - return true; -} - -wxWindow *wxBookCtrlBase::DoRemovePage(size_t nPage) -{ - wxCHECK_MSG( nPage < m_pages.size(), NULL, - _T("invalid page index in wxBookCtrlBase::DoRemovePage()") ); - - wxWindow *pageRemoved = m_pages[nPage]; - m_pages.RemoveAt(nPage); - DoInvalidateBestSize(); - - return pageRemoved; -} - -int wxBookCtrlBase::GetNextPage(bool forward) const -{ - int nPage; - - int nMax = GetPageCount(); - if ( nMax-- ) // decrement it to get the last valid index - { - int nSel = GetSelection(); - - // change selection wrapping if it becomes invalid - nPage = forward ? nSel == nMax ? 0 - : nSel + 1 - : nSel == 0 ? nMax - : nSel - 1; - } - else // notebook is empty, no next page - { - nPage = wxNOT_FOUND; - } - - return nPage; -} - -int wxBookCtrlBase::DoSetSelection(size_t n, int flags) -{ - wxCHECK_MSG( n < GetPageCount(), wxNOT_FOUND, - wxT("invalid page index in wxBookCtrlBase::DoSetSelection()") ); - - const int oldSel = GetSelection(); - - if ( n != (size_t)oldSel ) - { - wxBookCtrlBaseEvent *event = CreatePageChangingEvent(); - bool allowed = false; - - if ( flags & SetSelection_SendEvent ) - { - event->SetSelection(n); - event->SetOldSelection(oldSel); - event->SetEventObject(this); - - allowed = !GetEventHandler()->ProcessEvent(*event) || event->IsAllowed(); - } - - if ( !(flags & SetSelection_SendEvent) || allowed) - { - if ( oldSel != wxNOT_FOUND ) - m_pages[oldSel]->Hide(); - - wxWindow *page = m_pages[n]; - page->SetSize(GetPageRect()); - page->Show(); - - // change selection now to ignore the selection change event - UpdateSelectedPage(n); - - if ( flags & SetSelection_SendEvent ) - { - // program allows the page change - MakeChangedEvent(*event); - (void)GetEventHandler()->ProcessEvent(*event); - } - } - - delete event; - } - - return oldSel; -} - - -#endif // wxUSE_BOOKCTRL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/bookctrl.cpp +// Purpose: wxBookCtrlBase implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 19.08.03 +// RCS-ID: $Id: bookctrl.cpp 53783 2008-05-27 14:15:14Z SC $ +// Copyright: (c) 2003 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_BOOKCTRL + +#include "wx/imaglist.h" + +#include "wx/bookctrl.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxBookCtrlBase, wxControl) + +BEGIN_EVENT_TABLE(wxBookCtrlBase, wxControl) + EVT_SIZE(wxBookCtrlBase::OnSize) +#if wxUSE_HELP + EVT_HELP(wxID_ANY, wxBookCtrlBase::OnHelp) +#endif // wxUSE_HELP +END_EVENT_TABLE() + +// ---------------------------------------------------------------------------- +// constructors and destructors +// ---------------------------------------------------------------------------- + +void wxBookCtrlBase::Init() +{ + m_bookctrl = NULL; + m_imageList = NULL; + m_ownsImageList = false; + m_fitToCurrentPage = false; + +#if defined(__WXWINCE__) + m_internalBorder = 1; +#else + m_internalBorder = 5; +#endif + + m_controlMargin = 0; + m_controlSizer = NULL; +} + +bool +wxBookCtrlBase::Create(wxWindow *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + return wxControl::Create + ( + parent, + id, + pos, + size, + style, + wxDefaultValidator, + name + ); +} + +wxBookCtrlBase::~wxBookCtrlBase() +{ + if ( m_ownsImageList ) + { + // may be NULL, ok + delete m_imageList; + } +} + +// ---------------------------------------------------------------------------- +// image list +// ---------------------------------------------------------------------------- + +void wxBookCtrlBase::SetImageList(wxImageList *imageList) +{ + if ( m_ownsImageList ) + { + // may be NULL, ok + delete m_imageList; + + m_ownsImageList = false; + } + + m_imageList = imageList; +} + +void wxBookCtrlBase::AssignImageList(wxImageList* imageList) +{ + SetImageList(imageList); + + m_ownsImageList = true; +} + +// ---------------------------------------------------------------------------- +// geometry +// ---------------------------------------------------------------------------- + +void wxBookCtrlBase::DoInvalidateBestSize() +{ + // notice that it is not necessary to invalidate our own best size + // explicitly if we have m_bookctrl as it will already invalidate the best + // size of its parent when its own size is invalidated and its parent is + // this control + if ( m_bookctrl ) + m_bookctrl->InvalidateBestSize(); + else + wxControl::InvalidateBestSize(); +} + +void wxBookCtrlBase::SetPageSize(const wxSize& size) +{ + SetClientSize(CalcSizeFromPage(size)); +} + +wxSize wxBookCtrlBase::DoGetBestSize() const +{ + wxSize bestSize; + + // iterate over all pages, get the largest width and height + const size_t nCount = m_pages.size(); + for ( size_t nPage = 0; nPage < nCount; nPage++ ) + { + const wxWindow * const pPage = m_pages[nPage]; + if( pPage ) + { + wxSize childBestSize(pPage->GetBestSize()); + + if ( childBestSize.x > bestSize.x ) + bestSize.x = childBestSize.x; + + if ( childBestSize.y > bestSize.y ) + bestSize.y = childBestSize.y; + } + } + + if (m_fitToCurrentPage && GetCurrentPage()) + bestSize = GetCurrentPage()->GetBestSize(); + + // convert display area to window area, adding the size necessary for the + // tabs + wxSize best = CalcSizeFromPage(bestSize); + CacheBestSize(best); + return best; +} + +wxRect wxBookCtrlBase::GetPageRect() const +{ + const wxSize size = GetControllerSize(); + + wxPoint pt; + wxRect rectPage(pt, GetClientSize()); + + switch ( GetWindowStyle() & wxBK_ALIGN_MASK ) + { + default: + wxFAIL_MSG( _T("unexpected alignment") ); + // fall through + + case wxBK_TOP: + rectPage.y = size.y + GetInternalBorder(); + // fall through + + case wxBK_BOTTOM: + rectPage.height -= size.y + GetInternalBorder(); + if (rectPage.height < 0) + rectPage.height = 0; + break; + + case wxBK_LEFT: + rectPage.x = size.x + GetInternalBorder(); + // fall through + + case wxBK_RIGHT: + rectPage.width -= size.x + GetInternalBorder(); + if (rectPage.width < 0) + rectPage.width = 0; + break; + } + + return rectPage; +} + +// Lay out controls +void wxBookCtrlBase::DoSize() +{ + if ( !m_bookctrl ) + { + // we're not fully created yet or OnSize() should be hidden by derived class + return; + } + + if (GetSizer()) + Layout(); + else + { + // resize controller and the page area to fit inside our new size + const wxSize sizeClient( GetClientSize() ), + sizeBorder( m_bookctrl->GetSize() - m_bookctrl->GetClientSize() ), + sizeCtrl( GetControllerSize() ); + + m_bookctrl->SetClientSize( sizeCtrl.x - sizeBorder.x, sizeCtrl.y - sizeBorder.y ); + // if this changes the visibility of the scrollbars the best size changes, relayout in this case + wxSize sizeCtrl2 = GetControllerSize(); + if ( sizeCtrl != sizeCtrl2 ) + { + wxSize sizeBorder2 = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(); + m_bookctrl->SetClientSize( sizeCtrl2.x - sizeBorder2.x, sizeCtrl2.y - sizeBorder2.y ); + } + + const wxSize sizeNew = m_bookctrl->GetSize(); + wxPoint posCtrl; + switch ( GetWindowStyle() & wxBK_ALIGN_MASK ) + { + default: + wxFAIL_MSG( _T("unexpected alignment") ); + // fall through + + case wxBK_TOP: + case wxBK_LEFT: + // posCtrl is already ok + break; + + case wxBK_BOTTOM: + posCtrl.y = sizeClient.y - sizeNew.y; + break; + + case wxBK_RIGHT: + posCtrl.x = sizeClient.x - sizeNew.x; + break; + } + + if ( m_bookctrl->GetPosition() != posCtrl ) + m_bookctrl->Move(posCtrl); + } + + // resize all pages to fit the new control size + const wxRect pageRect = GetPageRect(); + const unsigned pagesCount = m_pages.Count(); + for ( unsigned int i = 0; i < pagesCount; ++i ) + { + wxWindow * const page = m_pages[i]; + if ( !page ) + { + wxASSERT_MSG( AllowNullPage(), + _T("Null page in a control that does not allow null pages?") ); + continue; + } + + page->SetSize(pageRect); + } +} + +void wxBookCtrlBase::OnSize(wxSizeEvent& event) +{ + event.Skip(); + + DoSize(); +} + +wxSize wxBookCtrlBase::GetControllerSize() const +{ + if(!m_bookctrl) + return wxSize(0,0); + + const wxSize sizeClient = GetClientSize(), + sizeBorder = m_bookctrl->GetSize() - m_bookctrl->GetClientSize(), + sizeCtrl = m_bookctrl->GetBestSize() + sizeBorder; + + wxSize size; + + if ( IsVertical() ) + { + size.x = sizeClient.x; + size.y = sizeCtrl.y; + } + else // left/right aligned + { + size.x = sizeCtrl.x; + size.y = sizeClient.y; + } + + return size; +} + +// ---------------------------------------------------------------------------- +// miscellaneous stuff +// ---------------------------------------------------------------------------- + +#if wxUSE_HELP + +void wxBookCtrlBase::OnHelp(wxHelpEvent& event) +{ + // determine where does this even originate from to avoid redirecting it + // back to the page which generated it (resulting in an infinite loop) + + // notice that we have to check in the hard(er) way instead of just testing + // if the event object == this because the book control can have other + // subcontrols inside it (e.g. wxSpinButton in case of a notebook in wxUniv) + wxWindow *source = wxStaticCast(event.GetEventObject(), wxWindow); + while ( source && source != this && source->GetParent() != this ) + { + source = source->GetParent(); + } + + if ( source && m_pages.Index(source) == wxNOT_FOUND ) + { + // this event is for the book control itself, redirect it to the + // corresponding page + wxWindow *page = NULL; + + if ( event.GetOrigin() == wxHelpEvent::Origin_HelpButton ) + { + // show help for the page under the mouse + const int pagePos = HitTest(ScreenToClient(event.GetPosition())); + + if ( pagePos != wxNOT_FOUND) + { + page = GetPage((size_t)pagePos); + } + } + else // event from keyboard or unknown source + { + // otherwise show the current page help + page = GetCurrentPage(); + } + + if ( page ) + { + // change event object to the page to avoid infinite recursion if + // we get this event ourselves if the page doesn't handle it + event.SetEventObject(page); + + if ( page->GetEventHandler()->ProcessEvent(event) ) + { + // don't call event.Skip() + return; + } + } + } + //else: event coming from one of our pages already + + event.Skip(); +} + +#endif // wxUSE_HELP + +// ---------------------------------------------------------------------------- +// pages management +// ---------------------------------------------------------------------------- + +bool +wxBookCtrlBase::InsertPage(size_t nPage, + wxWindow *page, + const wxString& WXUNUSED(text), + bool WXUNUSED(bSelect), + int WXUNUSED(imageId)) +{ + wxCHECK_MSG( page || AllowNullPage(), false, + _T("NULL page in wxBookCtrlBase::InsertPage()") ); + wxCHECK_MSG( nPage <= m_pages.size(), false, + _T("invalid page index in wxBookCtrlBase::InsertPage()") ); + + m_pages.Insert(page, nPage); + if ( page ) + page->SetSize(GetPageRect()); + + DoInvalidateBestSize(); + + return true; +} + +bool wxBookCtrlBase::DeletePage(size_t nPage) +{ + wxWindow *page = DoRemovePage(nPage); + if ( !(page || AllowNullPage()) ) + return false; + + // delete NULL is harmless + delete page; + + return true; +} + +wxWindow *wxBookCtrlBase::DoRemovePage(size_t nPage) +{ + wxCHECK_MSG( nPage < m_pages.size(), NULL, + _T("invalid page index in wxBookCtrlBase::DoRemovePage()") ); + + wxWindow *pageRemoved = m_pages[nPage]; + m_pages.RemoveAt(nPage); + DoInvalidateBestSize(); + + return pageRemoved; +} + +int wxBookCtrlBase::GetNextPage(bool forward) const +{ + int nPage; + + int nMax = GetPageCount(); + if ( nMax-- ) // decrement it to get the last valid index + { + int nSel = GetSelection(); + + // change selection wrapping if it becomes invalid + nPage = forward ? nSel == nMax ? 0 + : nSel + 1 + : nSel == 0 ? nMax + : nSel - 1; + } + else // notebook is empty, no next page + { + nPage = wxNOT_FOUND; + } + + return nPage; +} + +int wxBookCtrlBase::DoSetSelection(size_t n, int flags) +{ + wxCHECK_MSG( n < GetPageCount(), wxNOT_FOUND, + wxT("invalid page index in wxBookCtrlBase::DoSetSelection()") ); + + const int oldSel = GetSelection(); + + if ( n != (size_t)oldSel ) + { + wxBookCtrlBaseEvent *event = CreatePageChangingEvent(); + bool allowed = false; + + if ( flags & SetSelection_SendEvent ) + { + event->SetSelection(n); + event->SetOldSelection(oldSel); + event->SetEventObject(this); + + allowed = !GetEventHandler()->ProcessEvent(*event) || event->IsAllowed(); + } + + if ( !(flags & SetSelection_SendEvent) || allowed) + { + if ( oldSel != wxNOT_FOUND ) + m_pages[oldSel]->Hide(); + + wxWindow *page = m_pages[n]; + page->SetSize(GetPageRect()); + page->Show(); + + // change selection now to ignore the selection change event + UpdateSelectedPage(n); + + if ( flags & SetSelection_SendEvent ) + { + // program allows the page change + MakeChangedEvent(*event); + (void)GetEventHandler()->ProcessEvent(*event); + } + } + + delete event; + } + + return oldSel; +} + + +#endif // wxUSE_BOOKCTRL diff --git a/Source/3rd Party/wx/src/common/choiccmn.cpp b/Source/3rd Party/wx/src/common/choiccmn.cpp index 94481b914..7febe79e6 100644 --- a/Source/3rd Party/wx/src/common/choiccmn.cpp +++ b/Source/3rd Party/wx/src/common/choiccmn.cpp @@ -1,55 +1,55 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/choiccmn.cpp -// Purpose: common (to all ports) wxChoice functions -// Author: Vadim Zeitlin -// Modified by: -// Created: 26.07.99 -// RCS-ID: $Id: choiccmn.cpp 39470 2006-05-30 07:34:30Z ABX $ -// Copyright: (c) 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_CHOICE - -#include "wx/choice.h" - -#ifndef WX_PRECOMP -#endif - -const wxChar wxChoiceNameStr[] = wxT("choice"); - -// ============================================================================ -// implementation -// ============================================================================ - -wxChoiceBase::~wxChoiceBase() -{ - // this destructor is required for Darwin -} - -// ---------------------------------------------------------------------------- -// misc -// ---------------------------------------------------------------------------- - -void wxChoiceBase::Command(wxCommandEvent& event) -{ - SetSelection(event.GetInt()); - (void)ProcessEvent(event); -} - -#endif // wxUSE_CHOICE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/choiccmn.cpp +// Purpose: common (to all ports) wxChoice functions +// Author: Vadim Zeitlin +// Modified by: +// Created: 26.07.99 +// RCS-ID: $Id: choiccmn.cpp 39470 2006-05-30 07:34:30Z ABX $ +// Copyright: (c) 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_CHOICE + +#include "wx/choice.h" + +#ifndef WX_PRECOMP +#endif + +const wxChar wxChoiceNameStr[] = wxT("choice"); + +// ============================================================================ +// implementation +// ============================================================================ + +wxChoiceBase::~wxChoiceBase() +{ + // this destructor is required for Darwin +} + +// ---------------------------------------------------------------------------- +// misc +// ---------------------------------------------------------------------------- + +void wxChoiceBase::Command(wxCommandEvent& event) +{ + SetSelection(event.GetInt()); + (void)ProcessEvent(event); +} + +#endif // wxUSE_CHOICE diff --git a/Source/3rd Party/wx/src/common/clipcmn.cpp b/Source/3rd Party/wx/src/common/clipcmn.cpp index d4912cf8e..2421c48fe 100644 --- a/Source/3rd Party/wx/src/common/clipcmn.cpp +++ b/Source/3rd Party/wx/src/common/clipcmn.cpp @@ -1,63 +1,63 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/clipcmn.cpp -// Purpose: common (to all ports) wxClipboard functions -// Author: Robert Roebling -// Modified by: -// Created: 28.06.99 -// RCS-ID: $Id: clipcmn.cpp 40943 2006-08-31 19:31:43Z ABX $ -// Copyright: (c) Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_CLIPBOARD - -#include "wx/clipbrd.h" - -#ifndef WX_PRECOMP - #include "wx/module.h" -#endif - -static wxClipboard *gs_clipboard = NULL; - -/*static*/ wxClipboard *wxClipboardBase::Get() -{ - if ( !gs_clipboard ) - { - gs_clipboard = new wxClipboard; - } - return gs_clipboard; -} - -// ---------------------------------------------------------------------------- -// wxClipboardModule: module responsible for destroying the global clipboard -// object -// ---------------------------------------------------------------------------- - -class wxClipboardModule : public wxModule -{ -public: - bool OnInit() { return true; } - void OnExit() { wxDELETE(gs_clipboard); } - -private: - DECLARE_DYNAMIC_CLASS(wxClipboardModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule, wxModule) - -#endif // wxUSE_CLIPBOARD +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/clipcmn.cpp +// Purpose: common (to all ports) wxClipboard functions +// Author: Robert Roebling +// Modified by: +// Created: 28.06.99 +// RCS-ID: $Id: clipcmn.cpp 40943 2006-08-31 19:31:43Z ABX $ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_CLIPBOARD + +#include "wx/clipbrd.h" + +#ifndef WX_PRECOMP + #include "wx/module.h" +#endif + +static wxClipboard *gs_clipboard = NULL; + +/*static*/ wxClipboard *wxClipboardBase::Get() +{ + if ( !gs_clipboard ) + { + gs_clipboard = new wxClipboard; + } + return gs_clipboard; +} + +// ---------------------------------------------------------------------------- +// wxClipboardModule: module responsible for destroying the global clipboard +// object +// ---------------------------------------------------------------------------- + +class wxClipboardModule : public wxModule +{ +public: + bool OnInit() { return true; } + void OnExit() { wxDELETE(gs_clipboard); } + +private: + DECLARE_DYNAMIC_CLASS(wxClipboardModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxClipboardModule, wxModule) + +#endif // wxUSE_CLIPBOARD diff --git a/Source/3rd Party/wx/src/common/clntdata.cpp b/Source/3rd Party/wx/src/common/clntdata.cpp index f097259f8..d226f15b3 100644 --- a/Source/3rd Party/wx/src/common/clntdata.cpp +++ b/Source/3rd Party/wx/src/common/clntdata.cpp @@ -1,83 +1,83 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: common/clntdata.cpp -// Purpose: A mixin class for holding a wxClientData or void pointer -// Author: Robin Dunn -// Modified by: -// Created: 9-Oct-2001 -// RCS-ID: $Id: clntdata.cpp 35650 2005-09-23 12:56:45Z MR $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/clntdata.h" - - -// ---------------------------------------------------------------------------- - - -wxClientDataContainer::wxClientDataContainer() -{ - // no client data (yet) - m_clientData = NULL; - m_clientDataType = wxClientData_None; -} - -wxClientDataContainer::~wxClientDataContainer() -{ - // we only delete object data, not untyped - if ( m_clientDataType == wxClientData_Object ) - delete m_clientObject; -} - -void wxClientDataContainer::DoSetClientObject( wxClientData *data ) -{ - wxASSERT_MSG( m_clientDataType != wxClientData_Void, - wxT("can't have both object and void client data") ); - - if ( m_clientObject ) - delete m_clientObject; - - m_clientObject = data; - m_clientDataType = wxClientData_Object; -} - -wxClientData *wxClientDataContainer::DoGetClientObject() const -{ - // it's not an error to call GetClientObject() on a window which doesn't - // have client data at all - NULL will be returned - wxASSERT_MSG( m_clientDataType != wxClientData_Void, - wxT("this window doesn't have object client data") ); - - return m_clientObject; -} - -void wxClientDataContainer::DoSetClientData( void *data ) -{ - wxASSERT_MSG( m_clientDataType != wxClientData_Object, - wxT("can't have both object and void client data") ); - - m_clientData = data; - m_clientDataType = wxClientData_Void; -} - -void *wxClientDataContainer::DoGetClientData() const -{ - // it's not an error to call GetClientData() on a window which doesn't have - // client data at all - NULL will be returned - wxASSERT_MSG( m_clientDataType != wxClientData_Object, - wxT("this window doesn't have void client data") ); - - return m_clientData; -} - - -// ---------------------------------------------------------------------------- - - +///////////////////////////////////////////////////////////////////////////// +// Name: common/clntdata.cpp +// Purpose: A mixin class for holding a wxClientData or void pointer +// Author: Robin Dunn +// Modified by: +// Created: 9-Oct-2001 +// RCS-ID: $Id: clntdata.cpp 35650 2005-09-23 12:56:45Z MR $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/clntdata.h" + + +// ---------------------------------------------------------------------------- + + +wxClientDataContainer::wxClientDataContainer() +{ + // no client data (yet) + m_clientData = NULL; + m_clientDataType = wxClientData_None; +} + +wxClientDataContainer::~wxClientDataContainer() +{ + // we only delete object data, not untyped + if ( m_clientDataType == wxClientData_Object ) + delete m_clientObject; +} + +void wxClientDataContainer::DoSetClientObject( wxClientData *data ) +{ + wxASSERT_MSG( m_clientDataType != wxClientData_Void, + wxT("can't have both object and void client data") ); + + if ( m_clientObject ) + delete m_clientObject; + + m_clientObject = data; + m_clientDataType = wxClientData_Object; +} + +wxClientData *wxClientDataContainer::DoGetClientObject() const +{ + // it's not an error to call GetClientObject() on a window which doesn't + // have client data at all - NULL will be returned + wxASSERT_MSG( m_clientDataType != wxClientData_Void, + wxT("this window doesn't have object client data") ); + + return m_clientObject; +} + +void wxClientDataContainer::DoSetClientData( void *data ) +{ + wxASSERT_MSG( m_clientDataType != wxClientData_Object, + wxT("can't have both object and void client data") ); + + m_clientData = data; + m_clientDataType = wxClientData_Void; +} + +void *wxClientDataContainer::DoGetClientData() const +{ + // it's not an error to call GetClientData() on a window which doesn't have + // client data at all - NULL will be returned + wxASSERT_MSG( m_clientDataType != wxClientData_Object, + wxT("this window doesn't have void client data") ); + + return m_clientData; +} + + +// ---------------------------------------------------------------------------- + + diff --git a/Source/3rd Party/wx/src/common/clrpickercmn.cpp b/Source/3rd Party/wx/src/common/clrpickercmn.cpp index b62f6fc2b..8e21d7f6e 100644 --- a/Source/3rd Party/wx/src/common/clrpickercmn.cpp +++ b/Source/3rd Party/wx/src/common/clrpickercmn.cpp @@ -1,149 +1,149 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/clrpickercmn.cpp -// Purpose: wxColourPickerCtrl class implementation -// Author: Francesco Montorsi (readapted code written by Vadim Zeitlin) -// Modified by: -// Created: 15/04/2006 -// RCS-ID: $Id: clrpickercmn.cpp 42219 2006-10-21 19:53:05Z PC $ -// Copyright: (c) Vadim Zeitlin, Francesco Montorsi -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_COLOURPICKERCTRL - -#include "wx/clrpicker.h" - -#ifndef WX_PRECOMP - #include "wx/textctrl.h" -#endif - -const wxChar wxColourPickerCtrlNameStr[] = wxT("colourpicker"); -const wxChar wxColourPickerWidgetNameStr[] = wxT("colourpickerwidget"); - -// ============================================================================ -// implementation -// ============================================================================ - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_COLOURPICKER_CHANGED) -IMPLEMENT_DYNAMIC_CLASS(wxColourPickerCtrl, wxPickerBase) -IMPLEMENT_DYNAMIC_CLASS(wxColourPickerEvent, wxEvent) - -// ---------------------------------------------------------------------------- -// wxColourPickerCtrl -// ---------------------------------------------------------------------------- - -#define M_PICKER ((wxColourPickerWidget*)m_picker) - -bool wxColourPickerCtrl::Create( wxWindow *parent, wxWindowID id, - const wxColour &col, - const wxPoint &pos, const wxSize &size, - long style, const wxValidator& validator, - const wxString &name ) -{ - if (!wxPickerBase::CreateBase(parent, id, col.GetAsString(), pos, size, - style, validator, name)) - return false; - - // we are not interested to the ID of our picker as we connect - // to its "changed" event dynamically... - m_picker = new wxColourPickerWidget(this, wxID_ANY, col, - wxDefaultPosition, wxDefaultSize, - GetPickerStyle(style)); - - // complete sizer creation - wxPickerBase::PostCreation(); - - m_picker->Connect(wxEVT_COMMAND_COLOURPICKER_CHANGED, - wxColourPickerEventHandler(wxColourPickerCtrl::OnColourChange), - NULL, this); - - return true; -} - -void wxColourPickerCtrl::SetColour(const wxColour &col) -{ - M_PICKER->SetColour(col); - UpdateTextCtrlFromPicker(); -} - -bool wxColourPickerCtrl::SetColour(const wxString &text) -{ - wxColour col(text); // smart wxString->wxColour conversion - if ( !col.Ok() ) - return false; - M_PICKER->SetColour(col); - UpdateTextCtrlFromPicker(); - - return true; -} - -void wxColourPickerCtrl::UpdatePickerFromTextCtrl() -{ - wxASSERT(m_text); - - if (m_bIgnoreNextTextCtrlUpdate) - { - // ignore this update - m_bIgnoreNextTextCtrlUpdate = false; - return; - } - - // wxString -> wxColour conversion - wxColour col(m_text->GetValue()); - if ( !col.Ok() ) - return; // invalid user input - - if (M_PICKER->GetColour() != col) - { - M_PICKER->SetColour(col); - - // fire an event - wxColourPickerEvent event(this, GetId(), col); - GetEventHandler()->ProcessEvent(event); - } -} - -void wxColourPickerCtrl::UpdateTextCtrlFromPicker() -{ - if (!m_text) - return; // no textctrl to update - - // NOTE: this SetValue() will generate an unwanted wxEVT_COMMAND_TEXT_UPDATED - // which will trigger a unneeded UpdateFromTextCtrl(); thus before using - // SetValue() we set the m_bIgnoreNextTextCtrlUpdate flag... - m_bIgnoreNextTextCtrlUpdate = true; - m_text->SetValue(M_PICKER->GetColour().GetAsString()); -} - - - -// ---------------------------------------------------------------------------- -// wxColourPickerCtrl - event handlers -// ---------------------------------------------------------------------------- - -void wxColourPickerCtrl::OnColourChange(wxColourPickerEvent &ev) -{ - UpdateTextCtrlFromPicker(); - - // the wxColourPickerWidget sent us a colour-change notification. - // forward this event to our parent - wxColourPickerEvent event(this, GetId(), ev.GetColour()); - GetEventHandler()->ProcessEvent(event); -} - -#endif // wxUSE_COLOURPICKERCTRL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/clrpickercmn.cpp +// Purpose: wxColourPickerCtrl class implementation +// Author: Francesco Montorsi (readapted code written by Vadim Zeitlin) +// Modified by: +// Created: 15/04/2006 +// RCS-ID: $Id: clrpickercmn.cpp 42219 2006-10-21 19:53:05Z PC $ +// Copyright: (c) Vadim Zeitlin, Francesco Montorsi +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_COLOURPICKERCTRL + +#include "wx/clrpicker.h" + +#ifndef WX_PRECOMP + #include "wx/textctrl.h" +#endif + +const wxChar wxColourPickerCtrlNameStr[] = wxT("colourpicker"); +const wxChar wxColourPickerWidgetNameStr[] = wxT("colourpickerwidget"); + +// ============================================================================ +// implementation +// ============================================================================ + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_COLOURPICKER_CHANGED) +IMPLEMENT_DYNAMIC_CLASS(wxColourPickerCtrl, wxPickerBase) +IMPLEMENT_DYNAMIC_CLASS(wxColourPickerEvent, wxEvent) + +// ---------------------------------------------------------------------------- +// wxColourPickerCtrl +// ---------------------------------------------------------------------------- + +#define M_PICKER ((wxColourPickerWidget*)m_picker) + +bool wxColourPickerCtrl::Create( wxWindow *parent, wxWindowID id, + const wxColour &col, + const wxPoint &pos, const wxSize &size, + long style, const wxValidator& validator, + const wxString &name ) +{ + if (!wxPickerBase::CreateBase(parent, id, col.GetAsString(), pos, size, + style, validator, name)) + return false; + + // we are not interested to the ID of our picker as we connect + // to its "changed" event dynamically... + m_picker = new wxColourPickerWidget(this, wxID_ANY, col, + wxDefaultPosition, wxDefaultSize, + GetPickerStyle(style)); + + // complete sizer creation + wxPickerBase::PostCreation(); + + m_picker->Connect(wxEVT_COMMAND_COLOURPICKER_CHANGED, + wxColourPickerEventHandler(wxColourPickerCtrl::OnColourChange), + NULL, this); + + return true; +} + +void wxColourPickerCtrl::SetColour(const wxColour &col) +{ + M_PICKER->SetColour(col); + UpdateTextCtrlFromPicker(); +} + +bool wxColourPickerCtrl::SetColour(const wxString &text) +{ + wxColour col(text); // smart wxString->wxColour conversion + if ( !col.Ok() ) + return false; + M_PICKER->SetColour(col); + UpdateTextCtrlFromPicker(); + + return true; +} + +void wxColourPickerCtrl::UpdatePickerFromTextCtrl() +{ + wxASSERT(m_text); + + if (m_bIgnoreNextTextCtrlUpdate) + { + // ignore this update + m_bIgnoreNextTextCtrlUpdate = false; + return; + } + + // wxString -> wxColour conversion + wxColour col(m_text->GetValue()); + if ( !col.Ok() ) + return; // invalid user input + + if (M_PICKER->GetColour() != col) + { + M_PICKER->SetColour(col); + + // fire an event + wxColourPickerEvent event(this, GetId(), col); + GetEventHandler()->ProcessEvent(event); + } +} + +void wxColourPickerCtrl::UpdateTextCtrlFromPicker() +{ + if (!m_text) + return; // no textctrl to update + + // NOTE: this SetValue() will generate an unwanted wxEVT_COMMAND_TEXT_UPDATED + // which will trigger a unneeded UpdateFromTextCtrl(); thus before using + // SetValue() we set the m_bIgnoreNextTextCtrlUpdate flag... + m_bIgnoreNextTextCtrlUpdate = true; + m_text->SetValue(M_PICKER->GetColour().GetAsString()); +} + + + +// ---------------------------------------------------------------------------- +// wxColourPickerCtrl - event handlers +// ---------------------------------------------------------------------------- + +void wxColourPickerCtrl::OnColourChange(wxColourPickerEvent &ev) +{ + UpdateTextCtrlFromPicker(); + + // the wxColourPickerWidget sent us a colour-change notification. + // forward this event to our parent + wxColourPickerEvent event(this, GetId(), ev.GetColour()); + GetEventHandler()->ProcessEvent(event); +} + +#endif // wxUSE_COLOURPICKERCTRL diff --git a/Source/3rd Party/wx/src/common/cmdline.cpp b/Source/3rd Party/wx/src/common/cmdline.cpp index f0022b0ac..c7b135d0c 100644 --- a/Source/3rd Party/wx/src/common/cmdline.cpp +++ b/Source/3rd Party/wx/src/common/cmdline.cpp @@ -1,1246 +1,1246 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/cmdline.cpp -// Purpose: wxCmdLineParser implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 05.01.00 -// RCS-ID: $Id: cmdline.cpp 66920 2011-02-16 22:00:30Z JS $ -// Copyright: (c) 2000 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/dynarray.h" - #include "wx/string.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/app.h" -#endif //WX_PRECOMP - -#include "wx/cmdline.h" - -#if wxUSE_CMDLINE_PARSER - -#include - -#include "wx/datetime.h" -#include "wx/msgout.h" -#include "wx/filename.h" - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -static wxString GetTypeName(wxCmdLineParamType type); - -static wxString GetOptionName(const wxChar *p, const wxChar *allowedChars); - -static wxString GetShortOptionName(const wxChar *p); - -static wxString GetLongOptionName(const wxChar *p); - -// ---------------------------------------------------------------------------- -// private structs -// ---------------------------------------------------------------------------- - -// an internal representation of an option -struct wxCmdLineOption -{ - wxCmdLineOption(wxCmdLineEntryType k, - const wxString& shrt, - const wxString& lng, - const wxString& desc, - wxCmdLineParamType typ, - int fl) - { - wxASSERT_MSG( !shrt.empty() || !lng.empty(), - _T("option should have at least one name") ); - - wxASSERT_MSG - ( - GetShortOptionName(shrt).Len() == shrt.Len(), - wxT("Short option contains invalid characters") - ); - - wxASSERT_MSG - ( - GetLongOptionName(lng).Len() == lng.Len(), - wxT("Long option contains invalid characters") - ); - - - kind = k; - - shortName = shrt; - longName = lng; - description = desc; - - type = typ; - flags = fl; - - m_hasVal = false; - } - - // can't use union easily here, so just store all possible data fields, we - // don't waste much (might still use union later if the number of supported - // types increases, so always use the accessor functions and don't access - // the fields directly!) - - void Check(wxCmdLineParamType WXUNUSED_UNLESS_DEBUG(typ)) const - { - wxASSERT_MSG( type == typ, _T("type mismatch in wxCmdLineOption") ); - } - - long GetLongVal() const - { Check(wxCMD_LINE_VAL_NUMBER); return m_longVal; } - const wxString& GetStrVal() const - { Check(wxCMD_LINE_VAL_STRING); return m_strVal; } -#if wxUSE_DATETIME - const wxDateTime& GetDateVal() const - { Check(wxCMD_LINE_VAL_DATE); return m_dateVal; } -#endif // wxUSE_DATETIME - - void SetLongVal(long val) - { Check(wxCMD_LINE_VAL_NUMBER); m_longVal = val; m_hasVal = true; } - void SetStrVal(const wxString& val) - { Check(wxCMD_LINE_VAL_STRING); m_strVal = val; m_hasVal = true; } -#if wxUSE_DATETIME - void SetDateVal(const wxDateTime& val) - { Check(wxCMD_LINE_VAL_DATE); m_dateVal = val; m_hasVal = true; } -#endif // wxUSE_DATETIME - - void SetHasValue(bool hasValue = true) { m_hasVal = hasValue; } - bool HasValue() const { return m_hasVal; } - -public: - wxCmdLineEntryType kind; - wxString shortName, - longName, - description; - wxCmdLineParamType type; - int flags; - -private: - bool m_hasVal; - - long m_longVal; - wxString m_strVal; -#if wxUSE_DATETIME - wxDateTime m_dateVal; -#endif // wxUSE_DATETIME -}; - -struct wxCmdLineParam -{ - wxCmdLineParam(const wxString& desc, - wxCmdLineParamType typ, - int fl) - : description(desc) - { - type = typ; - flags = fl; - } - - wxString description; - wxCmdLineParamType type; - int flags; -}; - -WX_DECLARE_OBJARRAY(wxCmdLineOption, wxArrayOptions); -WX_DECLARE_OBJARRAY(wxCmdLineParam, wxArrayParams); - -#include "wx/arrimpl.cpp" - -WX_DEFINE_OBJARRAY(wxArrayOptions) -WX_DEFINE_OBJARRAY(wxArrayParams) - -// the parser internal state -struct wxCmdLineParserData -{ - // options - wxString m_switchChars; // characters which may start an option - bool m_enableLongOptions; // true if long options are enabled - wxString m_logo; // some extra text to show in Usage() - - // cmd line data - wxArrayString m_arguments; // == argv, argc == m_arguments.GetCount() - wxArrayOptions m_options; // all possible options and switchrs - wxArrayParams m_paramDesc; // description of all possible params - wxArrayString m_parameters; // all params found - - // methods - wxCmdLineParserData(); - void SetArguments(int argc, char **argv); -#if wxUSE_UNICODE - void SetArguments(int argc, wxChar **argv); -#endif // wxUSE_UNICODE - void SetArguments(const wxString& cmdline); - - int FindOption(const wxString& name); - int FindOptionByLongName(const wxString& name); -}; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxCmdLineParserData -// ---------------------------------------------------------------------------- - -wxCmdLineParserData::wxCmdLineParserData() -{ - m_enableLongOptions = true; -#ifdef __UNIX_LIKE__ - m_switchChars = _T("-"); -#else // !Unix - m_switchChars = _T("/-"); -#endif -} - -void wxCmdLineParserData::SetArguments(int argc, char **argv) -{ - m_arguments.clear(); - - for ( int n = 0; n < argc; n++ ) - { - m_arguments.push_back(wxString::FromAscii(argv[n])); - } -} - -#if wxUSE_UNICODE - -void wxCmdLineParserData::SetArguments(int argc, wxChar **argv) -{ - m_arguments.clear(); - - for ( int n = 0; n < argc; n++ ) - { - m_arguments.push_back(argv[n]); - } -} - -#endif // wxUSE_UNICODE - -void wxCmdLineParserData::SetArguments(const wxString& cmdLine) -{ - m_arguments.clear(); - - if(wxTheApp && wxTheApp->argc > 0) - m_arguments.push_back(wxTheApp->argv[0]); - else - m_arguments.push_back(wxEmptyString); - - wxArrayString args = wxCmdLineParser::ConvertStringToArgs(cmdLine); - - WX_APPEND_ARRAY(m_arguments, args); -} - -int wxCmdLineParserData::FindOption(const wxString& name) -{ - if ( !name.empty() ) - { - size_t count = m_options.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( m_options[n].shortName == name ) - { - // found - return n; - } - } - } - - return wxNOT_FOUND; -} - -int wxCmdLineParserData::FindOptionByLongName(const wxString& name) -{ - size_t count = m_options.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( m_options[n].longName == name ) - { - // found - return n; - } - } - - return wxNOT_FOUND; -} - -// ---------------------------------------------------------------------------- -// construction and destruction -// ---------------------------------------------------------------------------- - -void wxCmdLineParser::Init() -{ - m_data = new wxCmdLineParserData; -} - -void wxCmdLineParser::SetCmdLine(int argc, char **argv) -{ - m_data->SetArguments(argc, argv); -} - -#if wxUSE_UNICODE - -void wxCmdLineParser::SetCmdLine(int argc, wxChar **argv) -{ - m_data->SetArguments(argc, argv); -} - -#endif // wxUSE_UNICODE - -void wxCmdLineParser::SetCmdLine(const wxString& cmdline) -{ - m_data->SetArguments(cmdline); -} - -wxCmdLineParser::~wxCmdLineParser() -{ - delete m_data; -} - -// ---------------------------------------------------------------------------- -// options -// ---------------------------------------------------------------------------- - -void wxCmdLineParser::SetSwitchChars(const wxString& switchChars) -{ - m_data->m_switchChars = switchChars; -} - -void wxCmdLineParser::EnableLongOptions(bool enable) -{ - m_data->m_enableLongOptions = enable; -} - -bool wxCmdLineParser::AreLongOptionsEnabled() -{ - return m_data->m_enableLongOptions; -} - -void wxCmdLineParser::SetLogo(const wxString& logo) -{ - m_data->m_logo = logo; -} - -// ---------------------------------------------------------------------------- -// command line construction -// ---------------------------------------------------------------------------- - -void wxCmdLineParser::SetDesc(const wxCmdLineEntryDesc *desc) -{ - for ( ;; desc++ ) - { - switch ( desc->kind ) - { - case wxCMD_LINE_SWITCH: - AddSwitch(desc->shortName, desc->longName, desc->description, - desc->flags); - break; - - case wxCMD_LINE_OPTION: - AddOption(desc->shortName, desc->longName, desc->description, - desc->type, desc->flags); - break; - - case wxCMD_LINE_PARAM: - AddParam(desc->description, desc->type, desc->flags); - break; - - default: - wxFAIL_MSG( _T("unknown command line entry type") ); - // still fall through - - case wxCMD_LINE_NONE: - return; - } - } -} - -void wxCmdLineParser::AddSwitch(const wxString& shortName, - const wxString& longName, - const wxString& desc, - int flags) -{ - wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND, - _T("duplicate switch") ); - - wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_SWITCH, - shortName, longName, desc, - wxCMD_LINE_VAL_NONE, flags); - - m_data->m_options.Add(option); -} - -void wxCmdLineParser::AddOption(const wxString& shortName, - const wxString& longName, - const wxString& desc, - wxCmdLineParamType type, - int flags) -{ - wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND, - _T("duplicate option") ); - - wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_OPTION, - shortName, longName, desc, - type, flags); - - m_data->m_options.Add(option); -} - -void wxCmdLineParser::AddParam(const wxString& desc, - wxCmdLineParamType type, - int flags) -{ - // do some consistency checks: a required parameter can't follow an - // optional one and nothing should follow a parameter with MULTIPLE flag -#ifdef __WXDEBUG__ - if ( !m_data->m_paramDesc.IsEmpty() ) - { - wxCmdLineParam& param = m_data->m_paramDesc.Last(); - - wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE), - _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style will be ignored") ); - - if ( !(flags & wxCMD_LINE_PARAM_OPTIONAL) ) - { - wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL), - _T("a required parameter can't follow an optional one") ); - } - } -#endif // Debug - - wxCmdLineParam *param = new wxCmdLineParam(desc, type, flags); - - m_data->m_paramDesc.Add(param); -} - -// ---------------------------------------------------------------------------- -// access to parse command line -// ---------------------------------------------------------------------------- - -bool wxCmdLineParser::Found(const wxString& name) const -{ - int i = m_data->FindOption(name); - if ( i == wxNOT_FOUND ) - i = m_data->FindOptionByLongName(name); - - wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown switch") ); - - wxCmdLineOption& opt = m_data->m_options[(size_t)i]; - if ( !opt.HasValue() ) - return false; - - return true; -} - -bool wxCmdLineParser::Found(const wxString& name, wxString *value) const -{ - int i = m_data->FindOption(name); - if ( i == wxNOT_FOUND ) - i = m_data->FindOptionByLongName(name); - - wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") ); - - wxCmdLineOption& opt = m_data->m_options[(size_t)i]; - if ( !opt.HasValue() ) - return false; - - wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") ); - - *value = opt.GetStrVal(); - - return true; -} - -bool wxCmdLineParser::Found(const wxString& name, long *value) const -{ - int i = m_data->FindOption(name); - if ( i == wxNOT_FOUND ) - i = m_data->FindOptionByLongName(name); - - wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") ); - - wxCmdLineOption& opt = m_data->m_options[(size_t)i]; - if ( !opt.HasValue() ) - return false; - - wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") ); - - *value = opt.GetLongVal(); - - return true; -} - -#if wxUSE_DATETIME -bool wxCmdLineParser::Found(const wxString& name, wxDateTime *value) const -{ - int i = m_data->FindOption(name); - if ( i == wxNOT_FOUND ) - i = m_data->FindOptionByLongName(name); - - wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") ); - - wxCmdLineOption& opt = m_data->m_options[(size_t)i]; - if ( !opt.HasValue() ) - return false; - - wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") ); - - *value = opt.GetDateVal(); - - return true; -} -#endif // wxUSE_DATETIME - -size_t wxCmdLineParser::GetParamCount() const -{ - return m_data->m_parameters.size(); -} - -wxString wxCmdLineParser::GetParam(size_t n) const -{ - wxCHECK_MSG( n < GetParamCount(), wxEmptyString, _T("invalid param index") ); - - return m_data->m_parameters[n]; -} - -// Resets switches and options -void wxCmdLineParser::Reset() -{ - for ( size_t i = 0; i < m_data->m_options.Count(); i++ ) - { - wxCmdLineOption& opt = m_data->m_options[i]; - opt.SetHasValue(false); - } -} - - -// ---------------------------------------------------------------------------- -// the real work is done here -// ---------------------------------------------------------------------------- - -int wxCmdLineParser::Parse(bool showUsage) -{ - bool maybeOption = true; // can the following arg be an option? - bool ok = true; // true until an error is detected - bool helpRequested = false; // true if "-h" was given - bool hadRepeatableParam = false; // true if found param with MULTIPLE flag - - size_t currentParam = 0; // the index in m_paramDesc - - size_t countParam = m_data->m_paramDesc.GetCount(); - wxString errorMsg; - - Reset(); - - // parse everything - wxString arg; - size_t count = m_data->m_arguments.size(); - for ( size_t n = 1; ok && (n < count); n++ ) // 0 is program name - { - arg = m_data->m_arguments[n]; - - // special case: "--" should be discarded and all following arguments - // should be considered as parameters, even if they start with '-' and - // not like options (this is POSIX-like) - if ( arg == _T("--") ) - { - maybeOption = false; - - continue; - } - - // empty argument or just '-' is not an option but a parameter - if ( maybeOption && arg.length() > 1 && - wxStrchr(m_data->m_switchChars, arg[0u]) ) - { - bool isLong; - wxString name; - int optInd = wxNOT_FOUND; // init to suppress warnings - - // an option or a switch: find whether it's a long or a short one - if ( arg[0u] == _T('-') && arg[1u] == _T('-') ) - { - // a long one - isLong = true; - - // Skip leading "--" - const wxChar *p = arg.c_str() + 2; - - bool longOptionsEnabled = AreLongOptionsEnabled(); - - name = GetLongOptionName(p); - - if (longOptionsEnabled) - { - optInd = m_data->FindOptionByLongName(name); - if ( optInd == wxNOT_FOUND ) - { - errorMsg << wxString::Format(_("Unknown long option '%s'"), name.c_str()) - << _T('\n'); - } - } - else - { - optInd = wxNOT_FOUND; // Sanity check - - // Print the argument including leading "--" - name.Prepend( wxT("--") ); - errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str()) - << _T('\n'); - } - - } - else // not a long option - { - isLong = false; - - // a short one: as they can be cumulated, we try to find the - // longest substring which is a valid option - const wxChar *p = arg.c_str() + 1; - - name = GetShortOptionName(p); - - size_t len = name.length(); - do - { - if ( len == 0 ) - { - // we couldn't find a valid option name in the - // beginning of this string - errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str()) - << _T('\n'); - - break; - } - else - { - optInd = m_data->FindOption(name.Left(len)); - - // will try with one character less the next time - len--; - } - } - while ( optInd == wxNOT_FOUND ); - - len++; // compensates extra len-- above - if ( (optInd != wxNOT_FOUND) && (len != name.length()) ) - { - // first of all, the option name is only part of this - // string - name = name.Left(len); - - // our option is only part of this argument, there is - // something else in it - it is either the value of this - // option or other switches if it is a switch - if ( m_data->m_options[(size_t)optInd].kind - == wxCMD_LINE_SWITCH ) - { - // pretend that all the rest of the argument is the - // next argument, in fact - wxString arg2 = arg[0u]; - arg2 += arg.Mid(len + 1); // +1 for leading '-' - - m_data->m_arguments.insert - (m_data->m_arguments.begin() + n + 1, arg2); - count++; - } - //else: it's our value, we'll deal with it below - } - } - - if ( optInd == wxNOT_FOUND ) - { - ok = false; - - continue; // will break, in fact - } - - // look at what follows: - - // +1 for leading '-' - const wxChar *p = arg.c_str() + 1 + name.length(); - if ( isLong ) - p++; // for another leading '-' - - wxCmdLineOption& opt = m_data->m_options[(size_t)optInd]; - if ( opt.kind == wxCMD_LINE_SWITCH ) - { - // we must check that there is no value following the switch - if ( *p != _T('\0') ) - { - errorMsg << wxString::Format(_("Unexpected characters following option '%s'."), name.c_str()) - << _T('\n'); - ok = false; - } - else // no value, as expected - { - // nothing more to do - opt.SetHasValue(); - - if ( opt.flags & wxCMD_LINE_OPTION_HELP ) - { - helpRequested = true; - - // it's not an error, but we still stop here - ok = false; - } - } - } - else // it's an option. not a switch - { - // get the value - if ( isLong ) - { - if ( *p++ != _T('=') ) - { - errorMsg << wxString::Format(_("Option '%s' requires a value, '=' expected."), name.c_str()) - << _T('\n'); - - ok = false; - } - } - else // short option - { - switch ( *p ) - { - case _T('='): - case _T(':'): - // the value follows - p++; - break; - - case 0: - // the value is in the next argument - if ( ++n == count ) - { - // ... but there is none - errorMsg << wxString::Format(_("Option '%s' requires a value."), - name.c_str()) - << _T('\n'); - - ok = false; - } - else - { - // ... take it from there - p = m_data->m_arguments[n].c_str(); - } - break; - - default: - // the value is right here: this may be legal or - // not depending on the option style - if ( opt.flags & wxCMD_LINE_NEEDS_SEPARATOR ) - { - errorMsg << wxString::Format(_("Separator expected after the option '%s'."), - name.c_str()) - << _T('\n'); - - ok = false; - } - } - } - - if ( ok ) - { - wxString value = p; - switch ( opt.type ) - { - default: - wxFAIL_MSG( _T("unknown option type") ); - // still fall through - - case wxCMD_LINE_VAL_STRING: - opt.SetStrVal(value); - break; - - case wxCMD_LINE_VAL_NUMBER: - { - long val; - if ( value.ToLong(&val) ) - { - opt.SetLongVal(val); - } - else - { - errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."), - value.c_str(), name.c_str()) - << _T('\n'); - - ok = false; - } - } - break; - -#if wxUSE_DATETIME - case wxCMD_LINE_VAL_DATE: - { - wxDateTime dt; - const wxChar *res = dt.ParseDate(value); - if ( !res || *res ) - { - errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."), - name.c_str(), value.c_str()) - << _T('\n'); - - ok = false; - } - else - { - opt.SetDateVal(dt); - } - } - break; -#endif // wxUSE_DATETIME - } - } - } - } - else // not an option, must be a parameter - { - if ( currentParam < countParam ) - { - wxCmdLineParam& param = m_data->m_paramDesc[currentParam]; - - // TODO check the param type - - m_data->m_parameters.push_back(arg); - - if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) ) - { - currentParam++; - } - else - { - wxASSERT_MSG( currentParam == countParam - 1, - _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") ); - - // remember that we did have this last repeatable parameter - hadRepeatableParam = true; - } - } - else - { - errorMsg << wxString::Format(_("Unexpected parameter '%s'"), arg.c_str()) - << _T('\n'); - - ok = false; - } - } - } - - // verify that all mandatory options were given - if ( ok ) - { - size_t countOpt = m_data->m_options.GetCount(); - for ( size_t n = 0; ok && (n < countOpt); n++ ) - { - wxCmdLineOption& opt = m_data->m_options[n]; - if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() ) - { - wxString optName; - if ( !opt.longName ) - { - optName = opt.shortName; - } - else - { - if ( AreLongOptionsEnabled() ) - { - optName.Printf( _("%s (or %s)"), - opt.shortName.c_str(), - opt.longName.c_str() ); - } - else - { - optName.Printf( wxT("%s"), - opt.shortName.c_str() ); - } - } - - errorMsg << wxString::Format(_("The value for the option '%s' must be specified."), - optName.c_str()) - << _T('\n'); - - ok = false; - } - } - - for ( ; ok && (currentParam < countParam); currentParam++ ) - { - wxCmdLineParam& param = m_data->m_paramDesc[currentParam]; - if ( (currentParam == countParam - 1) && - (param.flags & wxCMD_LINE_PARAM_MULTIPLE) && - hadRepeatableParam ) - { - // special case: currentParam wasn't incremented, but we did - // have it, so don't give error - continue; - } - - if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) ) - { - errorMsg << wxString::Format(_("The required parameter '%s' was not specified."), - param.description.c_str()) - << _T('\n'); - - ok = false; - } - } - } - - // if there was an error during parsing the command line, show this error - // and also the usage message if it had been requested - if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) ) - { - wxMessageOutput* msgOut = wxMessageOutput::Get(); - if ( msgOut ) - { - wxString usage; - if ( showUsage ) - usage = GetUsageString(); - - msgOut->Printf( wxT("%s%s"), usage.c_str(), errorMsg.c_str() ); - } - else - { - wxFAIL_MSG( _T("no wxMessageOutput object?") ); - } - } - - return ok ? 0 : helpRequested ? -1 : 1; -} - -// ---------------------------------------------------------------------------- -// give the usage message -// ---------------------------------------------------------------------------- - -void wxCmdLineParser::Usage() -{ - wxMessageOutput* msgOut = wxMessageOutput::Get(); - if ( msgOut ) - { - msgOut->Printf( wxT("%s"), GetUsageString().c_str() ); - } - else - { - wxFAIL_MSG( _T("no wxMessageOutput object?") ); - } -} - -wxString wxCmdLineParser::GetUsageString() -{ - wxString appname; - if ( wxTheApp ) - { - appname = wxFileName(wxTheApp->argv[0]).GetFullName(); - } - else if (!m_data->m_arguments.empty() ) - { - appname = wxFileName(m_data->m_arguments[0]).GetFullName(); - } - - // we construct the brief cmd line desc on the fly, but not the detailed - // help message below because we want to align the options descriptions - // and for this we must first know the longest one of them - wxString usage; - wxArrayString namesOptions, descOptions; - - if ( !m_data->m_logo.empty() ) - { - usage << m_data->m_logo << _T('\n'); - } - - usage << wxString::Format(_("Usage: %s"), appname.c_str()); - - // the switch char is usually '-' but this can be changed with - // SetSwitchChars() and then the first one of possible chars is used - wxChar chSwitch = !m_data->m_switchChars ? _T('-') - : m_data->m_switchChars[0u]; - - bool areLongOptionsEnabled = AreLongOptionsEnabled(); - size_t n, count = m_data->m_options.GetCount(); - for ( n = 0; n < count; n++ ) - { - wxCmdLineOption& opt = m_data->m_options[n]; - - usage << _T(' '); - if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) ) - { - usage << _T('['); - } - - if ( !opt.shortName.empty() ) - { - usage << chSwitch << opt.shortName; - } - else if ( areLongOptionsEnabled && !opt.longName.empty() ) - { - usage << _T("--") << opt.longName; - } - else - { - if (!opt.longName.empty()) - { - wxFAIL_MSG( wxT("option with only a long name while long ") - wxT("options are disabled") ); - } - else - { - wxFAIL_MSG( _T("option without neither short nor long name") ); - } - } - - wxString option; - - if ( !opt.shortName.empty() ) - { - option << _T(" ") << chSwitch << opt.shortName; - } - - if ( areLongOptionsEnabled && !opt.longName.empty() ) - { - option << (option.empty() ? _T(" ") : _T(", ")) - << _T("--") << opt.longName; - } - - if ( opt.kind != wxCMD_LINE_SWITCH ) - { - wxString val; - val << _T('<') << GetTypeName(opt.type) << _T('>'); - usage << _T(' ') << val; - option << (!opt.longName ? _T(':') : _T('=')) << val; - } - - if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) ) - { - usage << _T(']'); - } - - namesOptions.push_back(option); - descOptions.push_back(opt.description); - } - - count = m_data->m_paramDesc.GetCount(); - for ( n = 0; n < count; n++ ) - { - wxCmdLineParam& param = m_data->m_paramDesc[n]; - - usage << _T(' '); - if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL ) - { - usage << _T('['); - } - - usage << param.description; - - if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE ) - { - usage << _T("..."); - } - - if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL ) - { - usage << _T(']'); - } - } - - usage << _T('\n'); - - // now construct the detailed help message - size_t len, lenMax = 0; - count = namesOptions.size(); - for ( n = 0; n < count; n++ ) - { - len = namesOptions[n].length(); - if ( len > lenMax ) - lenMax = len; - } - - for ( n = 0; n < count; n++ ) - { - len = namesOptions[n].length(); - usage << namesOptions[n] - << wxString(_T(' '), lenMax - len) << _T('\t') - << descOptions[n] - << _T('\n'); - } - - return usage; -} - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -static wxString GetTypeName(wxCmdLineParamType type) -{ - wxString s; - switch ( type ) - { - default: - wxFAIL_MSG( _T("unknown option type") ); - // still fall through - - case wxCMD_LINE_VAL_STRING: - s = _("str"); - break; - - case wxCMD_LINE_VAL_NUMBER: - s = _("num"); - break; - - case wxCMD_LINE_VAL_DATE: - s = _("date"); - break; - } - - return s; -} - -/* -Returns a string which is equal to the string pointed to by p, but up to the -point where p contains an character that's not allowed. -Allowable characters are letters and numbers, and characters pointed to by -the parameter allowedChars. - -For example, if p points to "abcde-@-_", and allowedChars is "-_", -this function returns "abcde-". -*/ -static wxString GetOptionName(const wxChar *p, - const wxChar *allowedChars) -{ - wxString argName; - - while ( *p && (wxIsalnum(*p) || wxStrchr(allowedChars, *p)) ) - { - argName += *p++; - } - - return argName; -} - -// Besides alphanumeric characters, short and long options can -// have other characters. - -// A short option additionally can have these -#define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?") - -// A long option can have the same characters as a short option and a '-'. -#define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \ - wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-") - -static wxString GetShortOptionName(const wxChar *p) -{ - return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION); -} - -static wxString GetLongOptionName(const wxChar *p) -{ - return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION); -} - -#endif // wxUSE_CMDLINE_PARSER - -// ---------------------------------------------------------------------------- -// global functions -// ---------------------------------------------------------------------------- - -/* - This function is mainly used under Windows (as under Unix we always get the - command line arguments as argc/argv anyhow) and so it tries to follow - Windows conventions for the command line handling, not Unix ones. For - instance, backslash is not special except when it precedes double quote when - it does quote it. - */ - -/* static */ -wxArrayString wxCmdLineParser::ConvertStringToArgs(const wxChar *p) -{ - wxArrayString args; - - wxString arg; - arg.reserve(1024); - - bool isInsideQuotes = false; - for ( ;; ) - { - // skip white space - while ( *p == _T(' ') || *p == _T('\t') ) - p++; - - // anything left? - if ( *p == _T('\0') ) - break; - - // parse this parameter - bool endParam = false; - bool lastBS = false; - for ( arg.clear(); !endParam; p++ ) - { - switch ( *p ) - { - case _T('"'): - if ( !lastBS ) - { - isInsideQuotes = !isInsideQuotes; - - // don't put quote in arg - continue; - } - //else: quote has no special meaning but the backslash - // still remains -- makes no sense but this is what - // Windows does - break; - - case _T(' '): - case _T('\t'): - // backslash does *not* quote the space, only quotes do - if ( isInsideQuotes ) - { - // skip assignment below - break; - } - // fall through - - case _T('\0'): - endParam = true; - - break; - } - - if ( endParam ) - { - break; - } - - lastBS = !lastBS && *p == _T('\\'); - - arg += *p; - } - - args.push_back(arg); - } - - return args; -} +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/cmdline.cpp +// Purpose: wxCmdLineParser implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 05.01.00 +// RCS-ID: $Id: cmdline.cpp 66920 2011-02-16 22:00:30Z JS $ +// Copyright: (c) 2000 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/string.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/app.h" +#endif //WX_PRECOMP + +#include "wx/cmdline.h" + +#if wxUSE_CMDLINE_PARSER + +#include + +#include "wx/datetime.h" +#include "wx/msgout.h" +#include "wx/filename.h" + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +static wxString GetTypeName(wxCmdLineParamType type); + +static wxString GetOptionName(const wxChar *p, const wxChar *allowedChars); + +static wxString GetShortOptionName(const wxChar *p); + +static wxString GetLongOptionName(const wxChar *p); + +// ---------------------------------------------------------------------------- +// private structs +// ---------------------------------------------------------------------------- + +// an internal representation of an option +struct wxCmdLineOption +{ + wxCmdLineOption(wxCmdLineEntryType k, + const wxString& shrt, + const wxString& lng, + const wxString& desc, + wxCmdLineParamType typ, + int fl) + { + wxASSERT_MSG( !shrt.empty() || !lng.empty(), + _T("option should have at least one name") ); + + wxASSERT_MSG + ( + GetShortOptionName(shrt).Len() == shrt.Len(), + wxT("Short option contains invalid characters") + ); + + wxASSERT_MSG + ( + GetLongOptionName(lng).Len() == lng.Len(), + wxT("Long option contains invalid characters") + ); + + + kind = k; + + shortName = shrt; + longName = lng; + description = desc; + + type = typ; + flags = fl; + + m_hasVal = false; + } + + // can't use union easily here, so just store all possible data fields, we + // don't waste much (might still use union later if the number of supported + // types increases, so always use the accessor functions and don't access + // the fields directly!) + + void Check(wxCmdLineParamType WXUNUSED_UNLESS_DEBUG(typ)) const + { + wxASSERT_MSG( type == typ, _T("type mismatch in wxCmdLineOption") ); + } + + long GetLongVal() const + { Check(wxCMD_LINE_VAL_NUMBER); return m_longVal; } + const wxString& GetStrVal() const + { Check(wxCMD_LINE_VAL_STRING); return m_strVal; } +#if wxUSE_DATETIME + const wxDateTime& GetDateVal() const + { Check(wxCMD_LINE_VAL_DATE); return m_dateVal; } +#endif // wxUSE_DATETIME + + void SetLongVal(long val) + { Check(wxCMD_LINE_VAL_NUMBER); m_longVal = val; m_hasVal = true; } + void SetStrVal(const wxString& val) + { Check(wxCMD_LINE_VAL_STRING); m_strVal = val; m_hasVal = true; } +#if wxUSE_DATETIME + void SetDateVal(const wxDateTime& val) + { Check(wxCMD_LINE_VAL_DATE); m_dateVal = val; m_hasVal = true; } +#endif // wxUSE_DATETIME + + void SetHasValue(bool hasValue = true) { m_hasVal = hasValue; } + bool HasValue() const { return m_hasVal; } + +public: + wxCmdLineEntryType kind; + wxString shortName, + longName, + description; + wxCmdLineParamType type; + int flags; + +private: + bool m_hasVal; + + long m_longVal; + wxString m_strVal; +#if wxUSE_DATETIME + wxDateTime m_dateVal; +#endif // wxUSE_DATETIME +}; + +struct wxCmdLineParam +{ + wxCmdLineParam(const wxString& desc, + wxCmdLineParamType typ, + int fl) + : description(desc) + { + type = typ; + flags = fl; + } + + wxString description; + wxCmdLineParamType type; + int flags; +}; + +WX_DECLARE_OBJARRAY(wxCmdLineOption, wxArrayOptions); +WX_DECLARE_OBJARRAY(wxCmdLineParam, wxArrayParams); + +#include "wx/arrimpl.cpp" + +WX_DEFINE_OBJARRAY(wxArrayOptions) +WX_DEFINE_OBJARRAY(wxArrayParams) + +// the parser internal state +struct wxCmdLineParserData +{ + // options + wxString m_switchChars; // characters which may start an option + bool m_enableLongOptions; // true if long options are enabled + wxString m_logo; // some extra text to show in Usage() + + // cmd line data + wxArrayString m_arguments; // == argv, argc == m_arguments.GetCount() + wxArrayOptions m_options; // all possible options and switchrs + wxArrayParams m_paramDesc; // description of all possible params + wxArrayString m_parameters; // all params found + + // methods + wxCmdLineParserData(); + void SetArguments(int argc, char **argv); +#if wxUSE_UNICODE + void SetArguments(int argc, wxChar **argv); +#endif // wxUSE_UNICODE + void SetArguments(const wxString& cmdline); + + int FindOption(const wxString& name); + int FindOptionByLongName(const wxString& name); +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxCmdLineParserData +// ---------------------------------------------------------------------------- + +wxCmdLineParserData::wxCmdLineParserData() +{ + m_enableLongOptions = true; +#ifdef __UNIX_LIKE__ + m_switchChars = _T("-"); +#else // !Unix + m_switchChars = _T("/-"); +#endif +} + +void wxCmdLineParserData::SetArguments(int argc, char **argv) +{ + m_arguments.clear(); + + for ( int n = 0; n < argc; n++ ) + { + m_arguments.push_back(wxString::FromAscii(argv[n])); + } +} + +#if wxUSE_UNICODE + +void wxCmdLineParserData::SetArguments(int argc, wxChar **argv) +{ + m_arguments.clear(); + + for ( int n = 0; n < argc; n++ ) + { + m_arguments.push_back(argv[n]); + } +} + +#endif // wxUSE_UNICODE + +void wxCmdLineParserData::SetArguments(const wxString& cmdLine) +{ + m_arguments.clear(); + + if(wxTheApp && wxTheApp->argc > 0) + m_arguments.push_back(wxTheApp->argv[0]); + else + m_arguments.push_back(wxEmptyString); + + wxArrayString args = wxCmdLineParser::ConvertStringToArgs(cmdLine); + + WX_APPEND_ARRAY(m_arguments, args); +} + +int wxCmdLineParserData::FindOption(const wxString& name) +{ + if ( !name.empty() ) + { + size_t count = m_options.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( m_options[n].shortName == name ) + { + // found + return n; + } + } + } + + return wxNOT_FOUND; +} + +int wxCmdLineParserData::FindOptionByLongName(const wxString& name) +{ + size_t count = m_options.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( m_options[n].longName == name ) + { + // found + return n; + } + } + + return wxNOT_FOUND; +} + +// ---------------------------------------------------------------------------- +// construction and destruction +// ---------------------------------------------------------------------------- + +void wxCmdLineParser::Init() +{ + m_data = new wxCmdLineParserData; +} + +void wxCmdLineParser::SetCmdLine(int argc, char **argv) +{ + m_data->SetArguments(argc, argv); +} + +#if wxUSE_UNICODE + +void wxCmdLineParser::SetCmdLine(int argc, wxChar **argv) +{ + m_data->SetArguments(argc, argv); +} + +#endif // wxUSE_UNICODE + +void wxCmdLineParser::SetCmdLine(const wxString& cmdline) +{ + m_data->SetArguments(cmdline); +} + +wxCmdLineParser::~wxCmdLineParser() +{ + delete m_data; +} + +// ---------------------------------------------------------------------------- +// options +// ---------------------------------------------------------------------------- + +void wxCmdLineParser::SetSwitchChars(const wxString& switchChars) +{ + m_data->m_switchChars = switchChars; +} + +void wxCmdLineParser::EnableLongOptions(bool enable) +{ + m_data->m_enableLongOptions = enable; +} + +bool wxCmdLineParser::AreLongOptionsEnabled() +{ + return m_data->m_enableLongOptions; +} + +void wxCmdLineParser::SetLogo(const wxString& logo) +{ + m_data->m_logo = logo; +} + +// ---------------------------------------------------------------------------- +// command line construction +// ---------------------------------------------------------------------------- + +void wxCmdLineParser::SetDesc(const wxCmdLineEntryDesc *desc) +{ + for ( ;; desc++ ) + { + switch ( desc->kind ) + { + case wxCMD_LINE_SWITCH: + AddSwitch(desc->shortName, desc->longName, desc->description, + desc->flags); + break; + + case wxCMD_LINE_OPTION: + AddOption(desc->shortName, desc->longName, desc->description, + desc->type, desc->flags); + break; + + case wxCMD_LINE_PARAM: + AddParam(desc->description, desc->type, desc->flags); + break; + + default: + wxFAIL_MSG( _T("unknown command line entry type") ); + // still fall through + + case wxCMD_LINE_NONE: + return; + } + } +} + +void wxCmdLineParser::AddSwitch(const wxString& shortName, + const wxString& longName, + const wxString& desc, + int flags) +{ + wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND, + _T("duplicate switch") ); + + wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_SWITCH, + shortName, longName, desc, + wxCMD_LINE_VAL_NONE, flags); + + m_data->m_options.Add(option); +} + +void wxCmdLineParser::AddOption(const wxString& shortName, + const wxString& longName, + const wxString& desc, + wxCmdLineParamType type, + int flags) +{ + wxASSERT_MSG( m_data->FindOption(shortName) == wxNOT_FOUND, + _T("duplicate option") ); + + wxCmdLineOption *option = new wxCmdLineOption(wxCMD_LINE_OPTION, + shortName, longName, desc, + type, flags); + + m_data->m_options.Add(option); +} + +void wxCmdLineParser::AddParam(const wxString& desc, + wxCmdLineParamType type, + int flags) +{ + // do some consistency checks: a required parameter can't follow an + // optional one and nothing should follow a parameter with MULTIPLE flag +#ifdef __WXDEBUG__ + if ( !m_data->m_paramDesc.IsEmpty() ) + { + wxCmdLineParam& param = m_data->m_paramDesc.Last(); + + wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE), + _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style will be ignored") ); + + if ( !(flags & wxCMD_LINE_PARAM_OPTIONAL) ) + { + wxASSERT_MSG( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL), + _T("a required parameter can't follow an optional one") ); + } + } +#endif // Debug + + wxCmdLineParam *param = new wxCmdLineParam(desc, type, flags); + + m_data->m_paramDesc.Add(param); +} + +// ---------------------------------------------------------------------------- +// access to parse command line +// ---------------------------------------------------------------------------- + +bool wxCmdLineParser::Found(const wxString& name) const +{ + int i = m_data->FindOption(name); + if ( i == wxNOT_FOUND ) + i = m_data->FindOptionByLongName(name); + + wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown switch") ); + + wxCmdLineOption& opt = m_data->m_options[(size_t)i]; + if ( !opt.HasValue() ) + return false; + + return true; +} + +bool wxCmdLineParser::Found(const wxString& name, wxString *value) const +{ + int i = m_data->FindOption(name); + if ( i == wxNOT_FOUND ) + i = m_data->FindOptionByLongName(name); + + wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") ); + + wxCmdLineOption& opt = m_data->m_options[(size_t)i]; + if ( !opt.HasValue() ) + return false; + + wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") ); + + *value = opt.GetStrVal(); + + return true; +} + +bool wxCmdLineParser::Found(const wxString& name, long *value) const +{ + int i = m_data->FindOption(name); + if ( i == wxNOT_FOUND ) + i = m_data->FindOptionByLongName(name); + + wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") ); + + wxCmdLineOption& opt = m_data->m_options[(size_t)i]; + if ( !opt.HasValue() ) + return false; + + wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") ); + + *value = opt.GetLongVal(); + + return true; +} + +#if wxUSE_DATETIME +bool wxCmdLineParser::Found(const wxString& name, wxDateTime *value) const +{ + int i = m_data->FindOption(name); + if ( i == wxNOT_FOUND ) + i = m_data->FindOptionByLongName(name); + + wxCHECK_MSG( i != wxNOT_FOUND, false, _T("unknown option") ); + + wxCmdLineOption& opt = m_data->m_options[(size_t)i]; + if ( !opt.HasValue() ) + return false; + + wxCHECK_MSG( value, false, _T("NULL pointer in wxCmdLineOption::Found") ); + + *value = opt.GetDateVal(); + + return true; +} +#endif // wxUSE_DATETIME + +size_t wxCmdLineParser::GetParamCount() const +{ + return m_data->m_parameters.size(); +} + +wxString wxCmdLineParser::GetParam(size_t n) const +{ + wxCHECK_MSG( n < GetParamCount(), wxEmptyString, _T("invalid param index") ); + + return m_data->m_parameters[n]; +} + +// Resets switches and options +void wxCmdLineParser::Reset() +{ + for ( size_t i = 0; i < m_data->m_options.Count(); i++ ) + { + wxCmdLineOption& opt = m_data->m_options[i]; + opt.SetHasValue(false); + } +} + + +// ---------------------------------------------------------------------------- +// the real work is done here +// ---------------------------------------------------------------------------- + +int wxCmdLineParser::Parse(bool showUsage) +{ + bool maybeOption = true; // can the following arg be an option? + bool ok = true; // true until an error is detected + bool helpRequested = false; // true if "-h" was given + bool hadRepeatableParam = false; // true if found param with MULTIPLE flag + + size_t currentParam = 0; // the index in m_paramDesc + + size_t countParam = m_data->m_paramDesc.GetCount(); + wxString errorMsg; + + Reset(); + + // parse everything + wxString arg; + size_t count = m_data->m_arguments.size(); + for ( size_t n = 1; ok && (n < count); n++ ) // 0 is program name + { + arg = m_data->m_arguments[n]; + + // special case: "--" should be discarded and all following arguments + // should be considered as parameters, even if they start with '-' and + // not like options (this is POSIX-like) + if ( arg == _T("--") ) + { + maybeOption = false; + + continue; + } + + // empty argument or just '-' is not an option but a parameter + if ( maybeOption && arg.length() > 1 && + wxStrchr(m_data->m_switchChars, arg[0u]) ) + { + bool isLong; + wxString name; + int optInd = wxNOT_FOUND; // init to suppress warnings + + // an option or a switch: find whether it's a long or a short one + if ( arg[0u] == _T('-') && arg[1u] == _T('-') ) + { + // a long one + isLong = true; + + // Skip leading "--" + const wxChar *p = arg.c_str() + 2; + + bool longOptionsEnabled = AreLongOptionsEnabled(); + + name = GetLongOptionName(p); + + if (longOptionsEnabled) + { + optInd = m_data->FindOptionByLongName(name); + if ( optInd == wxNOT_FOUND ) + { + errorMsg << wxString::Format(_("Unknown long option '%s'"), name.c_str()) + << _T('\n'); + } + } + else + { + optInd = wxNOT_FOUND; // Sanity check + + // Print the argument including leading "--" + name.Prepend( wxT("--") ); + errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str()) + << _T('\n'); + } + + } + else // not a long option + { + isLong = false; + + // a short one: as they can be cumulated, we try to find the + // longest substring which is a valid option + const wxChar *p = arg.c_str() + 1; + + name = GetShortOptionName(p); + + size_t len = name.length(); + do + { + if ( len == 0 ) + { + // we couldn't find a valid option name in the + // beginning of this string + errorMsg << wxString::Format(_("Unknown option '%s'"), name.c_str()) + << _T('\n'); + + break; + } + else + { + optInd = m_data->FindOption(name.Left(len)); + + // will try with one character less the next time + len--; + } + } + while ( optInd == wxNOT_FOUND ); + + len++; // compensates extra len-- above + if ( (optInd != wxNOT_FOUND) && (len != name.length()) ) + { + // first of all, the option name is only part of this + // string + name = name.Left(len); + + // our option is only part of this argument, there is + // something else in it - it is either the value of this + // option or other switches if it is a switch + if ( m_data->m_options[(size_t)optInd].kind + == wxCMD_LINE_SWITCH ) + { + // pretend that all the rest of the argument is the + // next argument, in fact + wxString arg2 = arg[0u]; + arg2 += arg.Mid(len + 1); // +1 for leading '-' + + m_data->m_arguments.insert + (m_data->m_arguments.begin() + n + 1, arg2); + count++; + } + //else: it's our value, we'll deal with it below + } + } + + if ( optInd == wxNOT_FOUND ) + { + ok = false; + + continue; // will break, in fact + } + + // look at what follows: + + // +1 for leading '-' + const wxChar *p = arg.c_str() + 1 + name.length(); + if ( isLong ) + p++; // for another leading '-' + + wxCmdLineOption& opt = m_data->m_options[(size_t)optInd]; + if ( opt.kind == wxCMD_LINE_SWITCH ) + { + // we must check that there is no value following the switch + if ( *p != _T('\0') ) + { + errorMsg << wxString::Format(_("Unexpected characters following option '%s'."), name.c_str()) + << _T('\n'); + ok = false; + } + else // no value, as expected + { + // nothing more to do + opt.SetHasValue(); + + if ( opt.flags & wxCMD_LINE_OPTION_HELP ) + { + helpRequested = true; + + // it's not an error, but we still stop here + ok = false; + } + } + } + else // it's an option. not a switch + { + // get the value + if ( isLong ) + { + if ( *p++ != _T('=') ) + { + errorMsg << wxString::Format(_("Option '%s' requires a value, '=' expected."), name.c_str()) + << _T('\n'); + + ok = false; + } + } + else // short option + { + switch ( *p ) + { + case _T('='): + case _T(':'): + // the value follows + p++; + break; + + case 0: + // the value is in the next argument + if ( ++n == count ) + { + // ... but there is none + errorMsg << wxString::Format(_("Option '%s' requires a value."), + name.c_str()) + << _T('\n'); + + ok = false; + } + else + { + // ... take it from there + p = m_data->m_arguments[n].c_str(); + } + break; + + default: + // the value is right here: this may be legal or + // not depending on the option style + if ( opt.flags & wxCMD_LINE_NEEDS_SEPARATOR ) + { + errorMsg << wxString::Format(_("Separator expected after the option '%s'."), + name.c_str()) + << _T('\n'); + + ok = false; + } + } + } + + if ( ok ) + { + wxString value = p; + switch ( opt.type ) + { + default: + wxFAIL_MSG( _T("unknown option type") ); + // still fall through + + case wxCMD_LINE_VAL_STRING: + opt.SetStrVal(value); + break; + + case wxCMD_LINE_VAL_NUMBER: + { + long val; + if ( value.ToLong(&val) ) + { + opt.SetLongVal(val); + } + else + { + errorMsg << wxString::Format(_("'%s' is not a correct numeric value for option '%s'."), + value.c_str(), name.c_str()) + << _T('\n'); + + ok = false; + } + } + break; + +#if wxUSE_DATETIME + case wxCMD_LINE_VAL_DATE: + { + wxDateTime dt; + const wxChar *res = dt.ParseDate(value); + if ( !res || *res ) + { + errorMsg << wxString::Format(_("Option '%s': '%s' cannot be converted to a date."), + name.c_str(), value.c_str()) + << _T('\n'); + + ok = false; + } + else + { + opt.SetDateVal(dt); + } + } + break; +#endif // wxUSE_DATETIME + } + } + } + } + else // not an option, must be a parameter + { + if ( currentParam < countParam ) + { + wxCmdLineParam& param = m_data->m_paramDesc[currentParam]; + + // TODO check the param type + + m_data->m_parameters.push_back(arg); + + if ( !(param.flags & wxCMD_LINE_PARAM_MULTIPLE) ) + { + currentParam++; + } + else + { + wxASSERT_MSG( currentParam == countParam - 1, + _T("all parameters after the one with wxCMD_LINE_PARAM_MULTIPLE style are ignored") ); + + // remember that we did have this last repeatable parameter + hadRepeatableParam = true; + } + } + else + { + errorMsg << wxString::Format(_("Unexpected parameter '%s'"), arg.c_str()) + << _T('\n'); + + ok = false; + } + } + } + + // verify that all mandatory options were given + if ( ok ) + { + size_t countOpt = m_data->m_options.GetCount(); + for ( size_t n = 0; ok && (n < countOpt); n++ ) + { + wxCmdLineOption& opt = m_data->m_options[n]; + if ( (opt.flags & wxCMD_LINE_OPTION_MANDATORY) && !opt.HasValue() ) + { + wxString optName; + if ( !opt.longName ) + { + optName = opt.shortName; + } + else + { + if ( AreLongOptionsEnabled() ) + { + optName.Printf( _("%s (or %s)"), + opt.shortName.c_str(), + opt.longName.c_str() ); + } + else + { + optName.Printf( wxT("%s"), + opt.shortName.c_str() ); + } + } + + errorMsg << wxString::Format(_("The value for the option '%s' must be specified."), + optName.c_str()) + << _T('\n'); + + ok = false; + } + } + + for ( ; ok && (currentParam < countParam); currentParam++ ) + { + wxCmdLineParam& param = m_data->m_paramDesc[currentParam]; + if ( (currentParam == countParam - 1) && + (param.flags & wxCMD_LINE_PARAM_MULTIPLE) && + hadRepeatableParam ) + { + // special case: currentParam wasn't incremented, but we did + // have it, so don't give error + continue; + } + + if ( !(param.flags & wxCMD_LINE_PARAM_OPTIONAL) ) + { + errorMsg << wxString::Format(_("The required parameter '%s' was not specified."), + param.description.c_str()) + << _T('\n'); + + ok = false; + } + } + } + + // if there was an error during parsing the command line, show this error + // and also the usage message if it had been requested + if ( !ok && (!errorMsg.empty() || (helpRequested && showUsage)) ) + { + wxMessageOutput* msgOut = wxMessageOutput::Get(); + if ( msgOut ) + { + wxString usage; + if ( showUsage ) + usage = GetUsageString(); + + msgOut->Printf( wxT("%s%s"), usage.c_str(), errorMsg.c_str() ); + } + else + { + wxFAIL_MSG( _T("no wxMessageOutput object?") ); + } + } + + return ok ? 0 : helpRequested ? -1 : 1; +} + +// ---------------------------------------------------------------------------- +// give the usage message +// ---------------------------------------------------------------------------- + +void wxCmdLineParser::Usage() +{ + wxMessageOutput* msgOut = wxMessageOutput::Get(); + if ( msgOut ) + { + msgOut->Printf( wxT("%s"), GetUsageString().c_str() ); + } + else + { + wxFAIL_MSG( _T("no wxMessageOutput object?") ); + } +} + +wxString wxCmdLineParser::GetUsageString() +{ + wxString appname; + if ( wxTheApp ) + { + appname = wxFileName(wxTheApp->argv[0]).GetFullName(); + } + else if (!m_data->m_arguments.empty() ) + { + appname = wxFileName(m_data->m_arguments[0]).GetFullName(); + } + + // we construct the brief cmd line desc on the fly, but not the detailed + // help message below because we want to align the options descriptions + // and for this we must first know the longest one of them + wxString usage; + wxArrayString namesOptions, descOptions; + + if ( !m_data->m_logo.empty() ) + { + usage << m_data->m_logo << _T('\n'); + } + + usage << wxString::Format(_("Usage: %s"), appname.c_str()); + + // the switch char is usually '-' but this can be changed with + // SetSwitchChars() and then the first one of possible chars is used + wxChar chSwitch = !m_data->m_switchChars ? _T('-') + : m_data->m_switchChars[0u]; + + bool areLongOptionsEnabled = AreLongOptionsEnabled(); + size_t n, count = m_data->m_options.GetCount(); + for ( n = 0; n < count; n++ ) + { + wxCmdLineOption& opt = m_data->m_options[n]; + + usage << _T(' '); + if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) ) + { + usage << _T('['); + } + + if ( !opt.shortName.empty() ) + { + usage << chSwitch << opt.shortName; + } + else if ( areLongOptionsEnabled && !opt.longName.empty() ) + { + usage << _T("--") << opt.longName; + } + else + { + if (!opt.longName.empty()) + { + wxFAIL_MSG( wxT("option with only a long name while long ") + wxT("options are disabled") ); + } + else + { + wxFAIL_MSG( _T("option without neither short nor long name") ); + } + } + + wxString option; + + if ( !opt.shortName.empty() ) + { + option << _T(" ") << chSwitch << opt.shortName; + } + + if ( areLongOptionsEnabled && !opt.longName.empty() ) + { + option << (option.empty() ? _T(" ") : _T(", ")) + << _T("--") << opt.longName; + } + + if ( opt.kind != wxCMD_LINE_SWITCH ) + { + wxString val; + val << _T('<') << GetTypeName(opt.type) << _T('>'); + usage << _T(' ') << val; + option << (!opt.longName ? _T(':') : _T('=')) << val; + } + + if ( !(opt.flags & wxCMD_LINE_OPTION_MANDATORY) ) + { + usage << _T(']'); + } + + namesOptions.push_back(option); + descOptions.push_back(opt.description); + } + + count = m_data->m_paramDesc.GetCount(); + for ( n = 0; n < count; n++ ) + { + wxCmdLineParam& param = m_data->m_paramDesc[n]; + + usage << _T(' '); + if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL ) + { + usage << _T('['); + } + + usage << param.description; + + if ( param.flags & wxCMD_LINE_PARAM_MULTIPLE ) + { + usage << _T("..."); + } + + if ( param.flags & wxCMD_LINE_PARAM_OPTIONAL ) + { + usage << _T(']'); + } + } + + usage << _T('\n'); + + // now construct the detailed help message + size_t len, lenMax = 0; + count = namesOptions.size(); + for ( n = 0; n < count; n++ ) + { + len = namesOptions[n].length(); + if ( len > lenMax ) + lenMax = len; + } + + for ( n = 0; n < count; n++ ) + { + len = namesOptions[n].length(); + usage << namesOptions[n] + << wxString(_T(' '), lenMax - len) << _T('\t') + << descOptions[n] + << _T('\n'); + } + + return usage; +} + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +static wxString GetTypeName(wxCmdLineParamType type) +{ + wxString s; + switch ( type ) + { + default: + wxFAIL_MSG( _T("unknown option type") ); + // still fall through + + case wxCMD_LINE_VAL_STRING: + s = _("str"); + break; + + case wxCMD_LINE_VAL_NUMBER: + s = _("num"); + break; + + case wxCMD_LINE_VAL_DATE: + s = _("date"); + break; + } + + return s; +} + +/* +Returns a string which is equal to the string pointed to by p, but up to the +point where p contains an character that's not allowed. +Allowable characters are letters and numbers, and characters pointed to by +the parameter allowedChars. + +For example, if p points to "abcde-@-_", and allowedChars is "-_", +this function returns "abcde-". +*/ +static wxString GetOptionName(const wxChar *p, + const wxChar *allowedChars) +{ + wxString argName; + + while ( *p && (wxIsalnum(*p) || wxStrchr(allowedChars, *p)) ) + { + argName += *p++; + } + + return argName; +} + +// Besides alphanumeric characters, short and long options can +// have other characters. + +// A short option additionally can have these +#define wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("_?") + +// A long option can have the same characters as a short option and a '-'. +#define wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION \ + wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION wxT("-") + +static wxString GetShortOptionName(const wxChar *p) +{ + return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_SHORT_OPTION); +} + +static wxString GetLongOptionName(const wxChar *p) +{ + return GetOptionName(p, wxCMD_LINE_CHARS_ALLOWED_BY_LONG_OPTION); +} + +#endif // wxUSE_CMDLINE_PARSER + +// ---------------------------------------------------------------------------- +// global functions +// ---------------------------------------------------------------------------- + +/* + This function is mainly used under Windows (as under Unix we always get the + command line arguments as argc/argv anyhow) and so it tries to follow + Windows conventions for the command line handling, not Unix ones. For + instance, backslash is not special except when it precedes double quote when + it does quote it. + */ + +/* static */ +wxArrayString wxCmdLineParser::ConvertStringToArgs(const wxChar *p) +{ + wxArrayString args; + + wxString arg; + arg.reserve(1024); + + bool isInsideQuotes = false; + for ( ;; ) + { + // skip white space + while ( *p == _T(' ') || *p == _T('\t') ) + p++; + + // anything left? + if ( *p == _T('\0') ) + break; + + // parse this parameter + bool endParam = false; + bool lastBS = false; + for ( arg.clear(); !endParam; p++ ) + { + switch ( *p ) + { + case _T('"'): + if ( !lastBS ) + { + isInsideQuotes = !isInsideQuotes; + + // don't put quote in arg + continue; + } + //else: quote has no special meaning but the backslash + // still remains -- makes no sense but this is what + // Windows does + break; + + case _T(' '): + case _T('\t'): + // backslash does *not* quote the space, only quotes do + if ( isInsideQuotes ) + { + // skip assignment below + break; + } + // fall through + + case _T('\0'): + endParam = true; + + break; + } + + if ( endParam ) + { + break; + } + + lastBS = !lastBS && *p == _T('\\'); + + arg += *p; + } + + args.push_back(arg); + } + + return args; +} diff --git a/Source/3rd Party/wx/src/common/cmdproc.cpp b/Source/3rd Party/wx/src/common/cmdproc.cpp index 0ca291a61..808f7bd95 100644 --- a/Source/3rd Party/wx/src/common/cmdproc.cpp +++ b/Source/3rd Party/wx/src/common/cmdproc.cpp @@ -1,325 +1,325 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/cmdproc.cpp -// Purpose: wxCommand and wxCommandProcessor classes -// Author: Julian Smart (extracted from docview.h by VZ) -// Modified by: -// Created: 05.11.00 -// RCS-ID: $Id: cmdproc.cpp 65725 2010-10-02 13:05:08Z TIK $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/string.h" - #include "wx/menu.h" -#endif //WX_PRECOMP - -#include "wx/cmdproc.h" - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_CLASS(wxCommand, wxObject) -IMPLEMENT_DYNAMIC_CLASS(wxCommandProcessor, wxObject) - -// ---------------------------------------------------------------------------- -// wxCommand -// ---------------------------------------------------------------------------- - -wxCommand::wxCommand(bool canUndoIt, const wxString& name) -{ - m_canUndo = canUndoIt; - m_commandName = name; -} - -// ---------------------------------------------------------------------------- -// Command processor -// ---------------------------------------------------------------------------- - -wxCommandProcessor::wxCommandProcessor(int maxCommands) -{ - m_maxNoCommands = maxCommands; -#if wxUSE_MENUS - m_commandEditMenu = (wxMenu *) NULL; -#endif // wxUSE_MENUS - m_undoAccelerator = wxT("\tCtrl+Z"); - m_redoAccelerator = wxT("\tCtrl+Y"); - - m_lastSavedCommand = - m_currentCommand = wxList::compatibility_iterator(); -} - -wxCommandProcessor::~wxCommandProcessor() -{ - ClearCommands(); -} - -bool wxCommandProcessor::DoCommand(wxCommand& cmd) -{ - return cmd.Do(); -} - -bool wxCommandProcessor::UndoCommand(wxCommand& cmd) -{ - return cmd.Undo(); -} - -// Pass a command to the processor. The processor calls Do(); -// if successful, is appended to the command history unless -// storeIt is false. -bool wxCommandProcessor::Submit(wxCommand *command, bool storeIt) -{ - wxCHECK_MSG( command, false, _T("no command in wxCommandProcessor::Submit") ); - - if ( !DoCommand(*command) ) - { - // the user code expects the command to be deleted anyhow - delete command; - - return false; - } - - if ( storeIt ) - Store(command); - else - delete command; - - return true; -} - -void wxCommandProcessor::Store(wxCommand *command) -{ - wxCHECK_RET( command, _T("no command in wxCommandProcessor::Store") ); - - // Correct a bug: we must chop off the current 'branch' - // so that we're at the end of the command list. - if (!m_currentCommand) - ClearCommands(); - else - { - wxList::compatibility_iterator node = m_currentCommand->GetNext(); - while (node) - { - wxList::compatibility_iterator next = node->GetNext(); - delete (wxCommand *)node->GetData(); - m_commands.Erase(node); - - // Make sure m_lastSavedCommand won't point to freed memory - if ( m_lastSavedCommand == node ) - m_lastSavedCommand = wxList::compatibility_iterator(); - - node = next; - } - } - - if ( (int)m_commands.GetCount() == m_maxNoCommands ) - { - wxList::compatibility_iterator firstNode = m_commands.GetFirst(); - wxCommand *firstCommand = (wxCommand *)firstNode->GetData(); - delete firstCommand; - m_commands.Erase(firstNode); - - // Make sure m_lastSavedCommand won't point to freed memory - if ( m_lastSavedCommand == firstNode ) - m_lastSavedCommand = wxList::compatibility_iterator(); - } - - m_commands.Append(command); - m_currentCommand = m_commands.GetLast(); - SetMenuStrings(); -} - -bool wxCommandProcessor::Undo() -{ - wxCommand *command = GetCurrentCommand(); - if ( command && command->CanUndo() ) - { - if ( UndoCommand(*command) ) - { - m_currentCommand = m_currentCommand->GetPrevious(); - SetMenuStrings(); - return true; - } - } - - return false; -} - -bool wxCommandProcessor::Redo() -{ - wxCommand *redoCommand = (wxCommand *) NULL; - wxList::compatibility_iterator redoNode -#if !wxUSE_STL - = NULL // just to avoid warnings -#endif // !wxUSE_STL - ; - - if ( m_currentCommand ) - { - // is there anything to redo? - if ( m_currentCommand->GetNext() ) - { - redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData(); - redoNode = m_currentCommand->GetNext(); - } - } - else // no current command, redo the first one - { - if (m_commands.GetCount() > 0) - { - redoCommand = (wxCommand *)m_commands.GetFirst()->GetData(); - redoNode = m_commands.GetFirst(); - } - } - - if (redoCommand) - { - bool success = DoCommand(*redoCommand); - if (success) - { - m_currentCommand = redoNode; - SetMenuStrings(); - return true; - } - } - return false; -} - -bool wxCommandProcessor::CanUndo() const -{ - wxCommand *command = GetCurrentCommand(); - - return command && command->CanUndo(); -} - -bool wxCommandProcessor::CanRedo() const -{ - if (m_currentCommand && !m_currentCommand->GetNext()) - return false; - - if (m_currentCommand && m_currentCommand->GetNext()) - return true; - - if (!m_currentCommand && (m_commands.GetCount() > 0)) - return true; - - return false; -} - -void wxCommandProcessor::Initialize() -{ - m_currentCommand = m_commands.GetLast(); - SetMenuStrings(); -} - -void wxCommandProcessor::SetMenuStrings() -{ -#if wxUSE_MENUS - if (m_commandEditMenu) - { - wxString undoLabel = GetUndoMenuLabel(); - wxString redoLabel = GetRedoMenuLabel(); - - m_commandEditMenu->SetLabel(wxID_UNDO, undoLabel); - m_commandEditMenu->Enable(wxID_UNDO, CanUndo()); - - m_commandEditMenu->SetLabel(wxID_REDO, redoLabel); - m_commandEditMenu->Enable(wxID_REDO, CanRedo()); - } -#endif // wxUSE_MENUS -} - -// Gets the current Undo menu label. -wxString wxCommandProcessor::GetUndoMenuLabel() const -{ - wxString buf; - if (m_currentCommand) - { - wxCommand *command = (wxCommand *)m_currentCommand->GetData(); - wxString commandName(command->GetName()); - if (commandName.empty()) commandName = _("Unnamed command"); - bool canUndo = command->CanUndo(); - if (canUndo) - buf = wxString(_("&Undo ")) + commandName + m_undoAccelerator; - else - buf = wxString(_("Can't &Undo ")) + commandName + m_undoAccelerator; - } - else - { - buf = _("&Undo") + m_undoAccelerator; - } - - return buf; -} - -// Gets the current Undo menu label. -wxString wxCommandProcessor::GetRedoMenuLabel() const -{ - wxString buf; - if (m_currentCommand) - { - // We can redo, if we're not at the end of the history. - if (m_currentCommand->GetNext()) - { - wxCommand *redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData(); - wxString redoCommandName(redoCommand->GetName()); - if (redoCommandName.empty()) redoCommandName = _("Unnamed command"); - buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator; - } - else - { - buf = _("&Redo") + m_redoAccelerator; - } - } - else - { - if (m_commands.GetCount() == 0) - { - buf = _("&Redo") + m_redoAccelerator; - } - else - { - // currentCommand is NULL but there are commands: this means that - // we've undone to the start of the list, but can redo the first. - wxCommand *redoCommand = (wxCommand *)m_commands.GetFirst()->GetData(); - wxString redoCommandName(redoCommand->GetName()); - if (redoCommandName.empty()) redoCommandName = _("Unnamed command"); - buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator; - } - } - return buf; -} - -void wxCommandProcessor::ClearCommands() -{ - wxList::compatibility_iterator node = m_commands.GetFirst(); - while (node) - { - wxCommand *command = (wxCommand *)node->GetData(); - delete command; - m_commands.Erase(node); - node = m_commands.GetFirst(); - } - - m_currentCommand = wxList::compatibility_iterator(); - m_lastSavedCommand = wxList::compatibility_iterator(); -} - - +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/cmdproc.cpp +// Purpose: wxCommand and wxCommandProcessor classes +// Author: Julian Smart (extracted from docview.h by VZ) +// Modified by: +// Created: 05.11.00 +// RCS-ID: $Id: cmdproc.cpp 65725 2010-10-02 13:05:08Z TIK $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/string.h" + #include "wx/menu.h" +#endif //WX_PRECOMP + +#include "wx/cmdproc.h" + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_CLASS(wxCommand, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxCommandProcessor, wxObject) + +// ---------------------------------------------------------------------------- +// wxCommand +// ---------------------------------------------------------------------------- + +wxCommand::wxCommand(bool canUndoIt, const wxString& name) +{ + m_canUndo = canUndoIt; + m_commandName = name; +} + +// ---------------------------------------------------------------------------- +// Command processor +// ---------------------------------------------------------------------------- + +wxCommandProcessor::wxCommandProcessor(int maxCommands) +{ + m_maxNoCommands = maxCommands; +#if wxUSE_MENUS + m_commandEditMenu = (wxMenu *) NULL; +#endif // wxUSE_MENUS + m_undoAccelerator = wxT("\tCtrl+Z"); + m_redoAccelerator = wxT("\tCtrl+Y"); + + m_lastSavedCommand = + m_currentCommand = wxList::compatibility_iterator(); +} + +wxCommandProcessor::~wxCommandProcessor() +{ + ClearCommands(); +} + +bool wxCommandProcessor::DoCommand(wxCommand& cmd) +{ + return cmd.Do(); +} + +bool wxCommandProcessor::UndoCommand(wxCommand& cmd) +{ + return cmd.Undo(); +} + +// Pass a command to the processor. The processor calls Do(); +// if successful, is appended to the command history unless +// storeIt is false. +bool wxCommandProcessor::Submit(wxCommand *command, bool storeIt) +{ + wxCHECK_MSG( command, false, _T("no command in wxCommandProcessor::Submit") ); + + if ( !DoCommand(*command) ) + { + // the user code expects the command to be deleted anyhow + delete command; + + return false; + } + + if ( storeIt ) + Store(command); + else + delete command; + + return true; +} + +void wxCommandProcessor::Store(wxCommand *command) +{ + wxCHECK_RET( command, _T("no command in wxCommandProcessor::Store") ); + + // Correct a bug: we must chop off the current 'branch' + // so that we're at the end of the command list. + if (!m_currentCommand) + ClearCommands(); + else + { + wxList::compatibility_iterator node = m_currentCommand->GetNext(); + while (node) + { + wxList::compatibility_iterator next = node->GetNext(); + delete (wxCommand *)node->GetData(); + m_commands.Erase(node); + + // Make sure m_lastSavedCommand won't point to freed memory + if ( m_lastSavedCommand == node ) + m_lastSavedCommand = wxList::compatibility_iterator(); + + node = next; + } + } + + if ( (int)m_commands.GetCount() == m_maxNoCommands ) + { + wxList::compatibility_iterator firstNode = m_commands.GetFirst(); + wxCommand *firstCommand = (wxCommand *)firstNode->GetData(); + delete firstCommand; + m_commands.Erase(firstNode); + + // Make sure m_lastSavedCommand won't point to freed memory + if ( m_lastSavedCommand == firstNode ) + m_lastSavedCommand = wxList::compatibility_iterator(); + } + + m_commands.Append(command); + m_currentCommand = m_commands.GetLast(); + SetMenuStrings(); +} + +bool wxCommandProcessor::Undo() +{ + wxCommand *command = GetCurrentCommand(); + if ( command && command->CanUndo() ) + { + if ( UndoCommand(*command) ) + { + m_currentCommand = m_currentCommand->GetPrevious(); + SetMenuStrings(); + return true; + } + } + + return false; +} + +bool wxCommandProcessor::Redo() +{ + wxCommand *redoCommand = (wxCommand *) NULL; + wxList::compatibility_iterator redoNode +#if !wxUSE_STL + = NULL // just to avoid warnings +#endif // !wxUSE_STL + ; + + if ( m_currentCommand ) + { + // is there anything to redo? + if ( m_currentCommand->GetNext() ) + { + redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData(); + redoNode = m_currentCommand->GetNext(); + } + } + else // no current command, redo the first one + { + if (m_commands.GetCount() > 0) + { + redoCommand = (wxCommand *)m_commands.GetFirst()->GetData(); + redoNode = m_commands.GetFirst(); + } + } + + if (redoCommand) + { + bool success = DoCommand(*redoCommand); + if (success) + { + m_currentCommand = redoNode; + SetMenuStrings(); + return true; + } + } + return false; +} + +bool wxCommandProcessor::CanUndo() const +{ + wxCommand *command = GetCurrentCommand(); + + return command && command->CanUndo(); +} + +bool wxCommandProcessor::CanRedo() const +{ + if (m_currentCommand && !m_currentCommand->GetNext()) + return false; + + if (m_currentCommand && m_currentCommand->GetNext()) + return true; + + if (!m_currentCommand && (m_commands.GetCount() > 0)) + return true; + + return false; +} + +void wxCommandProcessor::Initialize() +{ + m_currentCommand = m_commands.GetLast(); + SetMenuStrings(); +} + +void wxCommandProcessor::SetMenuStrings() +{ +#if wxUSE_MENUS + if (m_commandEditMenu) + { + wxString undoLabel = GetUndoMenuLabel(); + wxString redoLabel = GetRedoMenuLabel(); + + m_commandEditMenu->SetLabel(wxID_UNDO, undoLabel); + m_commandEditMenu->Enable(wxID_UNDO, CanUndo()); + + m_commandEditMenu->SetLabel(wxID_REDO, redoLabel); + m_commandEditMenu->Enable(wxID_REDO, CanRedo()); + } +#endif // wxUSE_MENUS +} + +// Gets the current Undo menu label. +wxString wxCommandProcessor::GetUndoMenuLabel() const +{ + wxString buf; + if (m_currentCommand) + { + wxCommand *command = (wxCommand *)m_currentCommand->GetData(); + wxString commandName(command->GetName()); + if (commandName.empty()) commandName = _("Unnamed command"); + bool canUndo = command->CanUndo(); + if (canUndo) + buf = wxString(_("&Undo ")) + commandName + m_undoAccelerator; + else + buf = wxString(_("Can't &Undo ")) + commandName + m_undoAccelerator; + } + else + { + buf = _("&Undo") + m_undoAccelerator; + } + + return buf; +} + +// Gets the current Undo menu label. +wxString wxCommandProcessor::GetRedoMenuLabel() const +{ + wxString buf; + if (m_currentCommand) + { + // We can redo, if we're not at the end of the history. + if (m_currentCommand->GetNext()) + { + wxCommand *redoCommand = (wxCommand *)m_currentCommand->GetNext()->GetData(); + wxString redoCommandName(redoCommand->GetName()); + if (redoCommandName.empty()) redoCommandName = _("Unnamed command"); + buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator; + } + else + { + buf = _("&Redo") + m_redoAccelerator; + } + } + else + { + if (m_commands.GetCount() == 0) + { + buf = _("&Redo") + m_redoAccelerator; + } + else + { + // currentCommand is NULL but there are commands: this means that + // we've undone to the start of the list, but can redo the first. + wxCommand *redoCommand = (wxCommand *)m_commands.GetFirst()->GetData(); + wxString redoCommandName(redoCommand->GetName()); + if (redoCommandName.empty()) redoCommandName = _("Unnamed command"); + buf = wxString(_("&Redo ")) + redoCommandName + m_redoAccelerator; + } + } + return buf; +} + +void wxCommandProcessor::ClearCommands() +{ + wxList::compatibility_iterator node = m_commands.GetFirst(); + while (node) + { + wxCommand *command = (wxCommand *)node->GetData(); + delete command; + m_commands.Erase(node); + node = m_commands.GetFirst(); + } + + m_currentCommand = wxList::compatibility_iterator(); + m_lastSavedCommand = wxList::compatibility_iterator(); +} + + diff --git a/Source/3rd Party/wx/src/common/cmndata.cpp b/Source/3rd Party/wx/src/common/cmndata.cpp index 9dccd841b..a6edb97b2 100644 --- a/Source/3rd Party/wx/src/common/cmndata.cpp +++ b/Source/3rd Party/wx/src/common/cmndata.cpp @@ -1,660 +1,660 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/cmndata.cpp -// Purpose: Common GDI data -// Author: Julian Smart -// Modified by: -// Created: 01/02/97 -// RCS-ID: $Id: cmndata.cpp 60700 2009-05-20 13:18:11Z JS $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/cmndata.h" - -#ifndef WX_PRECOMP - #if defined(__WXMSW__) - #include "wx/msw/wrapcdlg.h" - #endif // MSW - #include - #include "wx/string.h" - #include "wx/utils.h" - #include "wx/app.h" - #include "wx/log.h" - #include "wx/gdicmn.h" -#endif - -#include "wx/prntbase.h" -#include "wx/printdlg.h" - -#if wxUSE_FONTDLG - #include "wx/fontdlg.h" -#endif // wxUSE_FONTDLG - -#if wxUSE_PRINTING_ARCHITECTURE - -#include "wx/paper.h" - -#if defined(__WXMAC__) - #include "wx/mac/private/print.h" -#endif - -IMPLEMENT_DYNAMIC_CLASS(wxPrintData, wxObject) -IMPLEMENT_DYNAMIC_CLASS(wxPrintDialogData, wxObject) -IMPLEMENT_DYNAMIC_CLASS(wxPageSetupDialogData, wxObject) - -#endif // wxUSE_PRINTING_ARCHITECTURE - -IMPLEMENT_DYNAMIC_CLASS(wxFontData, wxObject) -IMPLEMENT_DYNAMIC_CLASS(wxColourData, wxObject) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxColourData -// ---------------------------------------------------------------------------- - -wxColourData::wxColourData() -{ - m_chooseFull = false; - m_dataColour.Set(0,0,0); - // m_custColours are wxNullColours initially -} - -wxColourData::wxColourData(const wxColourData& data) - : wxObject() -{ - (*this) = data; -} - -wxColourData::~wxColourData() -{ -} - -void wxColourData::SetCustomColour(int i, const wxColour& colour) -{ - wxCHECK_RET( (i >= 0 && i < 16), _T("custom colour index out of range") ); - - m_custColours[i] = colour; -} - -wxColour wxColourData::GetCustomColour(int i) -{ - wxCHECK_MSG( (i >= 0 && i < 16), wxColour(0,0,0), - _T("custom colour index out of range") ); - - return m_custColours[i]; -} - -void wxColourData::operator=(const wxColourData& data) -{ - int i; - for (i = 0; i < 16; i++) - m_custColours[i] = data.m_custColours[i]; - - m_dataColour = (wxColour&)data.m_dataColour; - m_chooseFull = data.m_chooseFull; -} - -// ---------------------------------------------------------------------------- -// Font data -// ---------------------------------------------------------------------------- - -wxFontData::wxFontData() -{ - // Intialize colour to black. - m_fontColour = wxNullColour; - - m_showHelp = false; - m_allowSymbols = true; - m_enableEffects = true; - m_minSize = 0; - m_maxSize = 0; - - m_encoding = wxFONTENCODING_SYSTEM; -} - -wxFontData::~wxFontData() -{ -} - -#if wxUSE_FONTDLG - -wxFontDialogBase::~wxFontDialogBase() -{ -} - -#endif // wxUSE_FONTDLG - -#if wxUSE_PRINTING_ARCHITECTURE -// ---------------------------------------------------------------------------- -// Print data -// ---------------------------------------------------------------------------- - -wxPrintData::wxPrintData() -{ - m_bin = wxPRINTBIN_DEFAULT; - m_media = wxPRINTMEDIA_DEFAULT; - m_printMode = wxPRINT_MODE_PRINTER; - m_printOrientation = wxPORTRAIT; - m_printOrientationReversed = false; - m_printNoCopies = 1; - m_printCollate = false; - - // New, 24/3/99 - m_printerName = wxEmptyString; - m_colour = true; - m_duplexMode = wxDUPLEX_SIMPLEX; - m_printQuality = wxPRINT_QUALITY_HIGH; - - // we intentionally don't initialize paper id and size at all, like this - // the default system settings will be used for them - m_paperId = wxPAPER_NONE; - m_paperSize = wxDefaultSize; - - m_privData = NULL; - m_privDataLen = 0; - - m_nativeData = wxPrintFactory::GetFactory()->CreatePrintNativeData(); -} - -wxPrintData::wxPrintData(const wxPrintData& printData) - : wxObject() -{ - m_nativeData = NULL; - m_privData = NULL; - (*this) = printData; -} - -void wxPrintData::SetPrivData( char *privData, int len ) -{ - if (m_privData) - { - delete [] m_privData; - m_privData = NULL; - } - m_privDataLen = len; - if (m_privDataLen > 0) - { - m_privData = new char[m_privDataLen]; - memcpy( m_privData, privData, m_privDataLen ); - } -} - -wxPrintData::~wxPrintData() -{ - m_nativeData->m_ref--; - if (m_nativeData->m_ref == 0) - delete m_nativeData; - - if (m_privData) - delete [] m_privData; -} - -void wxPrintData::ConvertToNative() -{ - m_nativeData->TransferFrom( *this ) ; -} - -void wxPrintData::ConvertFromNative() -{ - m_nativeData->TransferTo( *this ) ; -} - -void wxPrintData::operator=(const wxPrintData& data) -{ - m_printNoCopies = data.m_printNoCopies; - m_printCollate = data.m_printCollate; - m_printOrientation = data.m_printOrientation; - m_printOrientationReversed = data.m_printOrientationReversed; - m_printerName = data.m_printerName; - m_colour = data.m_colour; - m_duplexMode = data.m_duplexMode; - m_printQuality = data.m_printQuality; - m_paperId = data.m_paperId; - m_paperSize = data.m_paperSize; - m_bin = data.m_bin; - m_media = data.m_media; - m_printMode = data.m_printMode; - m_filename = data.m_filename; - - // UnRef old m_nativeData - if (m_nativeData) - { - m_nativeData->m_ref--; - if (m_nativeData->m_ref == 0) - delete m_nativeData; - } - // Set Ref new one - m_nativeData = data.GetNativeData(); - m_nativeData->m_ref++; - - if (m_privData) - { - delete [] m_privData; - m_privData = NULL; - } - m_privDataLen = data.GetPrivDataLen(); - if (m_privDataLen > 0) - { - m_privData = new char[m_privDataLen]; - memcpy( m_privData, data.GetPrivData(), m_privDataLen ); - } -} - -// Is this data OK for showing the print dialog? -bool wxPrintData::IsOk() const -{ - m_nativeData->TransferFrom( *this ); - - return m_nativeData->Ok(); -} - -// What should happen here? wxPostScriptPrintNativeData is not -// defined unless all this is true on MSW. -#if WXWIN_COMPATIBILITY_2_4 && wxUSE_PRINTING_ARCHITECTURE && (!defined(__WXMSW__) || wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW) - -#include "wx/generic/prntdlgg.h" - -#if wxUSE_POSTSCRIPT - #define WXUNUSED_WITHOUT_PS(name) name -#else - #define WXUNUSED_WITHOUT_PS(name) WXUNUSED(name) -#endif - -wxString wxPrintData::GetPrinterCommand() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterCommand(); -#endif - return wxEmptyString; -} - -wxString wxPrintData::GetPrinterOptions() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterOptions(); -#endif - return wxEmptyString; -} - -wxString wxPrintData::GetPreviewCommand() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPreviewCommand(); -#endif - return wxEmptyString; -} - -wxString wxPrintData::GetFontMetricPath() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetFontMetricPath(); -#endif - return wxEmptyString; -} - -double wxPrintData::GetPrinterScaleX() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterScaleX(); -#endif - return 1.0; -} - -double wxPrintData::GetPrinterScaleY() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterScaleY(); -#endif - return 1.0; -} - -long wxPrintData::GetPrinterTranslateX() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterTranslateX(); -#endif - return 0; -} - -long wxPrintData::GetPrinterTranslateY() const -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterTranslateY(); -#endif - return 0; -} - -void wxPrintData::SetPrinterCommand(const wxString& WXUNUSED_WITHOUT_PS(command)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterCommand( command ); -#endif -} - -void wxPrintData::SetPrinterOptions(const wxString& WXUNUSED_WITHOUT_PS(options)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterOptions( options ); -#endif -} - -void wxPrintData::SetPreviewCommand(const wxString& WXUNUSED_WITHOUT_PS(command)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPreviewCommand( command ); -#endif -} - -void wxPrintData::SetFontMetricPath(const wxString& WXUNUSED_WITHOUT_PS(path)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetFontMetricPath( path ); -#endif -} - -void wxPrintData::SetPrinterScaleX(double WXUNUSED_WITHOUT_PS(x)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterScaleX( x ); -#endif -} - -void wxPrintData::SetPrinterScaleY(double WXUNUSED_WITHOUT_PS(y)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterScaleY( y ); -#endif -} - -void wxPrintData::SetPrinterScaling(double WXUNUSED_WITHOUT_PS(x), double WXUNUSED_WITHOUT_PS(y)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterScaling( x, y ); -#endif -} - -void wxPrintData::SetPrinterTranslateX(long WXUNUSED_WITHOUT_PS(x)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterTranslateX( x ); -#endif -} - -void wxPrintData::SetPrinterTranslateY(long WXUNUSED_WITHOUT_PS(y)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterTranslateY( y ); -#endif -} - -void wxPrintData::SetPrinterTranslation(long WXUNUSED_WITHOUT_PS(x), long WXUNUSED_WITHOUT_PS(y)) -{ -#if wxUSE_POSTSCRIPT - if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) - ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterTranslation( x, y ); -#endif -} -#endif - -// ---------------------------------------------------------------------------- -// Print dialog data -// ---------------------------------------------------------------------------- - -wxPrintDialogData::wxPrintDialogData() -{ - m_printFromPage = 0; - m_printToPage = 0; - m_printMinPage = 0; - m_printMaxPage = 0; - m_printNoCopies = 1; - m_printAllPages = false; - m_printCollate = false; - m_printToFile = false; - m_printSelection = false; - m_printEnableSelection = false; - m_printEnablePageNumbers = true; - - wxPrintFactory* factory = wxPrintFactory::GetFactory(); - m_printEnablePrintToFile = ! factory->HasOwnPrintToFile(); - - m_printEnableHelp = false; -#if WXWIN_COMPATIBILITY_2_4 - m_printSetupDialog = false; -#endif -} - -wxPrintDialogData::wxPrintDialogData(const wxPrintDialogData& dialogData) - : wxObject() -{ - (*this) = dialogData; -} - -wxPrintDialogData::wxPrintDialogData(const wxPrintData& printData) -{ - m_printFromPage = 1; - m_printToPage = 0; - m_printMinPage = 1; - m_printMaxPage = 9999; - m_printNoCopies = 1; - m_printAllPages = false; - m_printCollate = false; - m_printToFile = false; - m_printSelection = false; - m_printEnableSelection = false; - m_printEnablePageNumbers = true; - m_printEnablePrintToFile = true; - m_printEnableHelp = false; -#if WXWIN_COMPATIBILITY_2_4 - m_printSetupDialog = false; -#endif - m_printData = printData; -} - -wxPrintDialogData::~wxPrintDialogData() -{ -} - -void wxPrintDialogData::operator=(const wxPrintDialogData& data) -{ - m_printFromPage = data.m_printFromPage; - m_printToPage = data.m_printToPage; - m_printMinPage = data.m_printMinPage; - m_printMaxPage = data.m_printMaxPage; - m_printNoCopies = data.m_printNoCopies; - m_printAllPages = data.m_printAllPages; - m_printCollate = data.m_printCollate; - m_printToFile = data.m_printToFile; - m_printSelection = data.m_printSelection; - m_printEnableSelection = data.m_printEnableSelection; - m_printEnablePageNumbers = data.m_printEnablePageNumbers; - m_printEnableHelp = data.m_printEnableHelp; - m_printEnablePrintToFile = data.m_printEnablePrintToFile; -#if WXWIN_COMPATIBILITY_2_4 - m_printSetupDialog = data.m_printSetupDialog; -#endif - m_printData = data.m_printData; -} - -void wxPrintDialogData::operator=(const wxPrintData& data) -{ - m_printData = data; -} - -// ---------------------------------------------------------------------------- -// wxPageSetupDialogData -// ---------------------------------------------------------------------------- - -wxPageSetupDialogData::wxPageSetupDialogData() -{ - m_paperSize = wxSize(0,0); - - CalculatePaperSizeFromId(); - - m_minMarginTopLeft = - m_minMarginBottomRight = - m_marginTopLeft = - m_marginBottomRight = wxPoint(0,0); - - // Flags - m_defaultMinMargins = false; - m_enableMargins = true; - m_enableOrientation = true; - m_enablePaper = true; - m_enablePrinter = true; - m_enableHelp = false; - m_getDefaultInfo = false; -} - -wxPageSetupDialogData::wxPageSetupDialogData(const wxPageSetupDialogData& dialogData) - : wxObject() -{ - (*this) = dialogData; -} - -wxPageSetupDialogData::wxPageSetupDialogData(const wxPrintData& printData) -{ - m_paperSize = wxSize(0,0); - m_minMarginTopLeft = - m_minMarginBottomRight = - m_marginTopLeft = - m_marginBottomRight = wxPoint(0,0); - - // Flags - m_defaultMinMargins = false; - m_enableMargins = true; - m_enableOrientation = true; - m_enablePaper = true; - m_enablePrinter = true; - m_enableHelp = false; - m_getDefaultInfo = false; - - m_printData = printData; - - // The wxPrintData paper size overrides these values, unless the size cannot - // be found. - CalculatePaperSizeFromId(); -} - -wxPageSetupDialogData::~wxPageSetupDialogData() -{ -} - -wxPageSetupDialogData& wxPageSetupDialogData::operator=(const wxPageSetupDialogData& data) -{ - m_paperSize = data.m_paperSize; - m_minMarginTopLeft = data.m_minMarginTopLeft; - m_minMarginBottomRight = data.m_minMarginBottomRight; - m_marginTopLeft = data.m_marginTopLeft; - m_marginBottomRight = data.m_marginBottomRight; - m_defaultMinMargins = data.m_defaultMinMargins; - m_enableMargins = data.m_enableMargins; - m_enableOrientation = data.m_enableOrientation; - m_enablePaper = data.m_enablePaper; - m_enablePrinter = data.m_enablePrinter; - m_getDefaultInfo = data.m_getDefaultInfo; - m_enableHelp = data.m_enableHelp; - - m_printData = data.m_printData; - - return *this; -} - -wxPageSetupDialogData& wxPageSetupDialogData::operator=(const wxPrintData& data) -{ - m_printData = data; - CalculatePaperSizeFromId(); - - return *this; -} - -// If a corresponding paper type is found in the paper database, will set the m_printData -// paper size id member as well. -void wxPageSetupDialogData::SetPaperSize(const wxSize& sz) -{ - m_paperSize = sz; - - CalculateIdFromPaperSize(); -} - -// Sets the wxPrintData id, plus the paper width/height if found in the paper database. -void wxPageSetupDialogData::SetPaperSize(wxPaperSize id) -{ - m_printData.SetPaperId(id); - - CalculatePaperSizeFromId(); -} - -void wxPageSetupDialogData::SetPrintData(const wxPrintData& printData) -{ - m_printData = printData; - CalculatePaperSizeFromId(); -} - -// Use paper size defined in this object to set the wxPrintData -// paper id -void wxPageSetupDialogData::CalculateIdFromPaperSize() -{ - wxASSERT_MSG( (wxThePrintPaperDatabase != (wxPrintPaperDatabase*) NULL), - wxT("wxThePrintPaperDatabase should not be NULL. Do not create global print dialog data objects.") ); - - wxSize sz = GetPaperSize(); - - wxPaperSize id = wxThePrintPaperDatabase->GetSize(wxSize(sz.x* 10, sz.y * 10)); - if (id != wxPAPER_NONE) - { - m_printData.SetPaperId(id); - } -} - -// Use paper id in wxPrintData to set this object's paper size -void wxPageSetupDialogData::CalculatePaperSizeFromId() -{ - wxASSERT_MSG( (wxThePrintPaperDatabase != (wxPrintPaperDatabase*) NULL), - wxT("wxThePrintPaperDatabase should not be NULL. Do not create global print dialog data objects.") ); - - wxSize sz = wxThePrintPaperDatabase->GetSize(m_printData.GetPaperId()); - - if (sz != wxSize(0, 0)) - { - // sz is in 10ths of a mm, while paper size is in mm - m_paperSize.x = sz.x / 10; - m_paperSize.y = sz.y / 10; - } -} - -#endif // wxUSE_PRINTING_ARCHITECTURE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/cmndata.cpp +// Purpose: Common GDI data +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id: cmndata.cpp 60700 2009-05-20 13:18:11Z JS $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/cmndata.h" + +#ifndef WX_PRECOMP + #if defined(__WXMSW__) + #include "wx/msw/wrapcdlg.h" + #endif // MSW + #include + #include "wx/string.h" + #include "wx/utils.h" + #include "wx/app.h" + #include "wx/log.h" + #include "wx/gdicmn.h" +#endif + +#include "wx/prntbase.h" +#include "wx/printdlg.h" + +#if wxUSE_FONTDLG + #include "wx/fontdlg.h" +#endif // wxUSE_FONTDLG + +#if wxUSE_PRINTING_ARCHITECTURE + +#include "wx/paper.h" + +#if defined(__WXMAC__) + #include "wx/mac/private/print.h" +#endif + +IMPLEMENT_DYNAMIC_CLASS(wxPrintData, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxPrintDialogData, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxPageSetupDialogData, wxObject) + +#endif // wxUSE_PRINTING_ARCHITECTURE + +IMPLEMENT_DYNAMIC_CLASS(wxFontData, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxColourData, wxObject) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxColourData +// ---------------------------------------------------------------------------- + +wxColourData::wxColourData() +{ + m_chooseFull = false; + m_dataColour.Set(0,0,0); + // m_custColours are wxNullColours initially +} + +wxColourData::wxColourData(const wxColourData& data) + : wxObject() +{ + (*this) = data; +} + +wxColourData::~wxColourData() +{ +} + +void wxColourData::SetCustomColour(int i, const wxColour& colour) +{ + wxCHECK_RET( (i >= 0 && i < 16), _T("custom colour index out of range") ); + + m_custColours[i] = colour; +} + +wxColour wxColourData::GetCustomColour(int i) +{ + wxCHECK_MSG( (i >= 0 && i < 16), wxColour(0,0,0), + _T("custom colour index out of range") ); + + return m_custColours[i]; +} + +void wxColourData::operator=(const wxColourData& data) +{ + int i; + for (i = 0; i < 16; i++) + m_custColours[i] = data.m_custColours[i]; + + m_dataColour = (wxColour&)data.m_dataColour; + m_chooseFull = data.m_chooseFull; +} + +// ---------------------------------------------------------------------------- +// Font data +// ---------------------------------------------------------------------------- + +wxFontData::wxFontData() +{ + // Intialize colour to black. + m_fontColour = wxNullColour; + + m_showHelp = false; + m_allowSymbols = true; + m_enableEffects = true; + m_minSize = 0; + m_maxSize = 0; + + m_encoding = wxFONTENCODING_SYSTEM; +} + +wxFontData::~wxFontData() +{ +} + +#if wxUSE_FONTDLG + +wxFontDialogBase::~wxFontDialogBase() +{ +} + +#endif // wxUSE_FONTDLG + +#if wxUSE_PRINTING_ARCHITECTURE +// ---------------------------------------------------------------------------- +// Print data +// ---------------------------------------------------------------------------- + +wxPrintData::wxPrintData() +{ + m_bin = wxPRINTBIN_DEFAULT; + m_media = wxPRINTMEDIA_DEFAULT; + m_printMode = wxPRINT_MODE_PRINTER; + m_printOrientation = wxPORTRAIT; + m_printOrientationReversed = false; + m_printNoCopies = 1; + m_printCollate = false; + + // New, 24/3/99 + m_printerName = wxEmptyString; + m_colour = true; + m_duplexMode = wxDUPLEX_SIMPLEX; + m_printQuality = wxPRINT_QUALITY_HIGH; + + // we intentionally don't initialize paper id and size at all, like this + // the default system settings will be used for them + m_paperId = wxPAPER_NONE; + m_paperSize = wxDefaultSize; + + m_privData = NULL; + m_privDataLen = 0; + + m_nativeData = wxPrintFactory::GetFactory()->CreatePrintNativeData(); +} + +wxPrintData::wxPrintData(const wxPrintData& printData) + : wxObject() +{ + m_nativeData = NULL; + m_privData = NULL; + (*this) = printData; +} + +void wxPrintData::SetPrivData( char *privData, int len ) +{ + if (m_privData) + { + delete [] m_privData; + m_privData = NULL; + } + m_privDataLen = len; + if (m_privDataLen > 0) + { + m_privData = new char[m_privDataLen]; + memcpy( m_privData, privData, m_privDataLen ); + } +} + +wxPrintData::~wxPrintData() +{ + m_nativeData->m_ref--; + if (m_nativeData->m_ref == 0) + delete m_nativeData; + + if (m_privData) + delete [] m_privData; +} + +void wxPrintData::ConvertToNative() +{ + m_nativeData->TransferFrom( *this ) ; +} + +void wxPrintData::ConvertFromNative() +{ + m_nativeData->TransferTo( *this ) ; +} + +void wxPrintData::operator=(const wxPrintData& data) +{ + m_printNoCopies = data.m_printNoCopies; + m_printCollate = data.m_printCollate; + m_printOrientation = data.m_printOrientation; + m_printOrientationReversed = data.m_printOrientationReversed; + m_printerName = data.m_printerName; + m_colour = data.m_colour; + m_duplexMode = data.m_duplexMode; + m_printQuality = data.m_printQuality; + m_paperId = data.m_paperId; + m_paperSize = data.m_paperSize; + m_bin = data.m_bin; + m_media = data.m_media; + m_printMode = data.m_printMode; + m_filename = data.m_filename; + + // UnRef old m_nativeData + if (m_nativeData) + { + m_nativeData->m_ref--; + if (m_nativeData->m_ref == 0) + delete m_nativeData; + } + // Set Ref new one + m_nativeData = data.GetNativeData(); + m_nativeData->m_ref++; + + if (m_privData) + { + delete [] m_privData; + m_privData = NULL; + } + m_privDataLen = data.GetPrivDataLen(); + if (m_privDataLen > 0) + { + m_privData = new char[m_privDataLen]; + memcpy( m_privData, data.GetPrivData(), m_privDataLen ); + } +} + +// Is this data OK for showing the print dialog? +bool wxPrintData::IsOk() const +{ + m_nativeData->TransferFrom( *this ); + + return m_nativeData->Ok(); +} + +// What should happen here? wxPostScriptPrintNativeData is not +// defined unless all this is true on MSW. +#if WXWIN_COMPATIBILITY_2_4 && wxUSE_PRINTING_ARCHITECTURE && (!defined(__WXMSW__) || wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW) + +#include "wx/generic/prntdlgg.h" + +#if wxUSE_POSTSCRIPT + #define WXUNUSED_WITHOUT_PS(name) name +#else + #define WXUNUSED_WITHOUT_PS(name) WXUNUSED(name) +#endif + +wxString wxPrintData::GetPrinterCommand() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterCommand(); +#endif + return wxEmptyString; +} + +wxString wxPrintData::GetPrinterOptions() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterOptions(); +#endif + return wxEmptyString; +} + +wxString wxPrintData::GetPreviewCommand() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPreviewCommand(); +#endif + return wxEmptyString; +} + +wxString wxPrintData::GetFontMetricPath() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetFontMetricPath(); +#endif + return wxEmptyString; +} + +double wxPrintData::GetPrinterScaleX() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterScaleX(); +#endif + return 1.0; +} + +double wxPrintData::GetPrinterScaleY() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterScaleY(); +#endif + return 1.0; +} + +long wxPrintData::GetPrinterTranslateX() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterTranslateX(); +#endif + return 0; +} + +long wxPrintData::GetPrinterTranslateY() const +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + return ((wxPostScriptPrintNativeData*)m_nativeData)->GetPrinterTranslateY(); +#endif + return 0; +} + +void wxPrintData::SetPrinterCommand(const wxString& WXUNUSED_WITHOUT_PS(command)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterCommand( command ); +#endif +} + +void wxPrintData::SetPrinterOptions(const wxString& WXUNUSED_WITHOUT_PS(options)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterOptions( options ); +#endif +} + +void wxPrintData::SetPreviewCommand(const wxString& WXUNUSED_WITHOUT_PS(command)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPreviewCommand( command ); +#endif +} + +void wxPrintData::SetFontMetricPath(const wxString& WXUNUSED_WITHOUT_PS(path)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetFontMetricPath( path ); +#endif +} + +void wxPrintData::SetPrinterScaleX(double WXUNUSED_WITHOUT_PS(x)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterScaleX( x ); +#endif +} + +void wxPrintData::SetPrinterScaleY(double WXUNUSED_WITHOUT_PS(y)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterScaleY( y ); +#endif +} + +void wxPrintData::SetPrinterScaling(double WXUNUSED_WITHOUT_PS(x), double WXUNUSED_WITHOUT_PS(y)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterScaling( x, y ); +#endif +} + +void wxPrintData::SetPrinterTranslateX(long WXUNUSED_WITHOUT_PS(x)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterTranslateX( x ); +#endif +} + +void wxPrintData::SetPrinterTranslateY(long WXUNUSED_WITHOUT_PS(y)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterTranslateY( y ); +#endif +} + +void wxPrintData::SetPrinterTranslation(long WXUNUSED_WITHOUT_PS(x), long WXUNUSED_WITHOUT_PS(y)) +{ +#if wxUSE_POSTSCRIPT + if (m_nativeData && wxIsKindOf(m_nativeData,wxPostScriptPrintNativeData)) + ((wxPostScriptPrintNativeData*)m_nativeData)->SetPrinterTranslation( x, y ); +#endif +} +#endif + +// ---------------------------------------------------------------------------- +// Print dialog data +// ---------------------------------------------------------------------------- + +wxPrintDialogData::wxPrintDialogData() +{ + m_printFromPage = 0; + m_printToPage = 0; + m_printMinPage = 0; + m_printMaxPage = 0; + m_printNoCopies = 1; + m_printAllPages = false; + m_printCollate = false; + m_printToFile = false; + m_printSelection = false; + m_printEnableSelection = false; + m_printEnablePageNumbers = true; + + wxPrintFactory* factory = wxPrintFactory::GetFactory(); + m_printEnablePrintToFile = ! factory->HasOwnPrintToFile(); + + m_printEnableHelp = false; +#if WXWIN_COMPATIBILITY_2_4 + m_printSetupDialog = false; +#endif +} + +wxPrintDialogData::wxPrintDialogData(const wxPrintDialogData& dialogData) + : wxObject() +{ + (*this) = dialogData; +} + +wxPrintDialogData::wxPrintDialogData(const wxPrintData& printData) +{ + m_printFromPage = 1; + m_printToPage = 0; + m_printMinPage = 1; + m_printMaxPage = 9999; + m_printNoCopies = 1; + m_printAllPages = false; + m_printCollate = false; + m_printToFile = false; + m_printSelection = false; + m_printEnableSelection = false; + m_printEnablePageNumbers = true; + m_printEnablePrintToFile = true; + m_printEnableHelp = false; +#if WXWIN_COMPATIBILITY_2_4 + m_printSetupDialog = false; +#endif + m_printData = printData; +} + +wxPrintDialogData::~wxPrintDialogData() +{ +} + +void wxPrintDialogData::operator=(const wxPrintDialogData& data) +{ + m_printFromPage = data.m_printFromPage; + m_printToPage = data.m_printToPage; + m_printMinPage = data.m_printMinPage; + m_printMaxPage = data.m_printMaxPage; + m_printNoCopies = data.m_printNoCopies; + m_printAllPages = data.m_printAllPages; + m_printCollate = data.m_printCollate; + m_printToFile = data.m_printToFile; + m_printSelection = data.m_printSelection; + m_printEnableSelection = data.m_printEnableSelection; + m_printEnablePageNumbers = data.m_printEnablePageNumbers; + m_printEnableHelp = data.m_printEnableHelp; + m_printEnablePrintToFile = data.m_printEnablePrintToFile; +#if WXWIN_COMPATIBILITY_2_4 + m_printSetupDialog = data.m_printSetupDialog; +#endif + m_printData = data.m_printData; +} + +void wxPrintDialogData::operator=(const wxPrintData& data) +{ + m_printData = data; +} + +// ---------------------------------------------------------------------------- +// wxPageSetupDialogData +// ---------------------------------------------------------------------------- + +wxPageSetupDialogData::wxPageSetupDialogData() +{ + m_paperSize = wxSize(0,0); + + CalculatePaperSizeFromId(); + + m_minMarginTopLeft = + m_minMarginBottomRight = + m_marginTopLeft = + m_marginBottomRight = wxPoint(0,0); + + // Flags + m_defaultMinMargins = false; + m_enableMargins = true; + m_enableOrientation = true; + m_enablePaper = true; + m_enablePrinter = true; + m_enableHelp = false; + m_getDefaultInfo = false; +} + +wxPageSetupDialogData::wxPageSetupDialogData(const wxPageSetupDialogData& dialogData) + : wxObject() +{ + (*this) = dialogData; +} + +wxPageSetupDialogData::wxPageSetupDialogData(const wxPrintData& printData) +{ + m_paperSize = wxSize(0,0); + m_minMarginTopLeft = + m_minMarginBottomRight = + m_marginTopLeft = + m_marginBottomRight = wxPoint(0,0); + + // Flags + m_defaultMinMargins = false; + m_enableMargins = true; + m_enableOrientation = true; + m_enablePaper = true; + m_enablePrinter = true; + m_enableHelp = false; + m_getDefaultInfo = false; + + m_printData = printData; + + // The wxPrintData paper size overrides these values, unless the size cannot + // be found. + CalculatePaperSizeFromId(); +} + +wxPageSetupDialogData::~wxPageSetupDialogData() +{ +} + +wxPageSetupDialogData& wxPageSetupDialogData::operator=(const wxPageSetupDialogData& data) +{ + m_paperSize = data.m_paperSize; + m_minMarginTopLeft = data.m_minMarginTopLeft; + m_minMarginBottomRight = data.m_minMarginBottomRight; + m_marginTopLeft = data.m_marginTopLeft; + m_marginBottomRight = data.m_marginBottomRight; + m_defaultMinMargins = data.m_defaultMinMargins; + m_enableMargins = data.m_enableMargins; + m_enableOrientation = data.m_enableOrientation; + m_enablePaper = data.m_enablePaper; + m_enablePrinter = data.m_enablePrinter; + m_getDefaultInfo = data.m_getDefaultInfo; + m_enableHelp = data.m_enableHelp; + + m_printData = data.m_printData; + + return *this; +} + +wxPageSetupDialogData& wxPageSetupDialogData::operator=(const wxPrintData& data) +{ + m_printData = data; + CalculatePaperSizeFromId(); + + return *this; +} + +// If a corresponding paper type is found in the paper database, will set the m_printData +// paper size id member as well. +void wxPageSetupDialogData::SetPaperSize(const wxSize& sz) +{ + m_paperSize = sz; + + CalculateIdFromPaperSize(); +} + +// Sets the wxPrintData id, plus the paper width/height if found in the paper database. +void wxPageSetupDialogData::SetPaperSize(wxPaperSize id) +{ + m_printData.SetPaperId(id); + + CalculatePaperSizeFromId(); +} + +void wxPageSetupDialogData::SetPrintData(const wxPrintData& printData) +{ + m_printData = printData; + CalculatePaperSizeFromId(); +} + +// Use paper size defined in this object to set the wxPrintData +// paper id +void wxPageSetupDialogData::CalculateIdFromPaperSize() +{ + wxASSERT_MSG( (wxThePrintPaperDatabase != (wxPrintPaperDatabase*) NULL), + wxT("wxThePrintPaperDatabase should not be NULL. Do not create global print dialog data objects.") ); + + wxSize sz = GetPaperSize(); + + wxPaperSize id = wxThePrintPaperDatabase->GetSize(wxSize(sz.x* 10, sz.y * 10)); + if (id != wxPAPER_NONE) + { + m_printData.SetPaperId(id); + } +} + +// Use paper id in wxPrintData to set this object's paper size +void wxPageSetupDialogData::CalculatePaperSizeFromId() +{ + wxASSERT_MSG( (wxThePrintPaperDatabase != (wxPrintPaperDatabase*) NULL), + wxT("wxThePrintPaperDatabase should not be NULL. Do not create global print dialog data objects.") ); + + wxSize sz = wxThePrintPaperDatabase->GetSize(m_printData.GetPaperId()); + + if (sz != wxSize(0, 0)) + { + // sz is in 10ths of a mm, while paper size is in mm + m_paperSize.x = sz.x / 10; + m_paperSize.y = sz.y / 10; + } +} + +#endif // wxUSE_PRINTING_ARCHITECTURE diff --git a/Source/3rd Party/wx/src/common/colourcmn.cpp b/Source/3rd Party/wx/src/common/colourcmn.cpp index 0bd34c8c9..5851dfcdf 100644 --- a/Source/3rd Party/wx/src/common/colourcmn.cpp +++ b/Source/3rd Party/wx/src/common/colourcmn.cpp @@ -1,126 +1,126 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/colourcmn.cpp -// Purpose: wxColourBase implementation -// Author: Francesco Montorsi -// Modified by: -// Created: 20/4/2006 -// RCS-ID: $Id: colourcmn.cpp 41538 2006-09-30 20:45:15Z RR $ -// Copyright: (c) Francesco Montorsi -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/colour.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/utils.h" - #include "wx/gdicmn.h" -#endif - -#if wxUSE_VARIANT -IMPLEMENT_VARIANT_OBJECT_EXPORTED(wxColour,WXDLLEXPORT) -#endif - -// ============================================================================ -// wxString <-> wxColour conversions -// ============================================================================ - -bool wxColourBase::FromString(const wxChar *str) -{ - if ( str == NULL || str[0] == wxT('\0')) - return false; // invalid or empty string - - if ( wxStrncmp(str, wxT("RGB"), 3) == 0 || - wxStrncmp(str, wxT("rgb"), 3) == 0 ) - { - // CSS-like RGB specification - // according to http://www.w3.org/TR/REC-CSS2/syndata.html#color-units - // values outside 0-255 range are allowed but should be clipped - int red, green, blue; - if (wxSscanf(&str[3], wxT("(%d, %d, %d)"), &red, &green, &blue) != 3) - return false; - - Set((unsigned char)wxClip(red,0,255), - (unsigned char)wxClip(green,0,255), - (unsigned char)wxClip(blue,0,255)); - } - else if ( str[0] == wxT('#') && wxStrlen(str) == 7 ) - { - // hexadecimal prefixed with # (HTML syntax) - unsigned long tmp; - if (wxSscanf(&str[1], wxT("%lx"), &tmp) != 1) - return false; - - Set((unsigned char)(tmp >> 16), - (unsigned char)(tmp >> 8), - (unsigned char)tmp); - } - else if (wxTheColourDatabase) // a colour name ? - { - // we can't do - // *this = wxTheColourDatabase->Find(str) - // because this place can be called from constructor - // and 'this' could not be available yet - wxColour clr = wxTheColourDatabase->Find(str); - if (clr.Ok()) - Set((unsigned char)clr.Red(), - (unsigned char)clr.Green(), - (unsigned char)clr.Blue()); - } - - if (Ok()) - return true; - - wxLogDebug(wxT("wxColour::Set - couldn't set to colour string '%s'"), str); - return false; -} - -wxString wxColourBase::GetAsString(long flags) const -{ - wxString colName; - - if (flags & wxC2S_NAME) - colName = wxTheColourDatabase->FindName((const wxColour &)(*this)).MakeLower(); - - if ( colName.empty() && (flags & wxC2S_CSS_SYNTAX) ) - { - // no name for this colour; return it in CSS syntax - colName.Printf(wxT("rgb(%d, %d, %d)"), - Red(), Green(), Blue()); - } - else if ( colName.empty() && (flags & wxC2S_HTML_SYNTAX) ) - { - // no name for this colour; return it in HTML syntax - colName.Printf(wxT("#%02X%02X%02X"), - Red(), Green(), Blue()); - } - - // this function always returns a non-empty string - wxASSERT_MSG(!colName.empty(), - wxT("Invalid wxColour -> wxString conversion flags")); - - return colName; -} - -#if WXWIN_COMPATIBILITY_2_6 - -// static -wxColour wxColourBase::CreateByName(const wxString& name) -{ - return wxColour(name); -} - -void wxColourBase::InitFromName(const wxString& col) -{ - Set(col); -} - -#endif // WXWIN_COMPATIBILITY_2_6 +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/colourcmn.cpp +// Purpose: wxColourBase implementation +// Author: Francesco Montorsi +// Modified by: +// Created: 20/4/2006 +// RCS-ID: $Id: colourcmn.cpp 41538 2006-09-30 20:45:15Z RR $ +// Copyright: (c) Francesco Montorsi +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/colour.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/utils.h" + #include "wx/gdicmn.h" +#endif + +#if wxUSE_VARIANT +IMPLEMENT_VARIANT_OBJECT_EXPORTED(wxColour,WXDLLEXPORT) +#endif + +// ============================================================================ +// wxString <-> wxColour conversions +// ============================================================================ + +bool wxColourBase::FromString(const wxChar *str) +{ + if ( str == NULL || str[0] == wxT('\0')) + return false; // invalid or empty string + + if ( wxStrncmp(str, wxT("RGB"), 3) == 0 || + wxStrncmp(str, wxT("rgb"), 3) == 0 ) + { + // CSS-like RGB specification + // according to http://www.w3.org/TR/REC-CSS2/syndata.html#color-units + // values outside 0-255 range are allowed but should be clipped + int red, green, blue; + if (wxSscanf(&str[3], wxT("(%d, %d, %d)"), &red, &green, &blue) != 3) + return false; + + Set((unsigned char)wxClip(red,0,255), + (unsigned char)wxClip(green,0,255), + (unsigned char)wxClip(blue,0,255)); + } + else if ( str[0] == wxT('#') && wxStrlen(str) == 7 ) + { + // hexadecimal prefixed with # (HTML syntax) + unsigned long tmp; + if (wxSscanf(&str[1], wxT("%lx"), &tmp) != 1) + return false; + + Set((unsigned char)(tmp >> 16), + (unsigned char)(tmp >> 8), + (unsigned char)tmp); + } + else if (wxTheColourDatabase) // a colour name ? + { + // we can't do + // *this = wxTheColourDatabase->Find(str) + // because this place can be called from constructor + // and 'this' could not be available yet + wxColour clr = wxTheColourDatabase->Find(str); + if (clr.Ok()) + Set((unsigned char)clr.Red(), + (unsigned char)clr.Green(), + (unsigned char)clr.Blue()); + } + + if (Ok()) + return true; + + wxLogDebug(wxT("wxColour::Set - couldn't set to colour string '%s'"), str); + return false; +} + +wxString wxColourBase::GetAsString(long flags) const +{ + wxString colName; + + if (flags & wxC2S_NAME) + colName = wxTheColourDatabase->FindName((const wxColour &)(*this)).MakeLower(); + + if ( colName.empty() && (flags & wxC2S_CSS_SYNTAX) ) + { + // no name for this colour; return it in CSS syntax + colName.Printf(wxT("rgb(%d, %d, %d)"), + Red(), Green(), Blue()); + } + else if ( colName.empty() && (flags & wxC2S_HTML_SYNTAX) ) + { + // no name for this colour; return it in HTML syntax + colName.Printf(wxT("#%02X%02X%02X"), + Red(), Green(), Blue()); + } + + // this function always returns a non-empty string + wxASSERT_MSG(!colName.empty(), + wxT("Invalid wxColour -> wxString conversion flags")); + + return colName; +} + +#if WXWIN_COMPATIBILITY_2_6 + +// static +wxColour wxColourBase::CreateByName(const wxString& name) +{ + return wxColour(name); +} + +void wxColourBase::InitFromName(const wxString& col) +{ + Set(col); +} + +#endif // WXWIN_COMPATIBILITY_2_6 diff --git a/Source/3rd Party/wx/src/common/combocmn.cpp b/Source/3rd Party/wx/src/common/combocmn.cpp index 4e67f32ea..f67061a3c 100644 --- a/Source/3rd Party/wx/src/common/combocmn.cpp +++ b/Source/3rd Party/wx/src/common/combocmn.cpp @@ -1,2340 +1,2340 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/combocmn.cpp -// Purpose: wxComboCtrlBase -// Author: Jaakko Salli -// Modified by: -// Created: Apr-30-2006 -// RCS-ID: $Id: combocmn.cpp 67178 2011-03-13 09:32:19Z JMS $ -// Copyright: (c) 2005 Jaakko Salli -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_COMBOCTRL - -#include "wx/combobox.h" - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/log.h" - #include "wx/dcclient.h" - #include "wx/settings.h" - #include "wx/dialog.h" - #include "wx/timer.h" -#endif - -#include "wx/tooltip.h" - -#include "wx/combo.h" - - - -// constants -// ---------------------------------------------------------------------------- - -#define DEFAULT_DROPBUTTON_WIDTH 19 - -#define BMP_BUTTON_MARGIN 4 - -#define DEFAULT_POPUP_HEIGHT 400 - -#define DEFAULT_TEXT_INDENT 3 - -#define COMBO_MARGIN 2 // spacing right of wxTextCtrl - - -#if defined(__WXMSW__) - -#define USE_TRANSIENT_POPUP 1 // Use wxPopupWindowTransient (preferred, if it works properly on platform) -#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common - // native controls work on it like normal. -#define POPUPWIN_IS_PERFECT 0 // Same, but for non-transient popup window. -#define TEXTCTRL_TEXT_CENTERED 0 // 1 if text in textctrl is vertically centered -#define FOCUS_RING 0 // No focus ring on wxMSW - -//#undef wxUSE_POPUPWIN -//#define wxUSE_POPUPWIN 0 - -#elif defined(__WXGTK__) - -// NB: It is not recommended to use wxDialog as popup on wxGTK, because of -// this bug: If wxDialog is hidden, its position becomes corrupt -// between hide and next show, but without internal coordinates being -// reflected (or something like that - atleast commenting out ->Hide() -// seemed to eliminate the position change). - -#define USE_TRANSIENT_POPUP 1 // Use wxPopupWindowTransient (preferred, if it works properly on platform) -#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common - // native controls work on it like normal. -#define POPUPWIN_IS_PERFECT 1 // Same, but for non-transient popup window. -#define TEXTCTRL_TEXT_CENTERED 1 // 1 if text in textctrl is vertically centered -#define FOCUS_RING 0 // No focus ring on wxGTK - -#elif defined(__WXMAC__) - -#define USE_TRANSIENT_POPUP 0 // Use wxPopupWindowTransient (preferred, if it works properly on platform) -#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common - // native controls work on it like normal. -#define POPUPWIN_IS_PERFECT 0 // Same, but for non-transient popup window. -#define TEXTCTRL_TEXT_CENTERED 1 // 1 if text in textctrl is vertically centered -#define FOCUS_RING 3 // Reserve room for the textctrl's focus ring to display - -#undef DEFAULT_DROPBUTTON_WIDTH -#define DEFAULT_DROPBUTTON_WIDTH 22 -#undef COMBO_MARGIN -#define COMBO_MARGIN FOCUS_RING - -#else - -#define USE_TRANSIENT_POPUP 0 // Use wxPopupWindowTransient (preferred, if it works properly on platform) -#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common - // native controls work on it like normal. -#define POPUPWIN_IS_PERFECT 0 // Same, but for non-transient popup window. -#define TEXTCTRL_TEXT_CENTERED 1 // 1 if text in textctrl is vertically centered -#define FOCUS_RING 0 - -#endif - - -// Popupwin is really only supported on wxMSW (not WINCE) and wxGTK, regardless -// what the wxUSE_POPUPWIN says. -// FIXME: Why isn't wxUSE_POPUPWIN reliable any longer? (it was in wxW2.6.2) -#if (!defined(__WXMSW__) && !defined(__WXGTK__)) || defined(__WXWINCE__) -#undef wxUSE_POPUPWIN -#define wxUSE_POPUPWIN 0 -#endif - - -#if wxUSE_POPUPWIN - #include "wx/popupwin.h" -#else - #undef USE_TRANSIENT_POPUP - #define USE_TRANSIENT_POPUP 0 -#endif - - -// Define different types of popup windows -enum -{ - POPUPWIN_NONE = 0, - POPUPWIN_WXPOPUPTRANSIENTWINDOW = 1, - POPUPWIN_WXPOPUPWINDOW = 2, - POPUPWIN_WXDIALOG = 3 -}; - - -#if USE_TRANSIENT_POPUP - // wxPopupTransientWindow is implemented - - #define wxComboPopupWindowBase wxPopupTransientWindow - #define PRIMARY_POPUP_TYPE POPUPWIN_WXPOPUPTRANSIENTWINDOW - #define USES_WXPOPUPTRANSIENTWINDOW 1 - - #if TRANSIENT_POPUPWIN_IS_PERFECT - // - #elif POPUPWIN_IS_PERFECT - #define wxComboPopupWindowBase2 wxPopupWindow - #define SECONDARY_POPUP_TYPE POPUPWIN_WXPOPUPWINDOW - #define USES_WXPOPUPWINDOW 1 - #else - #define wxComboPopupWindowBase2 wxDialog - #define SECONDARY_POPUP_TYPE POPUPWIN_WXDIALOG - #define USES_WXDIALOG 1 - #endif - -#elif wxUSE_POPUPWIN - // wxPopupWindow (but not wxPopupTransientWindow) is properly implemented - - #define wxComboPopupWindowBase wxPopupWindow - #define PRIMARY_POPUP_TYPE POPUPWIN_WXPOPUPWINDOW - #define USES_WXPOPUPWINDOW 1 - - #if !POPUPWIN_IS_PERFECT - #define wxComboPopupWindowBase2 wxDialog - #define SECONDARY_POPUP_TYPE POPUPWIN_WXDIALOG - #define USES_WXDIALOG 1 - #endif - -#else - // wxPopupWindow is not implemented - - #define wxComboPopupWindowBase wxDialog - #define PRIMARY_POPUP_TYPE POPUPWIN_WXDIALOG - #define USES_WXDIALOG 1 - -#endif - - -#ifndef USES_WXPOPUPTRANSIENTWINDOW - #define USES_WXPOPUPTRANSIENTWINDOW 0 -#endif - -#ifndef USES_WXPOPUPWINDOW - #define USES_WXPOPUPWINDOW 0 -#endif - -#ifndef USES_WXDIALOG - #define USES_WXDIALOG 0 -#endif - - -#if USES_WXPOPUPWINDOW - #define INSTALL_TOPLEV_HANDLER 1 -#else - #define INSTALL_TOPLEV_HANDLER 0 -#endif - - -// -// ** TODO ** -// * wxComboPopupWindow for external use (ie. replace old wxUniv wxPopupComboWindow) -// - - -// ---------------------------------------------------------------------------- -// wxComboFrameEventHandler takes care of hiding the popup when events happen -// in its top level parent. -// ---------------------------------------------------------------------------- - -#if INSTALL_TOPLEV_HANDLER - -// -// This will no longer be necessary after wxTransientPopupWindow -// works well on all platforms. -// - -class wxComboFrameEventHandler : public wxEvtHandler -{ -public: - wxComboFrameEventHandler( wxComboCtrlBase* pCb ); - virtual ~wxComboFrameEventHandler(); - - void OnPopup(); - - void OnIdle( wxIdleEvent& event ); - void OnMouseEvent( wxMouseEvent& event ); - void OnActivate( wxActivateEvent& event ); - void OnResize( wxSizeEvent& event ); - void OnMove( wxMoveEvent& event ); - void OnMenuEvent( wxMenuEvent& event ); - void OnClose( wxCloseEvent& event ); - -protected: - wxWindow* m_focusStart; - wxComboCtrlBase* m_combo; - -private: - DECLARE_EVENT_TABLE() -}; - -BEGIN_EVENT_TABLE(wxComboFrameEventHandler, wxEvtHandler) - EVT_IDLE(wxComboFrameEventHandler::OnIdle) - EVT_LEFT_DOWN(wxComboFrameEventHandler::OnMouseEvent) - EVT_RIGHT_DOWN(wxComboFrameEventHandler::OnMouseEvent) - EVT_SIZE(wxComboFrameEventHandler::OnResize) - EVT_MOVE(wxComboFrameEventHandler::OnMove) - EVT_MENU_HIGHLIGHT(wxID_ANY,wxComboFrameEventHandler::OnMenuEvent) - EVT_MENU_OPEN(wxComboFrameEventHandler::OnMenuEvent) - EVT_ACTIVATE(wxComboFrameEventHandler::OnActivate) - EVT_CLOSE(wxComboFrameEventHandler::OnClose) -END_EVENT_TABLE() - -wxComboFrameEventHandler::wxComboFrameEventHandler( wxComboCtrlBase* combo ) - : wxEvtHandler() -{ - m_combo = combo; -} - -wxComboFrameEventHandler::~wxComboFrameEventHandler() -{ -} - -void wxComboFrameEventHandler::OnPopup() -{ - m_focusStart = ::wxWindow::FindFocus(); -} - -void wxComboFrameEventHandler::OnIdle( wxIdleEvent& event ) -{ - wxWindow* winFocused = ::wxWindow::FindFocus(); - - wxWindow* popup = m_combo->GetPopupControl()->GetControl(); - wxWindow* winpopup = m_combo->GetPopupWindow(); - - if ( - winFocused != m_focusStart && - winFocused != popup && - winFocused->GetParent() != popup && - winFocused != winpopup && - winFocused->GetParent() != winpopup && - winFocused != m_combo && - winFocused != m_combo->GetButton() // GTK (atleast) requires this - ) - { - m_combo->HidePopup(); - } - - event.Skip(); -} - -void wxComboFrameEventHandler::OnMenuEvent( wxMenuEvent& event ) -{ - m_combo->HidePopup(); - event.Skip(); -} - -void wxComboFrameEventHandler::OnMouseEvent( wxMouseEvent& event ) -{ - m_combo->HidePopup(); - event.Skip(); -} - -void wxComboFrameEventHandler::OnClose( wxCloseEvent& event ) -{ - m_combo->HidePopup(); - event.Skip(); -} - -void wxComboFrameEventHandler::OnActivate( wxActivateEvent& event ) -{ - m_combo->HidePopup(); - event.Skip(); -} - -void wxComboFrameEventHandler::OnResize( wxSizeEvent& event ) -{ - m_combo->HidePopup(); - event.Skip(); -} - -void wxComboFrameEventHandler::OnMove( wxMoveEvent& event ) -{ - m_combo->HidePopup(); - event.Skip(); -} - -#endif // INSTALL_TOPLEV_HANDLER - -// ---------------------------------------------------------------------------- -// wxComboPopupWindow is, in essence, wxPopupWindow customized for -// wxComboCtrl. -// ---------------------------------------------------------------------------- - -class wxComboPopupWindow : public wxComboPopupWindowBase -{ -public: - - wxComboPopupWindow( wxComboCtrlBase *parent, - int style ) - #if USES_WXPOPUPWINDOW || USES_WXPOPUPTRANSIENTWINDOW - : wxComboPopupWindowBase(parent,style) - #else - : wxComboPopupWindowBase(parent, - wxID_ANY, - wxEmptyString, - wxPoint(-21,-21), - wxSize(20,20), - style) - #endif - { - m_inShow = 0; - } - -#if USES_WXPOPUPTRANSIENTWINDOW - virtual bool Show( bool show ); - virtual bool ProcessLeftDown(wxMouseEvent& event); -protected: - virtual void OnDismiss(); -#endif - -private: - wxByte m_inShow; -}; - - -#if USES_WXPOPUPTRANSIENTWINDOW -bool wxComboPopupWindow::Show( bool show ) -{ - // Guard against recursion - if ( m_inShow ) - return wxComboPopupWindowBase::Show(show); - - m_inShow++; - - wxASSERT( IsKindOf(CLASSINFO(wxPopupTransientWindow)) ); - - wxPopupTransientWindow* ptw = (wxPopupTransientWindow*) this; - wxComboCtrlBase* combo = (wxComboCtrlBase*) GetParent(); - - if ( show != ptw->IsShown() ) - { - if ( show ) - ptw->Popup(combo->GetPopupControl()->GetControl()); - else - ptw->Dismiss(); - } - - m_inShow--; - - return true; -} - -bool wxComboPopupWindow::ProcessLeftDown(wxMouseEvent& event) -{ - return wxPopupTransientWindow::ProcessLeftDown(event); -} - -// First thing that happens when a transient popup closes is that this method gets called. -void wxComboPopupWindow::OnDismiss() -{ - wxComboCtrlBase* combo = (wxComboCtrlBase*) GetParent(); - wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxComboCtrlBase)), - wxT("parent might not be wxComboCtrl, but check IMPLEMENT_DYNAMIC_CLASS(2) macro for correctness") ); - - combo->OnPopupDismiss(); -} -#endif // USES_WXPOPUPTRANSIENTWINDOW - - -// ---------------------------------------------------------------------------- -// wxComboPopupWindowEvtHandler does bulk of the custom event handling -// of a popup window. It is separate so we can have different types -// of popup windows. -// ---------------------------------------------------------------------------- - -class wxComboPopupWindowEvtHandler : public wxEvtHandler -{ -public: - - wxComboPopupWindowEvtHandler( wxComboCtrlBase *parent ) - { - m_combo = parent; - } - - void OnSizeEvent( wxSizeEvent& event ); - void OnKeyEvent(wxKeyEvent& event); -#if USES_WXDIALOG - void OnActivate( wxActivateEvent& event ); -#endif - -private: - wxComboCtrlBase* m_combo; - - DECLARE_EVENT_TABLE() -}; - - -BEGIN_EVENT_TABLE(wxComboPopupWindowEvtHandler, wxEvtHandler) - EVT_KEY_DOWN(wxComboPopupWindowEvtHandler::OnKeyEvent) - EVT_KEY_UP(wxComboPopupWindowEvtHandler::OnKeyEvent) -#if USES_WXDIALOG - EVT_ACTIVATE(wxComboPopupWindowEvtHandler::OnActivate) -#endif - EVT_SIZE(wxComboPopupWindowEvtHandler::OnSizeEvent) -END_EVENT_TABLE() - - -void wxComboPopupWindowEvtHandler::OnSizeEvent( wxSizeEvent& WXUNUSED(event) ) -{ - // Block the event so that the popup control does not get auto-resized. -} - -void wxComboPopupWindowEvtHandler::OnKeyEvent( wxKeyEvent& event ) -{ - // Relay keyboard event to the main child controls - wxWindowList children = m_combo->GetPopupWindow()->GetChildren(); - wxWindowList::iterator node = children.begin(); - wxWindow* child = (wxWindow*)*node; - child->AddPendingEvent(event); -} - -#if USES_WXDIALOG -void wxComboPopupWindowEvtHandler::OnActivate( wxActivateEvent& event ) -{ - if ( !event.GetActive() ) - { - // Tell combo control that we are dismissed. - m_combo->HidePopup(); - - event.Skip(); - } -} -#endif - - -// ---------------------------------------------------------------------------- -// wxComboPopup -// -// ---------------------------------------------------------------------------- - -wxComboPopup::~wxComboPopup() -{ -} - -void wxComboPopup::OnPopup() -{ -} - -void wxComboPopup::OnDismiss() -{ -} - -wxSize wxComboPopup::GetAdjustedSize( int minWidth, - int prefHeight, - int WXUNUSED(maxHeight) ) -{ - return wxSize(minWidth,prefHeight); -} - -void wxComboPopup::DefaultPaintComboControl( wxComboCtrlBase* combo, - wxDC& dc, const wxRect& rect ) -{ - if ( combo->GetWindowStyle() & wxCB_READONLY ) // ie. no textctrl - { - combo->PrepareBackground(dc,rect,0); - - dc.DrawText( combo->GetValue(), - rect.x + combo->GetTextIndent(), - (rect.height-dc.GetCharHeight())/2 + rect.y ); - } -} - -void wxComboPopup::PaintComboControl( wxDC& dc, const wxRect& rect ) -{ - DefaultPaintComboControl(m_combo,dc,rect); -} - -void wxComboPopup::OnComboKeyEvent( wxKeyEvent& event ) -{ - event.Skip(); -} - -void wxComboPopup::OnComboDoubleClick() -{ -} - -void wxComboPopup::SetStringValue( const wxString& WXUNUSED(value) ) -{ -} - -bool wxComboPopup::LazyCreate() -{ - return false; -} - -void wxComboPopup::Dismiss() -{ - m_combo->HidePopup(); -} - -// ---------------------------------------------------------------------------- -// input handling -// ---------------------------------------------------------------------------- - -// -// This is pushed to the event handler queue of the child textctrl. -// -class wxComboBoxExtraInputHandler : public wxEvtHandler -{ -public: - - wxComboBoxExtraInputHandler( wxComboCtrlBase* combo ) - : wxEvtHandler() - { - m_combo = combo; - } - virtual ~wxComboBoxExtraInputHandler() { } - void OnKey(wxKeyEvent& event); - void OnFocus(wxFocusEvent& event); - -protected: - wxComboCtrlBase* m_combo; - -private: - DECLARE_EVENT_TABLE() -}; - - -BEGIN_EVENT_TABLE(wxComboBoxExtraInputHandler, wxEvtHandler) - EVT_KEY_DOWN(wxComboBoxExtraInputHandler::OnKey) - EVT_KEY_UP(wxComboBoxExtraInputHandler::OnKey) - EVT_CHAR(wxComboBoxExtraInputHandler::OnKey) - EVT_SET_FOCUS(wxComboBoxExtraInputHandler::OnFocus) -END_EVENT_TABLE() - - -void wxComboBoxExtraInputHandler::OnKey(wxKeyEvent& event) -{ - // Let the wxComboCtrl event handler have a go first. - wxComboCtrlBase* combo = m_combo; - - wxKeyEvent redirectedEvent(event); - redirectedEvent.SetId(combo->GetId()); - redirectedEvent.SetEventObject(combo); - - if ( !combo->GetEventHandler()->ProcessEvent(redirectedEvent) ) - { - // Don't let TAB through to the text ctrl - looks ugly - if ( event.GetKeyCode() != WXK_TAB ) - event.Skip(); - } -} - -void wxComboBoxExtraInputHandler::OnFocus(wxFocusEvent& event) -{ - // FIXME: This code does run when control is clicked, - // yet on Windows it doesn't select all the text. - if ( !(m_combo->GetInternalFlags() & wxCC_NO_TEXT_AUTO_SELECT) ) - { - if ( m_combo->GetTextCtrl() ) - m_combo->GetTextCtrl()->SelectAll(); - else - m_combo->SetSelection(-1,-1); - } - - // Send focus indication to parent. - // NB: This is needed for cases where the textctrl gets focus - // instead of its parent. While this may trigger multiple - // wxEVT_SET_FOCUSes (since m_text->SetFocus is called - // from combo's focus event handler), they should be quite - // harmless. - wxFocusEvent evt2(wxEVT_SET_FOCUS,m_combo->GetId()); - evt2.SetEventObject(m_combo); - m_combo->GetEventHandler()->ProcessEvent(evt2); - - event.Skip(); -} - - -// -// This is pushed to the event handler queue of the control in popup. -// - -class wxComboPopupExtraEventHandler : public wxEvtHandler -{ -public: - - wxComboPopupExtraEventHandler( wxComboCtrlBase* combo ) - : wxEvtHandler() - { - m_combo = combo; - m_beenInside = false; - } - virtual ~wxComboPopupExtraEventHandler() { } - - void OnMouseEvent( wxMouseEvent& event ); - - // Called from wxComboCtrlBase::OnPopupDismiss - void OnPopupDismiss() - { - m_beenInside = false; - } - -protected: - wxComboCtrlBase* m_combo; - - bool m_beenInside; - -private: - DECLARE_EVENT_TABLE() -}; - - -BEGIN_EVENT_TABLE(wxComboPopupExtraEventHandler, wxEvtHandler) - EVT_MOUSE_EVENTS(wxComboPopupExtraEventHandler::OnMouseEvent) -END_EVENT_TABLE() - - -void wxComboPopupExtraEventHandler::OnMouseEvent( wxMouseEvent& event ) -{ - wxPoint pt = event.GetPosition(); - wxSize sz = m_combo->GetPopupControl()->GetControl()->GetClientSize(); - int evtType = event.GetEventType(); - bool isInside = pt.x >= 0 && pt.y >= 0 && pt.x < sz.x && pt.y < sz.y; - - if ( evtType == wxEVT_MOTION || - evtType == wxEVT_LEFT_DOWN || - evtType == wxEVT_RIGHT_DOWN ) - { - // Block motion and click events outside the popup - if ( !isInside || !m_combo->IsPopupShown() ) - { - event.Skip(false); - return; - } - } - else if ( evtType == wxEVT_LEFT_UP ) - { - if ( !m_combo->IsPopupShown() ) - { - event.Skip(false); - return; - } - - if ( !m_beenInside ) - { - if ( isInside ) - { - m_beenInside = true; - } - else - { - // - // Some mouse events to popup that happen outside it, before cursor - // has been inside the popu, need to be ignored by it but relayed to - // the dropbutton. - // - wxWindow* btn = m_combo->GetButton(); - if ( btn ) - btn->GetEventHandler()->AddPendingEvent(event); - else - m_combo->GetEventHandler()->AddPendingEvent(event); - - return; - } - - event.Skip(); - } - } - - event.Skip(); -} - -// ---------------------------------------------------------------------------- -// wxComboCtrlBase -// ---------------------------------------------------------------------------- - - -BEGIN_EVENT_TABLE(wxComboCtrlBase, wxControl) - EVT_TEXT(wxID_ANY,wxComboCtrlBase::OnTextCtrlEvent) - EVT_SIZE(wxComboCtrlBase::OnSizeEvent) - EVT_SET_FOCUS(wxComboCtrlBase::OnFocusEvent) - EVT_KILL_FOCUS(wxComboCtrlBase::OnFocusEvent) - EVT_IDLE(wxComboCtrlBase::OnIdleEvent) - //EVT_BUTTON(wxID_ANY,wxComboCtrlBase::OnButtonClickEvent) - EVT_KEY_DOWN(wxComboCtrlBase::OnKeyEvent) - EVT_TEXT_ENTER(wxID_ANY,wxComboCtrlBase::OnTextCtrlEvent) - EVT_SYS_COLOUR_CHANGED(wxComboCtrlBase::OnSysColourChanged) -END_EVENT_TABLE() - - -IMPLEMENT_ABSTRACT_CLASS(wxComboCtrlBase, wxControl) - -void wxComboCtrlBase::Init() -{ - m_winPopup = (wxWindow *)NULL; - m_popup = (wxWindow *)NULL; - m_popupWinState = Hidden; - m_btn = (wxWindow*) NULL; - m_text = (wxTextCtrl*) NULL; - m_popupInterface = (wxComboPopup*) NULL; - - m_popupExtraHandler = (wxEvtHandler*) NULL; - m_textEvtHandler = (wxEvtHandler*) NULL; - -#if INSTALL_TOPLEV_HANDLER - m_toplevEvtHandler = (wxEvtHandler*) NULL; -#endif - - m_mainCtrlWnd = this; - - m_heightPopup = -1; - m_widthMinPopup = -1; - m_anchorSide = 0; - m_widthCustomPaint = 0; - m_widthCustomBorder = 0; - - m_btnState = 0; - m_btnWidDefault = 0; - m_blankButtonBg = false; - m_ignoreEvtText = 0; - m_popupWinType = POPUPWIN_NONE; - m_btnWid = m_btnHei = -1; - m_btnSide = wxRIGHT; - m_btnSpacingX = 0; - - m_extLeft = 0; - m_extRight = 0; - m_absIndent = -1; - m_iFlags = 0; - m_timeCanAcceptClick = 0; - - m_resetFocus = false; -} - -bool wxComboCtrlBase::Create(wxWindow *parent, - wxWindowID id, - const wxString& value, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name) -{ - if ( !wxControl::Create(parent, - id, - pos, - size, - style | wxWANTS_CHARS, - validator, - name) ) - return false; - - m_valueString = value; - - // Get colours - OnThemeChange(); - m_absIndent = GetNativeTextIndent(); - - m_iFlags |= wxCC_IFLAG_CREATED; - - // If x and y indicate valid size, wxSizeEvent won't be - // emitted automatically, so we need to add artifical one. - if ( size.x > 0 && size.y > 0 ) - { - wxSizeEvent evt(size,GetId()); - GetEventHandler()->AddPendingEvent(evt); - } - - return true; -} - -void wxComboCtrlBase::InstallInputHandlers() -{ - if ( m_text ) - { - m_textEvtHandler = new wxComboBoxExtraInputHandler(this); - m_text->PushEventHandler(m_textEvtHandler); - } -} - -void -wxComboCtrlBase::CreateTextCtrl(int style, const wxValidator& validator) -{ - if ( !(m_windowStyle & wxCB_READONLY) ) - { - if ( m_text ) - m_text->Destroy(); - - // wxTE_PROCESS_TAB is needed because on Windows, wxTAB_TRAVERSAL is - // not used by the wxPropertyGrid and therefore the tab is processed by - // looking at ancestors to see if they have wxTAB_TRAVERSAL. The - // navigation event is then sent to the wrong window. - style |= wxTE_PROCESS_TAB; - - if ( HasFlag(wxTE_PROCESS_ENTER) ) - style |= wxTE_PROCESS_ENTER; - - // Ignore EVT_TEXT generated by the constructor (but only - // if the event redirector already exists) - // NB: This must be " = 1" instead of "++"; - if ( m_textEvtHandler ) - m_ignoreEvtText = 1; - else - m_ignoreEvtText = 0; - - m_text = new wxTextCtrl(this, wxID_ANY, m_valueString, - wxDefaultPosition, wxSize(10,-1), - style, validator); - } -} - -void wxComboCtrlBase::OnThemeChange() -{ - // Leave the default bg on the Mac so the area used by the focus ring will - // be the correct colour and themed brush. Instead we'll use - // wxSYS_COLOUR_WINDOW in the EVT_PAINT handler as needed. -#ifndef __WXMAC__ - if ( !m_hasBgCol ) - { -#ifdef __WXGTK__ - // Set background to gtk_rc_get_style(m_widget)->bg[GTK_STATE_NORMAL], - // which can be different than the background of text entry. - wxColour bgCol = GetDefaultAttributes().colBg; -#else - wxColour bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); -#endif - SetOwnBackgroundColour(bgCol); - m_hasBgCol = false; - } -#endif -} - -wxComboCtrlBase::~wxComboCtrlBase() -{ - if ( HasCapture() ) - ReleaseMouse(); - -#if INSTALL_TOPLEV_HANDLER - delete ((wxComboFrameEventHandler*)m_toplevEvtHandler); - m_toplevEvtHandler = (wxEvtHandler*) NULL; -#endif - - DestroyPopup(); - - if ( m_text ) - m_text->RemoveEventHandler(m_textEvtHandler); - - delete m_textEvtHandler; -} - - -// ---------------------------------------------------------------------------- -// geometry stuff -// ---------------------------------------------------------------------------- - -// Recalculates button and textctrl areas -void wxComboCtrlBase::CalculateAreas( int btnWidth ) -{ - wxSize sz = GetClientSize(); - int customBorder = m_widthCustomBorder; - int btnBorder; // border for button only - - // check if button should really be outside the border: we'll do it it if - // its platform default or bitmap+pushbutton background is used, but not if - // there is vertical size adjustment or horizontal spacing. - if ( ( (m_iFlags & wxCC_BUTTON_OUTSIDE_BORDER) || - (m_bmpNormal.Ok() && m_blankButtonBg) ) && - m_btnSpacingX == 0 && - m_btnHei <= 0 ) - { - m_iFlags |= wxCC_IFLAG_BUTTON_OUTSIDE; - btnBorder = 0; - } - else - { - m_iFlags &= ~(wxCC_IFLAG_BUTTON_OUTSIDE); - btnBorder = customBorder; - } - - // Defaul indentation - if ( m_absIndent < 0 ) - m_absIndent = GetNativeTextIndent(); - - int butWidth = btnWidth; - - if ( butWidth <= 0 ) - butWidth = m_btnWidDefault; - else - m_btnWidDefault = butWidth; - - if ( butWidth <= 0 ) - return; - - int butHeight = sz.y - btnBorder*2; - - // Adjust button width - if ( m_btnWid > 0 ) - butWidth = m_btnWid; - else - { - // Adjust button width to match aspect ratio - // (but only if control is smaller than best size). - int bestHeight = GetBestSize().y; - int height = GetSize().y; - - if ( height < bestHeight ) - { - // Make very small buttons square, as it makes - // them accommodate arrow image better and still - // looks decent. - if ( height > 18 ) - butWidth = (height*butWidth)/bestHeight; - else - butWidth = butHeight; - } - } - - // Adjust button height - if ( m_btnHei > 0 ) - butHeight = m_btnHei; - - // Use size of normal bitmap if... - // It is larger - // OR - // button width is set to default and blank button bg is not drawn - if ( m_bmpNormal.Ok() ) - { - int bmpReqWidth = m_bmpNormal.GetWidth(); - int bmpReqHeight = m_bmpNormal.GetHeight(); - - // If drawing blank button background, we need to add some margin. - if ( m_blankButtonBg ) - { - bmpReqWidth += BMP_BUTTON_MARGIN*2; - bmpReqHeight += BMP_BUTTON_MARGIN*2; - } - - if ( butWidth < bmpReqWidth || ( m_btnWid == 0 && !m_blankButtonBg ) ) - butWidth = bmpReqWidth; - if ( butHeight < bmpReqHeight || ( m_btnHei == 0 && !m_blankButtonBg ) ) - butHeight = bmpReqHeight; - - // Need to fix height? - if ( (sz.y-(customBorder*2)) < butHeight && btnWidth == 0 ) - { - int newY = butHeight+(customBorder*2); - SetClientSize(wxDefaultCoord,newY); - sz.y = newY; - } - } - - int butAreaWid = butWidth + (m_btnSpacingX*2); - - m_btnSize.x = butWidth; - m_btnSize.y = butHeight; - - m_btnArea.x = ( m_btnSide==wxRIGHT ? sz.x - butAreaWid - btnBorder : btnBorder ); - m_btnArea.y = btnBorder + FOCUS_RING; - m_btnArea.width = butAreaWid; - m_btnArea.height = sz.y - ((btnBorder+FOCUS_RING)*2); - - m_tcArea.x = ( m_btnSide==wxRIGHT ? 0 : butAreaWid ) + customBorder + FOCUS_RING; - m_tcArea.y = customBorder + FOCUS_RING; - m_tcArea.width = sz.x - butAreaWid - (customBorder*2) - (FOCUS_RING*2); - m_tcArea.height = sz.y - ((customBorder+FOCUS_RING)*2); - -/* - if ( m_text ) - { - ::wxMessageBox(wxString::Format(wxT("ButtonArea (%i,%i,%i,%i)\n"),m_btnArea.x,m_btnArea.y,m_btnArea.width,m_btnArea.height) + - wxString::Format(wxT("TextCtrlArea (%i,%i,%i,%i)"),m_tcArea.x,m_tcArea.y,m_tcArea.width,m_tcArea.height)); - } -*/ -} - -void wxComboCtrlBase::PositionTextCtrl( int textCtrlXAdjust, int textCtrlYAdjust ) -{ - if ( !m_text ) - return; - -#if !TEXTCTRL_TEXT_CENTERED - - wxSize sz = GetClientSize(); - - int customBorder = m_widthCustomBorder; - if ( (m_text->GetWindowStyleFlag() & wxBORDER_MASK) == wxNO_BORDER ) - { - // Centre textctrl - int tcSizeY = m_text->GetBestSize().y; - int diff = sz.y - tcSizeY; - int y = textCtrlYAdjust + (diff/2); - - if ( y < customBorder ) - y = customBorder; - - m_text->SetSize( m_tcArea.x + m_widthCustomPaint + m_absIndent + textCtrlXAdjust, - y, - m_tcArea.width - COMBO_MARGIN - - (textCtrlXAdjust + m_widthCustomPaint + m_absIndent), - -1 ); - - // Make sure textctrl doesn't exceed the bottom custom border - wxSize tsz = m_text->GetSize(); - diff = (y + tsz.y) - (sz.y - customBorder); - if ( diff >= 0 ) - { - tsz.y = tsz.y - diff - 1; - m_text->SetSize(tsz); - } - } - else -#else // TEXTCTRL_TEXT_CENTERED - wxUnusedVar(textCtrlXAdjust); - wxUnusedVar(textCtrlYAdjust); -#endif // !TEXTCTRL_TEXT_CENTERED/TEXTCTRL_TEXT_CENTERED - { - // If it has border, have textctrl will the entire text field. - m_text->SetSize( m_tcArea.x + m_widthCustomPaint, - m_tcArea.y, - m_tcArea.width - m_widthCustomPaint, - m_tcArea.height ); - } -} - -wxSize wxComboCtrlBase::DoGetBestSize() const -{ - wxSize sizeText(150,0); - - if ( m_text ) - sizeText = m_text->GetBestSize(); - - // TODO: Better method to calculate close-to-native control height. - - int fhei; - if ( m_font.Ok() ) - fhei = (m_font.GetPointSize()*2) + 5; - else if ( wxNORMAL_FONT->Ok() ) - fhei = (wxNORMAL_FONT->GetPointSize()*2) + 5; - else - fhei = sizeText.y + 4; - - // Need to force height to accomodate bitmap? - int btnSizeY = m_btnSize.y; - if ( m_bmpNormal.Ok() && fhei < btnSizeY ) - fhei = btnSizeY; - - // Control height doesn't depend on border -/* - // Add border - int border = m_windowStyle & wxBORDER_MASK; - if ( border == wxSIMPLE_BORDER ) - fhei += 2; - else if ( border == wxNO_BORDER ) - fhei += (m_widthCustomBorder*2); - else - // Sunken etc. - fhei += 4; -*/ - - // Final adjustments -#ifdef __WXGTK__ - fhei += 1; -#endif - -#ifdef __WXMAC__ - // these are the numbers from the HIG: - switch ( m_windowVariant ) - { - case wxWINDOW_VARIANT_NORMAL: - default : - fhei = 22; - break; - case wxWINDOW_VARIANT_SMALL: - fhei = 19; - break; - case wxWINDOW_VARIANT_MINI: - fhei = 15; - break; - } -#endif - - fhei += 2 * FOCUS_RING; - int width = sizeText.x + FOCUS_RING + COMBO_MARGIN + DEFAULT_DROPBUTTON_WIDTH; - - wxSize ret(width, fhei); - CacheBestSize(ret); - return ret; -} - -void wxComboCtrlBase::OnSizeEvent( wxSizeEvent& event ) -{ - if ( !IsCreated() ) - return; - - // defined by actual wxComboCtrls - OnResize(); - - event.Skip(); -} - -// ---------------------------------------------------------------------------- -// standard operations -// ---------------------------------------------------------------------------- - -bool wxComboCtrlBase::Enable(bool enable) -{ - if ( !wxControl::Enable(enable) ) - return false; - - if ( m_btn ) - m_btn->Enable(enable); - if ( m_text ) - m_text->Enable(enable); - - Refresh(); - - return true; -} - -bool wxComboCtrlBase::Show(bool show) -{ - if ( !wxControl::Show(show) ) - return false; - - if (m_btn) - m_btn->Show(show); - - if (m_text) - m_text->Show(show); - - return true; -} - -bool wxComboCtrlBase::SetFont ( const wxFont& font ) -{ - if ( !wxControl::SetFont(font) ) - return false; - - if (m_text) - m_text->SetFont(font); - - return true; -} - -#if wxUSE_TOOLTIPS -void wxComboCtrlBase::DoSetToolTip(wxToolTip *tooltip) -{ - wxControl::DoSetToolTip(tooltip); - - // Set tool tip for button and text box - if ( tooltip ) - { - const wxString &tip = tooltip->GetTip(); - if ( m_text ) m_text->SetToolTip(tip); - if ( m_btn ) m_btn->SetToolTip(tip); - } - else - { - if ( m_text ) m_text->SetToolTip( (wxToolTip*) NULL ); - if ( m_btn ) m_btn->SetToolTip( (wxToolTip*) NULL ); - } -} -#endif // wxUSE_TOOLTIPS - -#if wxUSE_VALIDATORS -void wxComboCtrlBase::SetValidator(const wxValidator& validator) -{ - wxTextCtrl* textCtrl = GetTextCtrl(); - - if ( textCtrl ) - textCtrl->SetValidator( validator ); - else - wxControl::SetValidator( validator ); -} - -wxValidator* wxComboCtrlBase::GetValidator() -{ - wxTextCtrl* textCtrl = GetTextCtrl(); - - return textCtrl ? textCtrl->GetValidator() : wxControl::GetValidator(); -} -#endif // wxUSE_VALIDATORS - -// ---------------------------------------------------------------------------- -// painting -// ---------------------------------------------------------------------------- - -#if (!defined(__WXMSW__)) || defined(__WXUNIVERSAL__) -// prepare combo box background on area in a way typical on platform -void wxComboCtrlBase::PrepareBackground( wxDC& dc, const wxRect& rect, int flags ) const -{ - wxSize sz = GetClientSize(); - bool isEnabled; - bool isFocused; // also selected - - // For smaller size control (and for disabled background) use less spacing - int focusSpacingX; - int focusSpacingY; - - if ( !(flags & wxCONTROL_ISSUBMENU) ) - { - // Drawing control - isEnabled = IsEnabled(); - isFocused = ShouldDrawFocus(); - - // Windows-style: for smaller size control (and for disabled background) use less spacing - focusSpacingX = isEnabled ? 2 : 1; - focusSpacingY = sz.y > (GetCharHeight()+2) && isEnabled ? 2 : 1; - } - else - { - // Drawing a list item - isEnabled = true; // they are never disabled - isFocused = flags & wxCONTROL_SELECTED ? true : false; - - focusSpacingX = 0; - focusSpacingY = 0; - } - - // Set the background sub-rectangle for selection, disabled etc - wxRect selRect(rect); - selRect.y += focusSpacingY; - selRect.height -= (focusSpacingY*2); - - int wcp = 0; - - if ( !(flags & wxCONTROL_ISSUBMENU) ) - wcp += m_widthCustomPaint; - - selRect.x += wcp + focusSpacingX; - selRect.width -= wcp + (focusSpacingX*2); - - wxColour fgCol; - wxColour bgCol; - - if ( isEnabled ) - { - if ( isFocused ) - fgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); - else if ( m_hasFgCol ) - // Honour the custom foreground colour - fgCol = GetForegroundColour(); - else - fgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); - } - else - { - fgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT); - } - - if ( isEnabled ) - { - if ( isFocused ) - bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); - else if ( m_hasBgCol ) - // Honour the custom background colour - bgCol = GetBackgroundColour(); - else -#if defined(__WXMAC__) || defined(__WXGTK__) // see note in OnThemeChange - bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); -#else - bgCol = GetBackgroundColour(); -#endif - } - else - { -#if defined(__WXMAC__) || defined(__WXGTK__) // see note in OnThemeChange - bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); -#else - bgCol = GetBackgroundColour(); -#endif - } - - dc.SetTextForeground( fgCol ); - dc.SetBrush( bgCol ); - dc.SetPen( bgCol ); - dc.DrawRectangle( selRect ); - - // Don't clip exactly to the selection rectangle so we can draw - // to the non-selected area in front of it. - wxRect clipRect(rect.x,rect.y, - (selRect.x+selRect.width)-rect.x,rect.height); - dc.SetClippingRegion(clipRect); -} -#else -// Save the library size a bit for platforms that re-implement this. -void wxComboCtrlBase::PrepareBackground( wxDC&, const wxRect&, int ) const -{ -} -#endif - -void wxComboCtrlBase::DrawButton( wxDC& dc, const wxRect& rect, int flags ) -{ - int drawState = m_btnState; - -#ifdef __WXGTK__ - if ( GetPopupWindowState() >= Animating ) - drawState |= wxCONTROL_PRESSED; -#endif - - wxRect drawRect(rect.x+m_btnSpacingX, - rect.y+((rect.height-m_btnSize.y)/2), - m_btnSize.x, - m_btnSize.y); - - // Make sure area is not larger than the control - if ( drawRect.y < rect.y ) - drawRect.y = rect.y; - if ( drawRect.height > rect.height ) - drawRect.height = rect.height; - - bool enabled = IsEnabled(); - - if ( !enabled ) - drawState |= wxCONTROL_DISABLED; - - if ( !m_bmpNormal.Ok() ) - { - if ( flags & Draw_BitmapOnly ) - return; - - // Need to clear button background even if m_btn is present - if ( flags & Draw_PaintBg ) - { - wxColour bgCol; - - if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE ) - bgCol = GetParent()->GetBackgroundColour(); - else - bgCol = GetBackgroundColour(); - - dc.SetBrush(bgCol); - dc.SetPen(bgCol); - dc.DrawRectangle(rect); - } - - // Draw standard button - wxRendererNative::Get().DrawComboBoxDropButton(this, - dc, - drawRect, - drawState); - } - else - { - // Draw bitmap - - wxBitmap* pBmp; - - if ( !enabled ) - pBmp = &m_bmpDisabled; - else if ( m_btnState & wxCONTROL_PRESSED ) - pBmp = &m_bmpPressed; - else if ( m_btnState & wxCONTROL_CURRENT ) - pBmp = &m_bmpHover; - else - pBmp = &m_bmpNormal; - - if ( m_blankButtonBg ) - { - // If using blank button background, we need to clear its background - // with button face colour instead of colour for rest of the control. - if ( flags & Draw_PaintBg ) - { - wxColour bgCol = GetParent()->GetBackgroundColour(); //wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); - //wxColour bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); - dc.SetPen(bgCol); - dc.SetBrush(bgCol); - dc.DrawRectangle(rect); - } - - wxRendererNative::Get().DrawPushButton(this, - dc, - drawRect, - drawState); - - } - else - - { - // Need to clear button background even if m_btn is present - // (assume non-button background was cleared just before this call so brushes are good) - if ( flags & Draw_PaintBg ) - dc.DrawRectangle(rect); - } - - // Draw bitmap centered in drawRect - dc.DrawBitmap(*pBmp, - drawRect.x + (drawRect.width-pBmp->GetWidth())/2, - drawRect.y + (drawRect.height-pBmp->GetHeight())/2, - true); - } -} - -void wxComboCtrlBase::RecalcAndRefresh() -{ - if ( IsCreated() ) - { - wxSizeEvent evt(GetSize(),GetId()); - GetEventHandler()->ProcessEvent(evt); - Refresh(); - } -} - -// ---------------------------------------------------------------------------- -// miscellaneous event handlers -// ---------------------------------------------------------------------------- - -void wxComboCtrlBase::OnTextCtrlEvent(wxCommandEvent& event) -{ - if ( event.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED ) - { - if ( m_ignoreEvtText > 0 ) - { - m_ignoreEvtText--; - return; - } - } - - // Change event id, object and string before relaying it forward - event.SetId(GetId()); - wxString s = event.GetString(); - event.SetEventObject(this); - event.SetString(s); - event.Skip(); -} - -// call if cursor is on button area or mouse is captured for the button -bool wxComboCtrlBase::HandleButtonMouseEvent( wxMouseEvent& event, - int flags ) -{ - int type = event.GetEventType(); - - if ( type == wxEVT_MOTION ) - { - if ( flags & wxCC_MF_ON_BUTTON ) - { - if ( !(m_btnState & wxCONTROL_CURRENT) ) - { - // Mouse hover begins - m_btnState |= wxCONTROL_CURRENT; - if ( HasCapture() ) // Retain pressed state. - m_btnState |= wxCONTROL_PRESSED; - Refresh(); - } - } - else if ( (m_btnState & wxCONTROL_CURRENT) ) - { - // Mouse hover ends - m_btnState &= ~(wxCONTROL_CURRENT|wxCONTROL_PRESSED); - Refresh(); - } - } - else if ( type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_DCLICK ) - { - if ( flags & (wxCC_MF_ON_CLICK_AREA|wxCC_MF_ON_BUTTON) ) - { - m_btnState |= wxCONTROL_PRESSED; - Refresh(); - - if ( !(m_iFlags & wxCC_POPUP_ON_MOUSE_UP) ) - OnButtonClick(); - else - // If showing popup now, do not capture mouse or there will be interference - CaptureMouse(); - } - } - else if ( type == wxEVT_LEFT_UP ) - { - - // Only accept event if mouse was left-press was previously accepted - if ( HasCapture() ) - ReleaseMouse(); - - if ( m_btnState & wxCONTROL_PRESSED ) - { - // If mouse was inside, fire the click event. - if ( m_iFlags & wxCC_POPUP_ON_MOUSE_UP ) - { - if ( flags & (wxCC_MF_ON_CLICK_AREA|wxCC_MF_ON_BUTTON) ) - OnButtonClick(); - } - - m_btnState &= ~(wxCONTROL_PRESSED); - Refresh(); - } - } - else if ( type == wxEVT_LEAVE_WINDOW ) - { - if ( m_btnState & (wxCONTROL_CURRENT|wxCONTROL_PRESSED) ) - { - m_btnState &= ~(wxCONTROL_CURRENT); - - // Mouse hover ends - if ( IsPopupWindowState(Hidden) ) - { - m_btnState &= ~(wxCONTROL_PRESSED); - Refresh(); - } - } - } - else - return false; - - return true; -} - -// returns true if event was consumed or filtered -bool wxComboCtrlBase::PreprocessMouseEvent( wxMouseEvent& event, - int WXUNUSED(flags) ) -{ - wxLongLong t = ::wxGetLocalTimeMillis(); - int evtType = event.GetEventType(); - -#if USES_WXPOPUPWINDOW || USES_WXDIALOG - if ( m_popupWinType != POPUPWIN_WXPOPUPTRANSIENTWINDOW ) - { - if ( IsPopupWindowState(Visible) && - ( evtType == wxEVT_LEFT_DOWN || evtType == wxEVT_RIGHT_DOWN ) ) - { - HidePopup(); - return true; - } - } -#endif - - // Filter out clicks on button immediately after popup dismiss (Windows like behaviour) - if ( evtType == wxEVT_LEFT_DOWN && t < m_timeCanAcceptClick ) - { - event.SetEventType(0); - return true; - } - - return false; -} - -void wxComboCtrlBase::HandleNormalMouseEvent( wxMouseEvent& event ) -{ - int evtType = event.GetEventType(); - - if ( (evtType == wxEVT_LEFT_DOWN || evtType == wxEVT_LEFT_DCLICK) && - (m_windowStyle & wxCB_READONLY) ) - { - if ( GetPopupWindowState() >= Animating ) - { - #if USES_WXPOPUPWINDOW - // Click here always hides the popup. - if ( m_popupWinType == POPUPWIN_WXPOPUPWINDOW ) - HidePopup(); - #endif - } - else - { - if ( !(m_windowStyle & wxCC_SPECIAL_DCLICK) ) - { - // In read-only mode, clicking the text is the - // same as clicking the button. - OnButtonClick(); - } - else if ( /*evtType == wxEVT_LEFT_UP || */evtType == wxEVT_LEFT_DCLICK ) - { - //if ( m_popupInterface->CycleValue() ) - // Refresh(); - if ( m_popupInterface ) - m_popupInterface->OnComboDoubleClick(); - } - } - } - else - if ( IsPopupShown() ) - { - // relay (some) mouse events to the popup - if ( evtType == wxEVT_MOUSEWHEEL ) - m_popup->AddPendingEvent(event); - } - else if ( evtType ) - event.Skip(); -} - -void wxComboCtrlBase::OnKeyEvent(wxKeyEvent& event) -{ - if ( IsPopupShown() ) - { - // pass it to the popped up control - GetPopupControl()->GetControl()->AddPendingEvent(event); - } - else // no popup - { - int keycode = event.GetKeyCode(); - - wxWindow* mainCtrl = GetMainWindowOfCompositeControl(); - - if ( mainCtrl->GetParent()->HasFlag(wxTAB_TRAVERSAL) && - keycode == WXK_TAB ) - { - wxNavigationKeyEvent evt; - - evt.SetFlags(wxNavigationKeyEvent::FromTab| - (!event.ShiftDown() ? wxNavigationKeyEvent::IsForward - : wxNavigationKeyEvent::IsBackward)); - evt.SetEventObject(mainCtrl); - evt.SetCurrentFocus(mainCtrl); - mainCtrl->GetParent()->GetEventHandler()->AddPendingEvent(evt); - return; - } - - if ( IsKeyPopupToggle(event) ) - { - OnButtonClick(); - return; - } - - int comboStyle = GetWindowStyle(); - wxComboPopup* popupInterface = GetPopupControl(); - - if ( !popupInterface ) - { - event.Skip(); - return; - } - - if ( (comboStyle & wxCB_READONLY) || - (keycode != WXK_RIGHT && keycode != WXK_LEFT) ) - { - popupInterface->OnComboKeyEvent(event); - } - else - event.Skip(); - } -} - -void wxComboCtrlBase::OnFocusEvent( wxFocusEvent& event ) -{ - if ( event.GetEventType() == wxEVT_SET_FOCUS ) - { - wxWindow* tc = GetTextCtrl(); - if ( tc && tc != DoFindFocus() ) -#ifdef __WXMAC__ - m_resetFocus = true; -#else - tc->SetFocus(); -#endif - } - - Refresh(); -} - -void wxComboCtrlBase::OnIdleEvent( wxIdleEvent& WXUNUSED(event) ) -{ - if ( m_resetFocus ) - { - m_resetFocus = false; - wxWindow* tc = GetTextCtrl(); - if ( tc ) - tc->SetFocus(); - } -} - -void wxComboCtrlBase::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event)) -{ - OnThemeChange(); - // indentation may also have changed - if ( !(m_iFlags & wxCC_IFLAG_INDENT_SET) ) - m_absIndent = GetNativeTextIndent(); - RecalcAndRefresh(); -} - -// ---------------------------------------------------------------------------- -// popup handling -// ---------------------------------------------------------------------------- - -// Create popup window and the child control -void wxComboCtrlBase::CreatePopup() -{ - wxComboPopup* popupInterface = m_popupInterface; - wxWindow* popup; - - if ( !m_winPopup ) - { -#ifdef wxComboPopupWindowBase2 - if ( m_iFlags & wxCC_IFLAG_USE_ALT_POPUP ) - { - #if !USES_WXDIALOG - m_winPopup = new wxComboPopupWindowBase2( this, wxNO_BORDER ); - #else - m_winPopup = new wxComboPopupWindowBase2( this, wxID_ANY, wxEmptyString, - wxPoint(-21,-21), wxSize(20, 20), - wxNO_BORDER ); - #endif - m_popupWinType = SECONDARY_POPUP_TYPE; - } - else -#endif - { - m_winPopup = new wxComboPopupWindow( this, wxNO_BORDER ); - m_popupWinType = PRIMARY_POPUP_TYPE; - } - m_popupWinEvtHandler = new wxComboPopupWindowEvtHandler(this); - m_winPopup->PushEventHandler(m_popupWinEvtHandler); - } - - popupInterface->Create(m_winPopup); - m_popup = popup = popupInterface->GetControl(); - - m_popupExtraHandler = new wxComboPopupExtraEventHandler(this); - popup->PushEventHandler( m_popupExtraHandler ); - - // This may be helpful on some platforms - // (eg. it bypasses a wxGTK popupwindow bug where - // window is not initially hidden when it should be) - m_winPopup->Hide(); - - popupInterface->m_iFlags |= wxCP_IFLAG_CREATED; -} - -// Destroy popup window and the child control -void wxComboCtrlBase::DestroyPopup() -{ - HidePopup(); - - if ( m_popup ) - m_popup->RemoveEventHandler(m_popupExtraHandler); - - delete m_popupExtraHandler; - - delete m_popupInterface; - - if ( m_winPopup ) - { - m_winPopup->RemoveEventHandler(m_popupWinEvtHandler); - delete m_popupWinEvtHandler; - m_popupWinEvtHandler = NULL; - m_winPopup->Destroy(); - } - - m_popupExtraHandler = (wxEvtHandler*) NULL; - m_popupInterface = (wxComboPopup*) NULL; - m_winPopup = (wxWindow*) NULL; - m_popup = (wxWindow*) NULL; -} - -void wxComboCtrlBase::DoSetPopupControl(wxComboPopup* iface) -{ - wxCHECK_RET( iface, wxT("no popup interface set for wxComboCtrl") ); - - DestroyPopup(); - - iface->InitBase(this); - iface->Init(); - - m_popupInterface = iface; - - if ( !iface->LazyCreate() ) - { - CreatePopup(); - } - else - { - m_popup = (wxWindow*) NULL; - } - - // This must be done after creation - if ( m_valueString.length() ) - { - iface->SetStringValue(m_valueString); - //Refresh(); - } -} - -// Ensures there is atleast the default popup -void wxComboCtrlBase::EnsurePopupControl() -{ - if ( !m_popupInterface ) - SetPopupControl(NULL); -} - -void wxComboCtrlBase::OnButtonClick() -{ - // Derived classes can override this method for totally custom - // popup action - if ( !IsPopupWindowState(Visible) ) - ShowPopup(); - else - HidePopup(); -} - -void wxComboCtrlBase::ShowPopup() -{ - EnsurePopupControl(); - wxCHECK_RET( !IsPopupWindowState(Visible), wxT("popup window already shown") ); - - if ( IsPopupWindowState(Animating) ) - return; - - SetFocus(); - - // Space above and below - int screenHeight; - wxPoint scrPos; - int spaceAbove; - int spaceBelow; - int maxHeightPopup; - wxSize ctrlSz = GetSize(); - - screenHeight = wxSystemSettings::GetMetric( wxSYS_SCREEN_Y ); - scrPos = GetParent()->ClientToScreen(GetPosition()); - - spaceAbove = scrPos.y; - spaceBelow = screenHeight - spaceAbove - ctrlSz.y; - - maxHeightPopup = spaceBelow; - if ( spaceAbove > spaceBelow ) - maxHeightPopup = spaceAbove; - - // Width - int widthPopup = ctrlSz.x + m_extLeft + m_extRight; - - if ( widthPopup < m_widthMinPopup ) - widthPopup = m_widthMinPopup; - - wxWindow* winPopup = m_winPopup; - wxWindow* popup; - - // Need to disable tab traversal of parent - // - // NB: This is to fix a bug in wxMSW. In theory it could also be fixed - // by, for instance, adding check to window.cpp:wxWindowMSW::MSWProcessMessage - // that if transient popup is open, then tab traversal is to be ignored. - // However, I think this code would still be needed for cases where - // transient popup doesn't work yet (wxWinCE?). - wxWindow* parent = GetParent(); - int parentFlags = parent->GetWindowStyle(); - if ( parentFlags & wxTAB_TRAVERSAL ) - { - parent->SetWindowStyle( parentFlags & ~(wxTAB_TRAVERSAL) ); - m_iFlags |= wxCC_IFLAG_PARENT_TAB_TRAVERSAL; - } - - if ( !winPopup ) - { - CreatePopup(); - winPopup = m_winPopup; - popup = m_popup; - } - else - { - popup = m_popup; - } - - winPopup->Enable(); - - wxASSERT( !m_popup || m_popup == popup ); // Consistency check. - - wxSize adjustedSize = m_popupInterface->GetAdjustedSize(widthPopup, - m_heightPopup<=0?DEFAULT_POPUP_HEIGHT:m_heightPopup, - maxHeightPopup); - - popup->SetSize(adjustedSize); - popup->Move(0,0); - m_popupInterface->OnPopup(); - - // - // Reposition and resize popup window - // - - wxSize szp = popup->GetSize(); - - int popupX; - int popupY = scrPos.y + ctrlSz.y; - - // Default anchor is wxLEFT - int anchorSide = m_anchorSide; - if ( !anchorSide ) - anchorSide = wxLEFT; - - int rightX = scrPos.x + ctrlSz.x + m_extRight - szp.x; - int leftX = scrPos.x - m_extLeft; - - if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ) - leftX -= ctrlSz.x; - - int screenWidth = wxSystemSettings::GetMetric( wxSYS_SCREEN_X ); - - // If there is not enough horizontal space, anchor on the other side. - // If there is no space even then, place the popup at x 0. - if ( anchorSide == wxRIGHT ) - { - if ( rightX < 0 ) - { - if ( (leftX+szp.x) < screenWidth ) - anchorSide = wxLEFT; - else - anchorSide = 0; - } - } - else - { - if ( (leftX+szp.x) >= screenWidth ) - { - if ( rightX >= 0 ) - anchorSide = wxRIGHT; - else - anchorSide = 0; - } - } - - // Select x coordinate according to the anchor side - if ( anchorSide == wxRIGHT ) - popupX = rightX; - else if ( anchorSide == wxLEFT ) - popupX = leftX; - else - popupX = 0; - - int showFlags = CanDeferShow; - - if ( spaceBelow < szp.y ) - { - popupY = scrPos.y - szp.y; - showFlags |= ShowAbove; - } - -#if INSTALL_TOPLEV_HANDLER - // Put top level window event handler into place - if ( m_popupWinType == POPUPWIN_WXPOPUPWINDOW ) - { - if ( !m_toplevEvtHandler ) - m_toplevEvtHandler = new wxComboFrameEventHandler(this); - - wxWindow* toplev = ::wxGetTopLevelParent( this ); - wxASSERT( toplev ); - ((wxComboFrameEventHandler*)m_toplevEvtHandler)->OnPopup(); - toplev->PushEventHandler( m_toplevEvtHandler ); - } -#endif - - // Set string selection (must be this way instead of SetStringSelection) - if ( m_text ) - { - if ( !(m_iFlags & wxCC_NO_TEXT_AUTO_SELECT) ) - m_text->SelectAll(); - - m_popupInterface->SetStringValue( m_text->GetValue() ); - } - else - { - // This is neede since focus/selection indication may change when popup is shown - Refresh(); - } - - // This must be after SetStringValue - m_popupWinState = Animating; - - wxRect popupWinRect( popupX, popupY, szp.x, szp.y ); - - m_popup = popup; - if ( (m_iFlags & wxCC_IFLAG_DISABLE_POPUP_ANIM) || - AnimateShow( popupWinRect, showFlags ) ) - { - DoShowPopup( popupWinRect, showFlags ); - } -} - -bool wxComboCtrlBase::AnimateShow( const wxRect& WXUNUSED(rect), int WXUNUSED(flags) ) -{ - return true; -} - -void wxComboCtrlBase::DoShowPopup( const wxRect& rect, int WXUNUSED(flags) ) -{ - wxWindow* winPopup = m_winPopup; - - if ( IsPopupWindowState(Animating) ) - { - // Make sure the popup window is shown in the right position. - // Should not matter even if animation already did this. - - // Some platforms (GTK) may like SetSize and Move to be separate - // (though the bug was probably fixed). - winPopup->SetSize( rect ); - - winPopup->Show(); - - m_popupWinState = Visible; - } - else if ( IsPopupWindowState(Hidden) ) - { - // Animation was aborted - - wxASSERT( !winPopup->IsShown() ); - - m_popupWinState = Hidden; - } -} - -void wxComboCtrlBase::OnPopupDismiss() -{ - // Just in case, avoid double dismiss - if ( IsPopupWindowState(Hidden) ) - return; - - // This must be set before focus - otherwise there will be recursive - // OnPopupDismisses. - m_popupWinState = Hidden; - - //SetFocus(); - m_winPopup->Disable(); - - // Inform popup control itself - m_popupInterface->OnDismiss(); - - if ( m_popupExtraHandler ) - ((wxComboPopupExtraEventHandler*)m_popupExtraHandler)->OnPopupDismiss(); - -#if INSTALL_TOPLEV_HANDLER - // Remove top level window event handler - if ( m_toplevEvtHandler ) - { - wxWindow* toplev = ::wxGetTopLevelParent( this ); - if ( toplev ) - toplev->RemoveEventHandler( m_toplevEvtHandler ); - } -#endif - - m_timeCanAcceptClick = ::wxGetLocalTimeMillis(); - - if ( m_popupWinType == POPUPWIN_WXPOPUPTRANSIENTWINDOW ) - m_timeCanAcceptClick += 150; - - // If cursor not on dropdown button, then clear its state - // (technically not required by all ports, but do it for all just in case) - if ( !m_btnArea.Contains(ScreenToClient(::wxGetMousePosition())) ) - m_btnState = 0; - - // Return parent's tab traversal flag. - // See ShowPopup for notes. - if ( m_iFlags & wxCC_IFLAG_PARENT_TAB_TRAVERSAL ) - { - wxWindow* parent = GetParent(); - parent->SetWindowStyle( parent->GetWindowStyle() | wxTAB_TRAVERSAL ); - m_iFlags &= ~(wxCC_IFLAG_PARENT_TAB_TRAVERSAL); - } - - // refresh control (necessary even if m_text) - Refresh(); - - SetFocus(); -} - -void wxComboCtrlBase::HidePopup() -{ - // Should be able to call this without popup interface - if ( IsPopupWindowState(Hidden) ) - return; - - // transfer value and show it in textctrl, if any - if ( !IsPopupWindowState(Animating) ) - SetValue( m_popupInterface->GetStringValue() ); - - m_winPopup->Hide(); - - OnPopupDismiss(); -} - -// ---------------------------------------------------------------------------- -// customization methods -// ---------------------------------------------------------------------------- - -void wxComboCtrlBase::SetButtonPosition( int width, int height, - int side, int spacingX ) -{ - m_btnWid = width; - m_btnHei = height; - m_btnSide = side; - m_btnSpacingX = spacingX; - - if ( width > 0 || height > 0 || spacingX ) - m_iFlags |= wxCC_IFLAG_HAS_NONSTANDARD_BUTTON; - - RecalcAndRefresh(); -} - -wxSize wxComboCtrlBase::GetButtonSize() -{ - if ( m_btnSize.x > 0 ) - return m_btnSize; - - wxSize retSize(m_btnWid,m_btnHei); - - // Need to call CalculateAreas now if button size is - // is not explicitly specified. - if ( retSize.x <= 0 || retSize.y <= 0) - { - OnResize(); - - retSize = m_btnSize; - } - - return retSize; -} - -void wxComboCtrlBase::SetButtonBitmaps( const wxBitmap& bmpNormal, - bool blankButtonBg, - const wxBitmap& bmpPressed, - const wxBitmap& bmpHover, - const wxBitmap& bmpDisabled ) -{ - m_bmpNormal = bmpNormal; - m_blankButtonBg = blankButtonBg; - - if ( bmpPressed.Ok() ) - m_bmpPressed = bmpPressed; - else - m_bmpPressed = bmpNormal; - - if ( bmpHover.Ok() ) - m_bmpHover = bmpHover; - else - m_bmpHover = bmpNormal; - - if ( bmpDisabled.Ok() ) - m_bmpDisabled = bmpDisabled; - else - m_bmpDisabled = bmpNormal; - - RecalcAndRefresh(); -} - -void wxComboCtrlBase::SetCustomPaintWidth( int width ) -{ - if ( m_text ) - { - // move textctrl accordingly - wxRect r = m_text->GetRect(); - int inc = width - m_widthCustomPaint; - r.x += inc; - r.width -= inc; - m_text->SetSize( r ); - } - - m_widthCustomPaint = width; - - RecalcAndRefresh(); -} - -void wxComboCtrlBase::SetTextIndent( int indent ) -{ - if ( indent < 0 ) - { - m_absIndent = GetNativeTextIndent(); - m_iFlags &= ~(wxCC_IFLAG_INDENT_SET); - } - else - { - m_absIndent = indent; - m_iFlags |= wxCC_IFLAG_INDENT_SET; - } - - RecalcAndRefresh(); -} - -wxCoord wxComboCtrlBase::GetNativeTextIndent() const -{ - return DEFAULT_TEXT_INDENT; -} - -// ---------------------------------------------------------------------------- -// methods forwarded to wxTextCtrl -// ---------------------------------------------------------------------------- - -wxString wxComboCtrlBase::GetValue() const -{ - if ( m_text ) - return m_text->GetValue(); - return m_valueString; -} - -void wxComboCtrlBase::SetValueWithEvent(const wxString& value, bool withEvent) -{ - if ( m_text ) - { - if ( !withEvent ) - m_ignoreEvtText++; - - m_text->SetValue(value); - if ( !(m_iFlags & wxCC_NO_TEXT_AUTO_SELECT) ) - m_text->SelectAll(); - } - - // Since wxComboPopup may want to paint the combo as well, we need - // to set the string value here (as well as sometimes in ShowPopup). - if ( m_valueString != value ) - { - m_valueString = value; - - EnsurePopupControl(); - - if (m_popupInterface) - m_popupInterface->SetStringValue(value); - } - - Refresh(); -} - -void wxComboCtrlBase::SetValue(const wxString& value) -{ - SetValueWithEvent(value, false); -} - -// In this SetValue variant wxComboPopup::SetStringValue is not called -void wxComboCtrlBase::SetText(const wxString& value) -{ - // Unlike in SetValue(), this must be called here or - // the behaviour will no be consistent in readonlys. - EnsurePopupControl(); - - m_valueString = value; - - if ( m_text ) - { - m_ignoreEvtText++; - m_text->SetValue( value ); - } - - Refresh(); -} - -void wxComboCtrlBase::Copy() -{ - if ( m_text ) - m_text->Copy(); -} - -void wxComboCtrlBase::Cut() -{ - if ( m_text ) - m_text->Cut(); -} - -void wxComboCtrlBase::Paste() -{ - if ( m_text ) - m_text->Paste(); -} - -void wxComboCtrlBase::SetInsertionPoint(long pos) -{ - if ( m_text ) - m_text->SetInsertionPoint(pos); -} - -void wxComboCtrlBase::SetInsertionPointEnd() -{ - if ( m_text ) - m_text->SetInsertionPointEnd(); -} - -long wxComboCtrlBase::GetInsertionPoint() const -{ - if ( m_text ) - return m_text->GetInsertionPoint(); - - return 0; -} - -long wxComboCtrlBase::GetLastPosition() const -{ - if ( m_text ) - return m_text->GetLastPosition(); - - return 0; -} - -void wxComboCtrlBase::Replace(long from, long to, const wxString& value) -{ - if ( m_text ) - m_text->Replace(from, to, value); -} - -void wxComboCtrlBase::Remove(long from, long to) -{ - if ( m_text ) - m_text->Remove(from, to); -} - -void wxComboCtrlBase::SetSelection(long from, long to) -{ - if ( m_text ) - m_text->SetSelection(from, to); -} - -void wxComboCtrlBase::Undo() -{ - if ( m_text ) - m_text->Undo(); -} - -#endif // wxUSE_COMBOCTRL +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/combocmn.cpp +// Purpose: wxComboCtrlBase +// Author: Jaakko Salli +// Modified by: +// Created: Apr-30-2006 +// RCS-ID: $Id: combocmn.cpp 67178 2011-03-13 09:32:19Z JMS $ +// Copyright: (c) 2005 Jaakko Salli +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_COMBOCTRL + +#include "wx/combobox.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/log.h" + #include "wx/dcclient.h" + #include "wx/settings.h" + #include "wx/dialog.h" + #include "wx/timer.h" +#endif + +#include "wx/tooltip.h" + +#include "wx/combo.h" + + + +// constants +// ---------------------------------------------------------------------------- + +#define DEFAULT_DROPBUTTON_WIDTH 19 + +#define BMP_BUTTON_MARGIN 4 + +#define DEFAULT_POPUP_HEIGHT 400 + +#define DEFAULT_TEXT_INDENT 3 + +#define COMBO_MARGIN 2 // spacing right of wxTextCtrl + + +#if defined(__WXMSW__) + +#define USE_TRANSIENT_POPUP 1 // Use wxPopupWindowTransient (preferred, if it works properly on platform) +#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common + // native controls work on it like normal. +#define POPUPWIN_IS_PERFECT 0 // Same, but for non-transient popup window. +#define TEXTCTRL_TEXT_CENTERED 0 // 1 if text in textctrl is vertically centered +#define FOCUS_RING 0 // No focus ring on wxMSW + +//#undef wxUSE_POPUPWIN +//#define wxUSE_POPUPWIN 0 + +#elif defined(__WXGTK__) + +// NB: It is not recommended to use wxDialog as popup on wxGTK, because of +// this bug: If wxDialog is hidden, its position becomes corrupt +// between hide and next show, but without internal coordinates being +// reflected (or something like that - atleast commenting out ->Hide() +// seemed to eliminate the position change). + +#define USE_TRANSIENT_POPUP 1 // Use wxPopupWindowTransient (preferred, if it works properly on platform) +#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common + // native controls work on it like normal. +#define POPUPWIN_IS_PERFECT 1 // Same, but for non-transient popup window. +#define TEXTCTRL_TEXT_CENTERED 1 // 1 if text in textctrl is vertically centered +#define FOCUS_RING 0 // No focus ring on wxGTK + +#elif defined(__WXMAC__) + +#define USE_TRANSIENT_POPUP 0 // Use wxPopupWindowTransient (preferred, if it works properly on platform) +#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common + // native controls work on it like normal. +#define POPUPWIN_IS_PERFECT 0 // Same, but for non-transient popup window. +#define TEXTCTRL_TEXT_CENTERED 1 // 1 if text in textctrl is vertically centered +#define FOCUS_RING 3 // Reserve room for the textctrl's focus ring to display + +#undef DEFAULT_DROPBUTTON_WIDTH +#define DEFAULT_DROPBUTTON_WIDTH 22 +#undef COMBO_MARGIN +#define COMBO_MARGIN FOCUS_RING + +#else + +#define USE_TRANSIENT_POPUP 0 // Use wxPopupWindowTransient (preferred, if it works properly on platform) +#define TRANSIENT_POPUPWIN_IS_PERFECT 0 // wxPopupTransientWindow works, its child can have focus, and common + // native controls work on it like normal. +#define POPUPWIN_IS_PERFECT 0 // Same, but for non-transient popup window. +#define TEXTCTRL_TEXT_CENTERED 1 // 1 if text in textctrl is vertically centered +#define FOCUS_RING 0 + +#endif + + +// Popupwin is really only supported on wxMSW (not WINCE) and wxGTK, regardless +// what the wxUSE_POPUPWIN says. +// FIXME: Why isn't wxUSE_POPUPWIN reliable any longer? (it was in wxW2.6.2) +#if (!defined(__WXMSW__) && !defined(__WXGTK__)) || defined(__WXWINCE__) +#undef wxUSE_POPUPWIN +#define wxUSE_POPUPWIN 0 +#endif + + +#if wxUSE_POPUPWIN + #include "wx/popupwin.h" +#else + #undef USE_TRANSIENT_POPUP + #define USE_TRANSIENT_POPUP 0 +#endif + + +// Define different types of popup windows +enum +{ + POPUPWIN_NONE = 0, + POPUPWIN_WXPOPUPTRANSIENTWINDOW = 1, + POPUPWIN_WXPOPUPWINDOW = 2, + POPUPWIN_WXDIALOG = 3 +}; + + +#if USE_TRANSIENT_POPUP + // wxPopupTransientWindow is implemented + + #define wxComboPopupWindowBase wxPopupTransientWindow + #define PRIMARY_POPUP_TYPE POPUPWIN_WXPOPUPTRANSIENTWINDOW + #define USES_WXPOPUPTRANSIENTWINDOW 1 + + #if TRANSIENT_POPUPWIN_IS_PERFECT + // + #elif POPUPWIN_IS_PERFECT + #define wxComboPopupWindowBase2 wxPopupWindow + #define SECONDARY_POPUP_TYPE POPUPWIN_WXPOPUPWINDOW + #define USES_WXPOPUPWINDOW 1 + #else + #define wxComboPopupWindowBase2 wxDialog + #define SECONDARY_POPUP_TYPE POPUPWIN_WXDIALOG + #define USES_WXDIALOG 1 + #endif + +#elif wxUSE_POPUPWIN + // wxPopupWindow (but not wxPopupTransientWindow) is properly implemented + + #define wxComboPopupWindowBase wxPopupWindow + #define PRIMARY_POPUP_TYPE POPUPWIN_WXPOPUPWINDOW + #define USES_WXPOPUPWINDOW 1 + + #if !POPUPWIN_IS_PERFECT + #define wxComboPopupWindowBase2 wxDialog + #define SECONDARY_POPUP_TYPE POPUPWIN_WXDIALOG + #define USES_WXDIALOG 1 + #endif + +#else + // wxPopupWindow is not implemented + + #define wxComboPopupWindowBase wxDialog + #define PRIMARY_POPUP_TYPE POPUPWIN_WXDIALOG + #define USES_WXDIALOG 1 + +#endif + + +#ifndef USES_WXPOPUPTRANSIENTWINDOW + #define USES_WXPOPUPTRANSIENTWINDOW 0 +#endif + +#ifndef USES_WXPOPUPWINDOW + #define USES_WXPOPUPWINDOW 0 +#endif + +#ifndef USES_WXDIALOG + #define USES_WXDIALOG 0 +#endif + + +#if USES_WXPOPUPWINDOW + #define INSTALL_TOPLEV_HANDLER 1 +#else + #define INSTALL_TOPLEV_HANDLER 0 +#endif + + +// +// ** TODO ** +// * wxComboPopupWindow for external use (ie. replace old wxUniv wxPopupComboWindow) +// + + +// ---------------------------------------------------------------------------- +// wxComboFrameEventHandler takes care of hiding the popup when events happen +// in its top level parent. +// ---------------------------------------------------------------------------- + +#if INSTALL_TOPLEV_HANDLER + +// +// This will no longer be necessary after wxTransientPopupWindow +// works well on all platforms. +// + +class wxComboFrameEventHandler : public wxEvtHandler +{ +public: + wxComboFrameEventHandler( wxComboCtrlBase* pCb ); + virtual ~wxComboFrameEventHandler(); + + void OnPopup(); + + void OnIdle( wxIdleEvent& event ); + void OnMouseEvent( wxMouseEvent& event ); + void OnActivate( wxActivateEvent& event ); + void OnResize( wxSizeEvent& event ); + void OnMove( wxMoveEvent& event ); + void OnMenuEvent( wxMenuEvent& event ); + void OnClose( wxCloseEvent& event ); + +protected: + wxWindow* m_focusStart; + wxComboCtrlBase* m_combo; + +private: + DECLARE_EVENT_TABLE() +}; + +BEGIN_EVENT_TABLE(wxComboFrameEventHandler, wxEvtHandler) + EVT_IDLE(wxComboFrameEventHandler::OnIdle) + EVT_LEFT_DOWN(wxComboFrameEventHandler::OnMouseEvent) + EVT_RIGHT_DOWN(wxComboFrameEventHandler::OnMouseEvent) + EVT_SIZE(wxComboFrameEventHandler::OnResize) + EVT_MOVE(wxComboFrameEventHandler::OnMove) + EVT_MENU_HIGHLIGHT(wxID_ANY,wxComboFrameEventHandler::OnMenuEvent) + EVT_MENU_OPEN(wxComboFrameEventHandler::OnMenuEvent) + EVT_ACTIVATE(wxComboFrameEventHandler::OnActivate) + EVT_CLOSE(wxComboFrameEventHandler::OnClose) +END_EVENT_TABLE() + +wxComboFrameEventHandler::wxComboFrameEventHandler( wxComboCtrlBase* combo ) + : wxEvtHandler() +{ + m_combo = combo; +} + +wxComboFrameEventHandler::~wxComboFrameEventHandler() +{ +} + +void wxComboFrameEventHandler::OnPopup() +{ + m_focusStart = ::wxWindow::FindFocus(); +} + +void wxComboFrameEventHandler::OnIdle( wxIdleEvent& event ) +{ + wxWindow* winFocused = ::wxWindow::FindFocus(); + + wxWindow* popup = m_combo->GetPopupControl()->GetControl(); + wxWindow* winpopup = m_combo->GetPopupWindow(); + + if ( + winFocused != m_focusStart && + winFocused != popup && + winFocused->GetParent() != popup && + winFocused != winpopup && + winFocused->GetParent() != winpopup && + winFocused != m_combo && + winFocused != m_combo->GetButton() // GTK (atleast) requires this + ) + { + m_combo->HidePopup(); + } + + event.Skip(); +} + +void wxComboFrameEventHandler::OnMenuEvent( wxMenuEvent& event ) +{ + m_combo->HidePopup(); + event.Skip(); +} + +void wxComboFrameEventHandler::OnMouseEvent( wxMouseEvent& event ) +{ + m_combo->HidePopup(); + event.Skip(); +} + +void wxComboFrameEventHandler::OnClose( wxCloseEvent& event ) +{ + m_combo->HidePopup(); + event.Skip(); +} + +void wxComboFrameEventHandler::OnActivate( wxActivateEvent& event ) +{ + m_combo->HidePopup(); + event.Skip(); +} + +void wxComboFrameEventHandler::OnResize( wxSizeEvent& event ) +{ + m_combo->HidePopup(); + event.Skip(); +} + +void wxComboFrameEventHandler::OnMove( wxMoveEvent& event ) +{ + m_combo->HidePopup(); + event.Skip(); +} + +#endif // INSTALL_TOPLEV_HANDLER + +// ---------------------------------------------------------------------------- +// wxComboPopupWindow is, in essence, wxPopupWindow customized for +// wxComboCtrl. +// ---------------------------------------------------------------------------- + +class wxComboPopupWindow : public wxComboPopupWindowBase +{ +public: + + wxComboPopupWindow( wxComboCtrlBase *parent, + int style ) + #if USES_WXPOPUPWINDOW || USES_WXPOPUPTRANSIENTWINDOW + : wxComboPopupWindowBase(parent,style) + #else + : wxComboPopupWindowBase(parent, + wxID_ANY, + wxEmptyString, + wxPoint(-21,-21), + wxSize(20,20), + style) + #endif + { + m_inShow = 0; + } + +#if USES_WXPOPUPTRANSIENTWINDOW + virtual bool Show( bool show ); + virtual bool ProcessLeftDown(wxMouseEvent& event); +protected: + virtual void OnDismiss(); +#endif + +private: + wxByte m_inShow; +}; + + +#if USES_WXPOPUPTRANSIENTWINDOW +bool wxComboPopupWindow::Show( bool show ) +{ + // Guard against recursion + if ( m_inShow ) + return wxComboPopupWindowBase::Show(show); + + m_inShow++; + + wxASSERT( IsKindOf(CLASSINFO(wxPopupTransientWindow)) ); + + wxPopupTransientWindow* ptw = (wxPopupTransientWindow*) this; + wxComboCtrlBase* combo = (wxComboCtrlBase*) GetParent(); + + if ( show != ptw->IsShown() ) + { + if ( show ) + ptw->Popup(combo->GetPopupControl()->GetControl()); + else + ptw->Dismiss(); + } + + m_inShow--; + + return true; +} + +bool wxComboPopupWindow::ProcessLeftDown(wxMouseEvent& event) +{ + return wxPopupTransientWindow::ProcessLeftDown(event); +} + +// First thing that happens when a transient popup closes is that this method gets called. +void wxComboPopupWindow::OnDismiss() +{ + wxComboCtrlBase* combo = (wxComboCtrlBase*) GetParent(); + wxASSERT_MSG( combo->IsKindOf(CLASSINFO(wxComboCtrlBase)), + wxT("parent might not be wxComboCtrl, but check IMPLEMENT_DYNAMIC_CLASS(2) macro for correctness") ); + + combo->OnPopupDismiss(); +} +#endif // USES_WXPOPUPTRANSIENTWINDOW + + +// ---------------------------------------------------------------------------- +// wxComboPopupWindowEvtHandler does bulk of the custom event handling +// of a popup window. It is separate so we can have different types +// of popup windows. +// ---------------------------------------------------------------------------- + +class wxComboPopupWindowEvtHandler : public wxEvtHandler +{ +public: + + wxComboPopupWindowEvtHandler( wxComboCtrlBase *parent ) + { + m_combo = parent; + } + + void OnSizeEvent( wxSizeEvent& event ); + void OnKeyEvent(wxKeyEvent& event); +#if USES_WXDIALOG + void OnActivate( wxActivateEvent& event ); +#endif + +private: + wxComboCtrlBase* m_combo; + + DECLARE_EVENT_TABLE() +}; + + +BEGIN_EVENT_TABLE(wxComboPopupWindowEvtHandler, wxEvtHandler) + EVT_KEY_DOWN(wxComboPopupWindowEvtHandler::OnKeyEvent) + EVT_KEY_UP(wxComboPopupWindowEvtHandler::OnKeyEvent) +#if USES_WXDIALOG + EVT_ACTIVATE(wxComboPopupWindowEvtHandler::OnActivate) +#endif + EVT_SIZE(wxComboPopupWindowEvtHandler::OnSizeEvent) +END_EVENT_TABLE() + + +void wxComboPopupWindowEvtHandler::OnSizeEvent( wxSizeEvent& WXUNUSED(event) ) +{ + // Block the event so that the popup control does not get auto-resized. +} + +void wxComboPopupWindowEvtHandler::OnKeyEvent( wxKeyEvent& event ) +{ + // Relay keyboard event to the main child controls + wxWindowList children = m_combo->GetPopupWindow()->GetChildren(); + wxWindowList::iterator node = children.begin(); + wxWindow* child = (wxWindow*)*node; + child->AddPendingEvent(event); +} + +#if USES_WXDIALOG +void wxComboPopupWindowEvtHandler::OnActivate( wxActivateEvent& event ) +{ + if ( !event.GetActive() ) + { + // Tell combo control that we are dismissed. + m_combo->HidePopup(); + + event.Skip(); + } +} +#endif + + +// ---------------------------------------------------------------------------- +// wxComboPopup +// +// ---------------------------------------------------------------------------- + +wxComboPopup::~wxComboPopup() +{ +} + +void wxComboPopup::OnPopup() +{ +} + +void wxComboPopup::OnDismiss() +{ +} + +wxSize wxComboPopup::GetAdjustedSize( int minWidth, + int prefHeight, + int WXUNUSED(maxHeight) ) +{ + return wxSize(minWidth,prefHeight); +} + +void wxComboPopup::DefaultPaintComboControl( wxComboCtrlBase* combo, + wxDC& dc, const wxRect& rect ) +{ + if ( combo->GetWindowStyle() & wxCB_READONLY ) // ie. no textctrl + { + combo->PrepareBackground(dc,rect,0); + + dc.DrawText( combo->GetValue(), + rect.x + combo->GetTextIndent(), + (rect.height-dc.GetCharHeight())/2 + rect.y ); + } +} + +void wxComboPopup::PaintComboControl( wxDC& dc, const wxRect& rect ) +{ + DefaultPaintComboControl(m_combo,dc,rect); +} + +void wxComboPopup::OnComboKeyEvent( wxKeyEvent& event ) +{ + event.Skip(); +} + +void wxComboPopup::OnComboDoubleClick() +{ +} + +void wxComboPopup::SetStringValue( const wxString& WXUNUSED(value) ) +{ +} + +bool wxComboPopup::LazyCreate() +{ + return false; +} + +void wxComboPopup::Dismiss() +{ + m_combo->HidePopup(); +} + +// ---------------------------------------------------------------------------- +// input handling +// ---------------------------------------------------------------------------- + +// +// This is pushed to the event handler queue of the child textctrl. +// +class wxComboBoxExtraInputHandler : public wxEvtHandler +{ +public: + + wxComboBoxExtraInputHandler( wxComboCtrlBase* combo ) + : wxEvtHandler() + { + m_combo = combo; + } + virtual ~wxComboBoxExtraInputHandler() { } + void OnKey(wxKeyEvent& event); + void OnFocus(wxFocusEvent& event); + +protected: + wxComboCtrlBase* m_combo; + +private: + DECLARE_EVENT_TABLE() +}; + + +BEGIN_EVENT_TABLE(wxComboBoxExtraInputHandler, wxEvtHandler) + EVT_KEY_DOWN(wxComboBoxExtraInputHandler::OnKey) + EVT_KEY_UP(wxComboBoxExtraInputHandler::OnKey) + EVT_CHAR(wxComboBoxExtraInputHandler::OnKey) + EVT_SET_FOCUS(wxComboBoxExtraInputHandler::OnFocus) +END_EVENT_TABLE() + + +void wxComboBoxExtraInputHandler::OnKey(wxKeyEvent& event) +{ + // Let the wxComboCtrl event handler have a go first. + wxComboCtrlBase* combo = m_combo; + + wxKeyEvent redirectedEvent(event); + redirectedEvent.SetId(combo->GetId()); + redirectedEvent.SetEventObject(combo); + + if ( !combo->GetEventHandler()->ProcessEvent(redirectedEvent) ) + { + // Don't let TAB through to the text ctrl - looks ugly + if ( event.GetKeyCode() != WXK_TAB ) + event.Skip(); + } +} + +void wxComboBoxExtraInputHandler::OnFocus(wxFocusEvent& event) +{ + // FIXME: This code does run when control is clicked, + // yet on Windows it doesn't select all the text. + if ( !(m_combo->GetInternalFlags() & wxCC_NO_TEXT_AUTO_SELECT) ) + { + if ( m_combo->GetTextCtrl() ) + m_combo->GetTextCtrl()->SelectAll(); + else + m_combo->SetSelection(-1,-1); + } + + // Send focus indication to parent. + // NB: This is needed for cases where the textctrl gets focus + // instead of its parent. While this may trigger multiple + // wxEVT_SET_FOCUSes (since m_text->SetFocus is called + // from combo's focus event handler), they should be quite + // harmless. + wxFocusEvent evt2(wxEVT_SET_FOCUS,m_combo->GetId()); + evt2.SetEventObject(m_combo); + m_combo->GetEventHandler()->ProcessEvent(evt2); + + event.Skip(); +} + + +// +// This is pushed to the event handler queue of the control in popup. +// + +class wxComboPopupExtraEventHandler : public wxEvtHandler +{ +public: + + wxComboPopupExtraEventHandler( wxComboCtrlBase* combo ) + : wxEvtHandler() + { + m_combo = combo; + m_beenInside = false; + } + virtual ~wxComboPopupExtraEventHandler() { } + + void OnMouseEvent( wxMouseEvent& event ); + + // Called from wxComboCtrlBase::OnPopupDismiss + void OnPopupDismiss() + { + m_beenInside = false; + } + +protected: + wxComboCtrlBase* m_combo; + + bool m_beenInside; + +private: + DECLARE_EVENT_TABLE() +}; + + +BEGIN_EVENT_TABLE(wxComboPopupExtraEventHandler, wxEvtHandler) + EVT_MOUSE_EVENTS(wxComboPopupExtraEventHandler::OnMouseEvent) +END_EVENT_TABLE() + + +void wxComboPopupExtraEventHandler::OnMouseEvent( wxMouseEvent& event ) +{ + wxPoint pt = event.GetPosition(); + wxSize sz = m_combo->GetPopupControl()->GetControl()->GetClientSize(); + int evtType = event.GetEventType(); + bool isInside = pt.x >= 0 && pt.y >= 0 && pt.x < sz.x && pt.y < sz.y; + + if ( evtType == wxEVT_MOTION || + evtType == wxEVT_LEFT_DOWN || + evtType == wxEVT_RIGHT_DOWN ) + { + // Block motion and click events outside the popup + if ( !isInside || !m_combo->IsPopupShown() ) + { + event.Skip(false); + return; + } + } + else if ( evtType == wxEVT_LEFT_UP ) + { + if ( !m_combo->IsPopupShown() ) + { + event.Skip(false); + return; + } + + if ( !m_beenInside ) + { + if ( isInside ) + { + m_beenInside = true; + } + else + { + // + // Some mouse events to popup that happen outside it, before cursor + // has been inside the popu, need to be ignored by it but relayed to + // the dropbutton. + // + wxWindow* btn = m_combo->GetButton(); + if ( btn ) + btn->GetEventHandler()->AddPendingEvent(event); + else + m_combo->GetEventHandler()->AddPendingEvent(event); + + return; + } + + event.Skip(); + } + } + + event.Skip(); +} + +// ---------------------------------------------------------------------------- +// wxComboCtrlBase +// ---------------------------------------------------------------------------- + + +BEGIN_EVENT_TABLE(wxComboCtrlBase, wxControl) + EVT_TEXT(wxID_ANY,wxComboCtrlBase::OnTextCtrlEvent) + EVT_SIZE(wxComboCtrlBase::OnSizeEvent) + EVT_SET_FOCUS(wxComboCtrlBase::OnFocusEvent) + EVT_KILL_FOCUS(wxComboCtrlBase::OnFocusEvent) + EVT_IDLE(wxComboCtrlBase::OnIdleEvent) + //EVT_BUTTON(wxID_ANY,wxComboCtrlBase::OnButtonClickEvent) + EVT_KEY_DOWN(wxComboCtrlBase::OnKeyEvent) + EVT_TEXT_ENTER(wxID_ANY,wxComboCtrlBase::OnTextCtrlEvent) + EVT_SYS_COLOUR_CHANGED(wxComboCtrlBase::OnSysColourChanged) +END_EVENT_TABLE() + + +IMPLEMENT_ABSTRACT_CLASS(wxComboCtrlBase, wxControl) + +void wxComboCtrlBase::Init() +{ + m_winPopup = (wxWindow *)NULL; + m_popup = (wxWindow *)NULL; + m_popupWinState = Hidden; + m_btn = (wxWindow*) NULL; + m_text = (wxTextCtrl*) NULL; + m_popupInterface = (wxComboPopup*) NULL; + + m_popupExtraHandler = (wxEvtHandler*) NULL; + m_textEvtHandler = (wxEvtHandler*) NULL; + +#if INSTALL_TOPLEV_HANDLER + m_toplevEvtHandler = (wxEvtHandler*) NULL; +#endif + + m_mainCtrlWnd = this; + + m_heightPopup = -1; + m_widthMinPopup = -1; + m_anchorSide = 0; + m_widthCustomPaint = 0; + m_widthCustomBorder = 0; + + m_btnState = 0; + m_btnWidDefault = 0; + m_blankButtonBg = false; + m_ignoreEvtText = 0; + m_popupWinType = POPUPWIN_NONE; + m_btnWid = m_btnHei = -1; + m_btnSide = wxRIGHT; + m_btnSpacingX = 0; + + m_extLeft = 0; + m_extRight = 0; + m_absIndent = -1; + m_iFlags = 0; + m_timeCanAcceptClick = 0; + + m_resetFocus = false; +} + +bool wxComboCtrlBase::Create(wxWindow *parent, + wxWindowID id, + const wxString& value, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxControl::Create(parent, + id, + pos, + size, + style | wxWANTS_CHARS, + validator, + name) ) + return false; + + m_valueString = value; + + // Get colours + OnThemeChange(); + m_absIndent = GetNativeTextIndent(); + + m_iFlags |= wxCC_IFLAG_CREATED; + + // If x and y indicate valid size, wxSizeEvent won't be + // emitted automatically, so we need to add artifical one. + if ( size.x > 0 && size.y > 0 ) + { + wxSizeEvent evt(size,GetId()); + GetEventHandler()->AddPendingEvent(evt); + } + + return true; +} + +void wxComboCtrlBase::InstallInputHandlers() +{ + if ( m_text ) + { + m_textEvtHandler = new wxComboBoxExtraInputHandler(this); + m_text->PushEventHandler(m_textEvtHandler); + } +} + +void +wxComboCtrlBase::CreateTextCtrl(int style, const wxValidator& validator) +{ + if ( !(m_windowStyle & wxCB_READONLY) ) + { + if ( m_text ) + m_text->Destroy(); + + // wxTE_PROCESS_TAB is needed because on Windows, wxTAB_TRAVERSAL is + // not used by the wxPropertyGrid and therefore the tab is processed by + // looking at ancestors to see if they have wxTAB_TRAVERSAL. The + // navigation event is then sent to the wrong window. + style |= wxTE_PROCESS_TAB; + + if ( HasFlag(wxTE_PROCESS_ENTER) ) + style |= wxTE_PROCESS_ENTER; + + // Ignore EVT_TEXT generated by the constructor (but only + // if the event redirector already exists) + // NB: This must be " = 1" instead of "++"; + if ( m_textEvtHandler ) + m_ignoreEvtText = 1; + else + m_ignoreEvtText = 0; + + m_text = new wxTextCtrl(this, wxID_ANY, m_valueString, + wxDefaultPosition, wxSize(10,-1), + style, validator); + } +} + +void wxComboCtrlBase::OnThemeChange() +{ + // Leave the default bg on the Mac so the area used by the focus ring will + // be the correct colour and themed brush. Instead we'll use + // wxSYS_COLOUR_WINDOW in the EVT_PAINT handler as needed. +#ifndef __WXMAC__ + if ( !m_hasBgCol ) + { +#ifdef __WXGTK__ + // Set background to gtk_rc_get_style(m_widget)->bg[GTK_STATE_NORMAL], + // which can be different than the background of text entry. + wxColour bgCol = GetDefaultAttributes().colBg; +#else + wxColour bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); +#endif + SetOwnBackgroundColour(bgCol); + m_hasBgCol = false; + } +#endif +} + +wxComboCtrlBase::~wxComboCtrlBase() +{ + if ( HasCapture() ) + ReleaseMouse(); + +#if INSTALL_TOPLEV_HANDLER + delete ((wxComboFrameEventHandler*)m_toplevEvtHandler); + m_toplevEvtHandler = (wxEvtHandler*) NULL; +#endif + + DestroyPopup(); + + if ( m_text ) + m_text->RemoveEventHandler(m_textEvtHandler); + + delete m_textEvtHandler; +} + + +// ---------------------------------------------------------------------------- +// geometry stuff +// ---------------------------------------------------------------------------- + +// Recalculates button and textctrl areas +void wxComboCtrlBase::CalculateAreas( int btnWidth ) +{ + wxSize sz = GetClientSize(); + int customBorder = m_widthCustomBorder; + int btnBorder; // border for button only + + // check if button should really be outside the border: we'll do it it if + // its platform default or bitmap+pushbutton background is used, but not if + // there is vertical size adjustment or horizontal spacing. + if ( ( (m_iFlags & wxCC_BUTTON_OUTSIDE_BORDER) || + (m_bmpNormal.Ok() && m_blankButtonBg) ) && + m_btnSpacingX == 0 && + m_btnHei <= 0 ) + { + m_iFlags |= wxCC_IFLAG_BUTTON_OUTSIDE; + btnBorder = 0; + } + else + { + m_iFlags &= ~(wxCC_IFLAG_BUTTON_OUTSIDE); + btnBorder = customBorder; + } + + // Defaul indentation + if ( m_absIndent < 0 ) + m_absIndent = GetNativeTextIndent(); + + int butWidth = btnWidth; + + if ( butWidth <= 0 ) + butWidth = m_btnWidDefault; + else + m_btnWidDefault = butWidth; + + if ( butWidth <= 0 ) + return; + + int butHeight = sz.y - btnBorder*2; + + // Adjust button width + if ( m_btnWid > 0 ) + butWidth = m_btnWid; + else + { + // Adjust button width to match aspect ratio + // (but only if control is smaller than best size). + int bestHeight = GetBestSize().y; + int height = GetSize().y; + + if ( height < bestHeight ) + { + // Make very small buttons square, as it makes + // them accommodate arrow image better and still + // looks decent. + if ( height > 18 ) + butWidth = (height*butWidth)/bestHeight; + else + butWidth = butHeight; + } + } + + // Adjust button height + if ( m_btnHei > 0 ) + butHeight = m_btnHei; + + // Use size of normal bitmap if... + // It is larger + // OR + // button width is set to default and blank button bg is not drawn + if ( m_bmpNormal.Ok() ) + { + int bmpReqWidth = m_bmpNormal.GetWidth(); + int bmpReqHeight = m_bmpNormal.GetHeight(); + + // If drawing blank button background, we need to add some margin. + if ( m_blankButtonBg ) + { + bmpReqWidth += BMP_BUTTON_MARGIN*2; + bmpReqHeight += BMP_BUTTON_MARGIN*2; + } + + if ( butWidth < bmpReqWidth || ( m_btnWid == 0 && !m_blankButtonBg ) ) + butWidth = bmpReqWidth; + if ( butHeight < bmpReqHeight || ( m_btnHei == 0 && !m_blankButtonBg ) ) + butHeight = bmpReqHeight; + + // Need to fix height? + if ( (sz.y-(customBorder*2)) < butHeight && btnWidth == 0 ) + { + int newY = butHeight+(customBorder*2); + SetClientSize(wxDefaultCoord,newY); + sz.y = newY; + } + } + + int butAreaWid = butWidth + (m_btnSpacingX*2); + + m_btnSize.x = butWidth; + m_btnSize.y = butHeight; + + m_btnArea.x = ( m_btnSide==wxRIGHT ? sz.x - butAreaWid - btnBorder : btnBorder ); + m_btnArea.y = btnBorder + FOCUS_RING; + m_btnArea.width = butAreaWid; + m_btnArea.height = sz.y - ((btnBorder+FOCUS_RING)*2); + + m_tcArea.x = ( m_btnSide==wxRIGHT ? 0 : butAreaWid ) + customBorder + FOCUS_RING; + m_tcArea.y = customBorder + FOCUS_RING; + m_tcArea.width = sz.x - butAreaWid - (customBorder*2) - (FOCUS_RING*2); + m_tcArea.height = sz.y - ((customBorder+FOCUS_RING)*2); + +/* + if ( m_text ) + { + ::wxMessageBox(wxString::Format(wxT("ButtonArea (%i,%i,%i,%i)\n"),m_btnArea.x,m_btnArea.y,m_btnArea.width,m_btnArea.height) + + wxString::Format(wxT("TextCtrlArea (%i,%i,%i,%i)"),m_tcArea.x,m_tcArea.y,m_tcArea.width,m_tcArea.height)); + } +*/ +} + +void wxComboCtrlBase::PositionTextCtrl( int textCtrlXAdjust, int textCtrlYAdjust ) +{ + if ( !m_text ) + return; + +#if !TEXTCTRL_TEXT_CENTERED + + wxSize sz = GetClientSize(); + + int customBorder = m_widthCustomBorder; + if ( (m_text->GetWindowStyleFlag() & wxBORDER_MASK) == wxNO_BORDER ) + { + // Centre textctrl + int tcSizeY = m_text->GetBestSize().y; + int diff = sz.y - tcSizeY; + int y = textCtrlYAdjust + (diff/2); + + if ( y < customBorder ) + y = customBorder; + + m_text->SetSize( m_tcArea.x + m_widthCustomPaint + m_absIndent + textCtrlXAdjust, + y, + m_tcArea.width - COMBO_MARGIN - + (textCtrlXAdjust + m_widthCustomPaint + m_absIndent), + -1 ); + + // Make sure textctrl doesn't exceed the bottom custom border + wxSize tsz = m_text->GetSize(); + diff = (y + tsz.y) - (sz.y - customBorder); + if ( diff >= 0 ) + { + tsz.y = tsz.y - diff - 1; + m_text->SetSize(tsz); + } + } + else +#else // TEXTCTRL_TEXT_CENTERED + wxUnusedVar(textCtrlXAdjust); + wxUnusedVar(textCtrlYAdjust); +#endif // !TEXTCTRL_TEXT_CENTERED/TEXTCTRL_TEXT_CENTERED + { + // If it has border, have textctrl will the entire text field. + m_text->SetSize( m_tcArea.x + m_widthCustomPaint, + m_tcArea.y, + m_tcArea.width - m_widthCustomPaint, + m_tcArea.height ); + } +} + +wxSize wxComboCtrlBase::DoGetBestSize() const +{ + wxSize sizeText(150,0); + + if ( m_text ) + sizeText = m_text->GetBestSize(); + + // TODO: Better method to calculate close-to-native control height. + + int fhei; + if ( m_font.Ok() ) + fhei = (m_font.GetPointSize()*2) + 5; + else if ( wxNORMAL_FONT->Ok() ) + fhei = (wxNORMAL_FONT->GetPointSize()*2) + 5; + else + fhei = sizeText.y + 4; + + // Need to force height to accomodate bitmap? + int btnSizeY = m_btnSize.y; + if ( m_bmpNormal.Ok() && fhei < btnSizeY ) + fhei = btnSizeY; + + // Control height doesn't depend on border +/* + // Add border + int border = m_windowStyle & wxBORDER_MASK; + if ( border == wxSIMPLE_BORDER ) + fhei += 2; + else if ( border == wxNO_BORDER ) + fhei += (m_widthCustomBorder*2); + else + // Sunken etc. + fhei += 4; +*/ + + // Final adjustments +#ifdef __WXGTK__ + fhei += 1; +#endif + +#ifdef __WXMAC__ + // these are the numbers from the HIG: + switch ( m_windowVariant ) + { + case wxWINDOW_VARIANT_NORMAL: + default : + fhei = 22; + break; + case wxWINDOW_VARIANT_SMALL: + fhei = 19; + break; + case wxWINDOW_VARIANT_MINI: + fhei = 15; + break; + } +#endif + + fhei += 2 * FOCUS_RING; + int width = sizeText.x + FOCUS_RING + COMBO_MARGIN + DEFAULT_DROPBUTTON_WIDTH; + + wxSize ret(width, fhei); + CacheBestSize(ret); + return ret; +} + +void wxComboCtrlBase::OnSizeEvent( wxSizeEvent& event ) +{ + if ( !IsCreated() ) + return; + + // defined by actual wxComboCtrls + OnResize(); + + event.Skip(); +} + +// ---------------------------------------------------------------------------- +// standard operations +// ---------------------------------------------------------------------------- + +bool wxComboCtrlBase::Enable(bool enable) +{ + if ( !wxControl::Enable(enable) ) + return false; + + if ( m_btn ) + m_btn->Enable(enable); + if ( m_text ) + m_text->Enable(enable); + + Refresh(); + + return true; +} + +bool wxComboCtrlBase::Show(bool show) +{ + if ( !wxControl::Show(show) ) + return false; + + if (m_btn) + m_btn->Show(show); + + if (m_text) + m_text->Show(show); + + return true; +} + +bool wxComboCtrlBase::SetFont ( const wxFont& font ) +{ + if ( !wxControl::SetFont(font) ) + return false; + + if (m_text) + m_text->SetFont(font); + + return true; +} + +#if wxUSE_TOOLTIPS +void wxComboCtrlBase::DoSetToolTip(wxToolTip *tooltip) +{ + wxControl::DoSetToolTip(tooltip); + + // Set tool tip for button and text box + if ( tooltip ) + { + const wxString &tip = tooltip->GetTip(); + if ( m_text ) m_text->SetToolTip(tip); + if ( m_btn ) m_btn->SetToolTip(tip); + } + else + { + if ( m_text ) m_text->SetToolTip( (wxToolTip*) NULL ); + if ( m_btn ) m_btn->SetToolTip( (wxToolTip*) NULL ); + } +} +#endif // wxUSE_TOOLTIPS + +#if wxUSE_VALIDATORS +void wxComboCtrlBase::SetValidator(const wxValidator& validator) +{ + wxTextCtrl* textCtrl = GetTextCtrl(); + + if ( textCtrl ) + textCtrl->SetValidator( validator ); + else + wxControl::SetValidator( validator ); +} + +wxValidator* wxComboCtrlBase::GetValidator() +{ + wxTextCtrl* textCtrl = GetTextCtrl(); + + return textCtrl ? textCtrl->GetValidator() : wxControl::GetValidator(); +} +#endif // wxUSE_VALIDATORS + +// ---------------------------------------------------------------------------- +// painting +// ---------------------------------------------------------------------------- + +#if (!defined(__WXMSW__)) || defined(__WXUNIVERSAL__) +// prepare combo box background on area in a way typical on platform +void wxComboCtrlBase::PrepareBackground( wxDC& dc, const wxRect& rect, int flags ) const +{ + wxSize sz = GetClientSize(); + bool isEnabled; + bool isFocused; // also selected + + // For smaller size control (and for disabled background) use less spacing + int focusSpacingX; + int focusSpacingY; + + if ( !(flags & wxCONTROL_ISSUBMENU) ) + { + // Drawing control + isEnabled = IsEnabled(); + isFocused = ShouldDrawFocus(); + + // Windows-style: for smaller size control (and for disabled background) use less spacing + focusSpacingX = isEnabled ? 2 : 1; + focusSpacingY = sz.y > (GetCharHeight()+2) && isEnabled ? 2 : 1; + } + else + { + // Drawing a list item + isEnabled = true; // they are never disabled + isFocused = flags & wxCONTROL_SELECTED ? true : false; + + focusSpacingX = 0; + focusSpacingY = 0; + } + + // Set the background sub-rectangle for selection, disabled etc + wxRect selRect(rect); + selRect.y += focusSpacingY; + selRect.height -= (focusSpacingY*2); + + int wcp = 0; + + if ( !(flags & wxCONTROL_ISSUBMENU) ) + wcp += m_widthCustomPaint; + + selRect.x += wcp + focusSpacingX; + selRect.width -= wcp + (focusSpacingX*2); + + wxColour fgCol; + wxColour bgCol; + + if ( isEnabled ) + { + if ( isFocused ) + fgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT); + else if ( m_hasFgCol ) + // Honour the custom foreground colour + fgCol = GetForegroundColour(); + else + fgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); + } + else + { + fgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT); + } + + if ( isEnabled ) + { + if ( isFocused ) + bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT); + else if ( m_hasBgCol ) + // Honour the custom background colour + bgCol = GetBackgroundColour(); + else +#if defined(__WXMAC__) || defined(__WXGTK__) // see note in OnThemeChange + bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); +#else + bgCol = GetBackgroundColour(); +#endif + } + else + { +#if defined(__WXMAC__) || defined(__WXGTK__) // see note in OnThemeChange + bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); +#else + bgCol = GetBackgroundColour(); +#endif + } + + dc.SetTextForeground( fgCol ); + dc.SetBrush( bgCol ); + dc.SetPen( bgCol ); + dc.DrawRectangle( selRect ); + + // Don't clip exactly to the selection rectangle so we can draw + // to the non-selected area in front of it. + wxRect clipRect(rect.x,rect.y, + (selRect.x+selRect.width)-rect.x,rect.height); + dc.SetClippingRegion(clipRect); +} +#else +// Save the library size a bit for platforms that re-implement this. +void wxComboCtrlBase::PrepareBackground( wxDC&, const wxRect&, int ) const +{ +} +#endif + +void wxComboCtrlBase::DrawButton( wxDC& dc, const wxRect& rect, int flags ) +{ + int drawState = m_btnState; + +#ifdef __WXGTK__ + if ( GetPopupWindowState() >= Animating ) + drawState |= wxCONTROL_PRESSED; +#endif + + wxRect drawRect(rect.x+m_btnSpacingX, + rect.y+((rect.height-m_btnSize.y)/2), + m_btnSize.x, + m_btnSize.y); + + // Make sure area is not larger than the control + if ( drawRect.y < rect.y ) + drawRect.y = rect.y; + if ( drawRect.height > rect.height ) + drawRect.height = rect.height; + + bool enabled = IsEnabled(); + + if ( !enabled ) + drawState |= wxCONTROL_DISABLED; + + if ( !m_bmpNormal.Ok() ) + { + if ( flags & Draw_BitmapOnly ) + return; + + // Need to clear button background even if m_btn is present + if ( flags & Draw_PaintBg ) + { + wxColour bgCol; + + if ( m_iFlags & wxCC_IFLAG_BUTTON_OUTSIDE ) + bgCol = GetParent()->GetBackgroundColour(); + else + bgCol = GetBackgroundColour(); + + dc.SetBrush(bgCol); + dc.SetPen(bgCol); + dc.DrawRectangle(rect); + } + + // Draw standard button + wxRendererNative::Get().DrawComboBoxDropButton(this, + dc, + drawRect, + drawState); + } + else + { + // Draw bitmap + + wxBitmap* pBmp; + + if ( !enabled ) + pBmp = &m_bmpDisabled; + else if ( m_btnState & wxCONTROL_PRESSED ) + pBmp = &m_bmpPressed; + else if ( m_btnState & wxCONTROL_CURRENT ) + pBmp = &m_bmpHover; + else + pBmp = &m_bmpNormal; + + if ( m_blankButtonBg ) + { + // If using blank button background, we need to clear its background + // with button face colour instead of colour for rest of the control. + if ( flags & Draw_PaintBg ) + { + wxColour bgCol = GetParent()->GetBackgroundColour(); //wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); + //wxColour bgCol = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); + dc.SetPen(bgCol); + dc.SetBrush(bgCol); + dc.DrawRectangle(rect); + } + + wxRendererNative::Get().DrawPushButton(this, + dc, + drawRect, + drawState); + + } + else + + { + // Need to clear button background even if m_btn is present + // (assume non-button background was cleared just before this call so brushes are good) + if ( flags & Draw_PaintBg ) + dc.DrawRectangle(rect); + } + + // Draw bitmap centered in drawRect + dc.DrawBitmap(*pBmp, + drawRect.x + (drawRect.width-pBmp->GetWidth())/2, + drawRect.y + (drawRect.height-pBmp->GetHeight())/2, + true); + } +} + +void wxComboCtrlBase::RecalcAndRefresh() +{ + if ( IsCreated() ) + { + wxSizeEvent evt(GetSize(),GetId()); + GetEventHandler()->ProcessEvent(evt); + Refresh(); + } +} + +// ---------------------------------------------------------------------------- +// miscellaneous event handlers +// ---------------------------------------------------------------------------- + +void wxComboCtrlBase::OnTextCtrlEvent(wxCommandEvent& event) +{ + if ( event.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED ) + { + if ( m_ignoreEvtText > 0 ) + { + m_ignoreEvtText--; + return; + } + } + + // Change event id, object and string before relaying it forward + event.SetId(GetId()); + wxString s = event.GetString(); + event.SetEventObject(this); + event.SetString(s); + event.Skip(); +} + +// call if cursor is on button area or mouse is captured for the button +bool wxComboCtrlBase::HandleButtonMouseEvent( wxMouseEvent& event, + int flags ) +{ + int type = event.GetEventType(); + + if ( type == wxEVT_MOTION ) + { + if ( flags & wxCC_MF_ON_BUTTON ) + { + if ( !(m_btnState & wxCONTROL_CURRENT) ) + { + // Mouse hover begins + m_btnState |= wxCONTROL_CURRENT; + if ( HasCapture() ) // Retain pressed state. + m_btnState |= wxCONTROL_PRESSED; + Refresh(); + } + } + else if ( (m_btnState & wxCONTROL_CURRENT) ) + { + // Mouse hover ends + m_btnState &= ~(wxCONTROL_CURRENT|wxCONTROL_PRESSED); + Refresh(); + } + } + else if ( type == wxEVT_LEFT_DOWN || type == wxEVT_LEFT_DCLICK ) + { + if ( flags & (wxCC_MF_ON_CLICK_AREA|wxCC_MF_ON_BUTTON) ) + { + m_btnState |= wxCONTROL_PRESSED; + Refresh(); + + if ( !(m_iFlags & wxCC_POPUP_ON_MOUSE_UP) ) + OnButtonClick(); + else + // If showing popup now, do not capture mouse or there will be interference + CaptureMouse(); + } + } + else if ( type == wxEVT_LEFT_UP ) + { + + // Only accept event if mouse was left-press was previously accepted + if ( HasCapture() ) + ReleaseMouse(); + + if ( m_btnState & wxCONTROL_PRESSED ) + { + // If mouse was inside, fire the click event. + if ( m_iFlags & wxCC_POPUP_ON_MOUSE_UP ) + { + if ( flags & (wxCC_MF_ON_CLICK_AREA|wxCC_MF_ON_BUTTON) ) + OnButtonClick(); + } + + m_btnState &= ~(wxCONTROL_PRESSED); + Refresh(); + } + } + else if ( type == wxEVT_LEAVE_WINDOW ) + { + if ( m_btnState & (wxCONTROL_CURRENT|wxCONTROL_PRESSED) ) + { + m_btnState &= ~(wxCONTROL_CURRENT); + + // Mouse hover ends + if ( IsPopupWindowState(Hidden) ) + { + m_btnState &= ~(wxCONTROL_PRESSED); + Refresh(); + } + } + } + else + return false; + + return true; +} + +// returns true if event was consumed or filtered +bool wxComboCtrlBase::PreprocessMouseEvent( wxMouseEvent& event, + int WXUNUSED(flags) ) +{ + wxLongLong t = ::wxGetLocalTimeMillis(); + int evtType = event.GetEventType(); + +#if USES_WXPOPUPWINDOW || USES_WXDIALOG + if ( m_popupWinType != POPUPWIN_WXPOPUPTRANSIENTWINDOW ) + { + if ( IsPopupWindowState(Visible) && + ( evtType == wxEVT_LEFT_DOWN || evtType == wxEVT_RIGHT_DOWN ) ) + { + HidePopup(); + return true; + } + } +#endif + + // Filter out clicks on button immediately after popup dismiss (Windows like behaviour) + if ( evtType == wxEVT_LEFT_DOWN && t < m_timeCanAcceptClick ) + { + event.SetEventType(0); + return true; + } + + return false; +} + +void wxComboCtrlBase::HandleNormalMouseEvent( wxMouseEvent& event ) +{ + int evtType = event.GetEventType(); + + if ( (evtType == wxEVT_LEFT_DOWN || evtType == wxEVT_LEFT_DCLICK) && + (m_windowStyle & wxCB_READONLY) ) + { + if ( GetPopupWindowState() >= Animating ) + { + #if USES_WXPOPUPWINDOW + // Click here always hides the popup. + if ( m_popupWinType == POPUPWIN_WXPOPUPWINDOW ) + HidePopup(); + #endif + } + else + { + if ( !(m_windowStyle & wxCC_SPECIAL_DCLICK) ) + { + // In read-only mode, clicking the text is the + // same as clicking the button. + OnButtonClick(); + } + else if ( /*evtType == wxEVT_LEFT_UP || */evtType == wxEVT_LEFT_DCLICK ) + { + //if ( m_popupInterface->CycleValue() ) + // Refresh(); + if ( m_popupInterface ) + m_popupInterface->OnComboDoubleClick(); + } + } + } + else + if ( IsPopupShown() ) + { + // relay (some) mouse events to the popup + if ( evtType == wxEVT_MOUSEWHEEL ) + m_popup->AddPendingEvent(event); + } + else if ( evtType ) + event.Skip(); +} + +void wxComboCtrlBase::OnKeyEvent(wxKeyEvent& event) +{ + if ( IsPopupShown() ) + { + // pass it to the popped up control + GetPopupControl()->GetControl()->AddPendingEvent(event); + } + else // no popup + { + int keycode = event.GetKeyCode(); + + wxWindow* mainCtrl = GetMainWindowOfCompositeControl(); + + if ( mainCtrl->GetParent()->HasFlag(wxTAB_TRAVERSAL) && + keycode == WXK_TAB ) + { + wxNavigationKeyEvent evt; + + evt.SetFlags(wxNavigationKeyEvent::FromTab| + (!event.ShiftDown() ? wxNavigationKeyEvent::IsForward + : wxNavigationKeyEvent::IsBackward)); + evt.SetEventObject(mainCtrl); + evt.SetCurrentFocus(mainCtrl); + mainCtrl->GetParent()->GetEventHandler()->AddPendingEvent(evt); + return; + } + + if ( IsKeyPopupToggle(event) ) + { + OnButtonClick(); + return; + } + + int comboStyle = GetWindowStyle(); + wxComboPopup* popupInterface = GetPopupControl(); + + if ( !popupInterface ) + { + event.Skip(); + return; + } + + if ( (comboStyle & wxCB_READONLY) || + (keycode != WXK_RIGHT && keycode != WXK_LEFT) ) + { + popupInterface->OnComboKeyEvent(event); + } + else + event.Skip(); + } +} + +void wxComboCtrlBase::OnFocusEvent( wxFocusEvent& event ) +{ + if ( event.GetEventType() == wxEVT_SET_FOCUS ) + { + wxWindow* tc = GetTextCtrl(); + if ( tc && tc != DoFindFocus() ) +#ifdef __WXMAC__ + m_resetFocus = true; +#else + tc->SetFocus(); +#endif + } + + Refresh(); +} + +void wxComboCtrlBase::OnIdleEvent( wxIdleEvent& WXUNUSED(event) ) +{ + if ( m_resetFocus ) + { + m_resetFocus = false; + wxWindow* tc = GetTextCtrl(); + if ( tc ) + tc->SetFocus(); + } +} + +void wxComboCtrlBase::OnSysColourChanged(wxSysColourChangedEvent& WXUNUSED(event)) +{ + OnThemeChange(); + // indentation may also have changed + if ( !(m_iFlags & wxCC_IFLAG_INDENT_SET) ) + m_absIndent = GetNativeTextIndent(); + RecalcAndRefresh(); +} + +// ---------------------------------------------------------------------------- +// popup handling +// ---------------------------------------------------------------------------- + +// Create popup window and the child control +void wxComboCtrlBase::CreatePopup() +{ + wxComboPopup* popupInterface = m_popupInterface; + wxWindow* popup; + + if ( !m_winPopup ) + { +#ifdef wxComboPopupWindowBase2 + if ( m_iFlags & wxCC_IFLAG_USE_ALT_POPUP ) + { + #if !USES_WXDIALOG + m_winPopup = new wxComboPopupWindowBase2( this, wxNO_BORDER ); + #else + m_winPopup = new wxComboPopupWindowBase2( this, wxID_ANY, wxEmptyString, + wxPoint(-21,-21), wxSize(20, 20), + wxNO_BORDER ); + #endif + m_popupWinType = SECONDARY_POPUP_TYPE; + } + else +#endif + { + m_winPopup = new wxComboPopupWindow( this, wxNO_BORDER ); + m_popupWinType = PRIMARY_POPUP_TYPE; + } + m_popupWinEvtHandler = new wxComboPopupWindowEvtHandler(this); + m_winPopup->PushEventHandler(m_popupWinEvtHandler); + } + + popupInterface->Create(m_winPopup); + m_popup = popup = popupInterface->GetControl(); + + m_popupExtraHandler = new wxComboPopupExtraEventHandler(this); + popup->PushEventHandler( m_popupExtraHandler ); + + // This may be helpful on some platforms + // (eg. it bypasses a wxGTK popupwindow bug where + // window is not initially hidden when it should be) + m_winPopup->Hide(); + + popupInterface->m_iFlags |= wxCP_IFLAG_CREATED; +} + +// Destroy popup window and the child control +void wxComboCtrlBase::DestroyPopup() +{ + HidePopup(); + + if ( m_popup ) + m_popup->RemoveEventHandler(m_popupExtraHandler); + + delete m_popupExtraHandler; + + delete m_popupInterface; + + if ( m_winPopup ) + { + m_winPopup->RemoveEventHandler(m_popupWinEvtHandler); + delete m_popupWinEvtHandler; + m_popupWinEvtHandler = NULL; + m_winPopup->Destroy(); + } + + m_popupExtraHandler = (wxEvtHandler*) NULL; + m_popupInterface = (wxComboPopup*) NULL; + m_winPopup = (wxWindow*) NULL; + m_popup = (wxWindow*) NULL; +} + +void wxComboCtrlBase::DoSetPopupControl(wxComboPopup* iface) +{ + wxCHECK_RET( iface, wxT("no popup interface set for wxComboCtrl") ); + + DestroyPopup(); + + iface->InitBase(this); + iface->Init(); + + m_popupInterface = iface; + + if ( !iface->LazyCreate() ) + { + CreatePopup(); + } + else + { + m_popup = (wxWindow*) NULL; + } + + // This must be done after creation + if ( m_valueString.length() ) + { + iface->SetStringValue(m_valueString); + //Refresh(); + } +} + +// Ensures there is atleast the default popup +void wxComboCtrlBase::EnsurePopupControl() +{ + if ( !m_popupInterface ) + SetPopupControl(NULL); +} + +void wxComboCtrlBase::OnButtonClick() +{ + // Derived classes can override this method for totally custom + // popup action + if ( !IsPopupWindowState(Visible) ) + ShowPopup(); + else + HidePopup(); +} + +void wxComboCtrlBase::ShowPopup() +{ + EnsurePopupControl(); + wxCHECK_RET( !IsPopupWindowState(Visible), wxT("popup window already shown") ); + + if ( IsPopupWindowState(Animating) ) + return; + + SetFocus(); + + // Space above and below + int screenHeight; + wxPoint scrPos; + int spaceAbove; + int spaceBelow; + int maxHeightPopup; + wxSize ctrlSz = GetSize(); + + screenHeight = wxSystemSettings::GetMetric( wxSYS_SCREEN_Y ); + scrPos = GetParent()->ClientToScreen(GetPosition()); + + spaceAbove = scrPos.y; + spaceBelow = screenHeight - spaceAbove - ctrlSz.y; + + maxHeightPopup = spaceBelow; + if ( spaceAbove > spaceBelow ) + maxHeightPopup = spaceAbove; + + // Width + int widthPopup = ctrlSz.x + m_extLeft + m_extRight; + + if ( widthPopup < m_widthMinPopup ) + widthPopup = m_widthMinPopup; + + wxWindow* winPopup = m_winPopup; + wxWindow* popup; + + // Need to disable tab traversal of parent + // + // NB: This is to fix a bug in wxMSW. In theory it could also be fixed + // by, for instance, adding check to window.cpp:wxWindowMSW::MSWProcessMessage + // that if transient popup is open, then tab traversal is to be ignored. + // However, I think this code would still be needed for cases where + // transient popup doesn't work yet (wxWinCE?). + wxWindow* parent = GetParent(); + int parentFlags = parent->GetWindowStyle(); + if ( parentFlags & wxTAB_TRAVERSAL ) + { + parent->SetWindowStyle( parentFlags & ~(wxTAB_TRAVERSAL) ); + m_iFlags |= wxCC_IFLAG_PARENT_TAB_TRAVERSAL; + } + + if ( !winPopup ) + { + CreatePopup(); + winPopup = m_winPopup; + popup = m_popup; + } + else + { + popup = m_popup; + } + + winPopup->Enable(); + + wxASSERT( !m_popup || m_popup == popup ); // Consistency check. + + wxSize adjustedSize = m_popupInterface->GetAdjustedSize(widthPopup, + m_heightPopup<=0?DEFAULT_POPUP_HEIGHT:m_heightPopup, + maxHeightPopup); + + popup->SetSize(adjustedSize); + popup->Move(0,0); + m_popupInterface->OnPopup(); + + // + // Reposition and resize popup window + // + + wxSize szp = popup->GetSize(); + + int popupX; + int popupY = scrPos.y + ctrlSz.y; + + // Default anchor is wxLEFT + int anchorSide = m_anchorSide; + if ( !anchorSide ) + anchorSide = wxLEFT; + + int rightX = scrPos.x + ctrlSz.x + m_extRight - szp.x; + int leftX = scrPos.x - m_extLeft; + + if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ) + leftX -= ctrlSz.x; + + int screenWidth = wxSystemSettings::GetMetric( wxSYS_SCREEN_X ); + + // If there is not enough horizontal space, anchor on the other side. + // If there is no space even then, place the popup at x 0. + if ( anchorSide == wxRIGHT ) + { + if ( rightX < 0 ) + { + if ( (leftX+szp.x) < screenWidth ) + anchorSide = wxLEFT; + else + anchorSide = 0; + } + } + else + { + if ( (leftX+szp.x) >= screenWidth ) + { + if ( rightX >= 0 ) + anchorSide = wxRIGHT; + else + anchorSide = 0; + } + } + + // Select x coordinate according to the anchor side + if ( anchorSide == wxRIGHT ) + popupX = rightX; + else if ( anchorSide == wxLEFT ) + popupX = leftX; + else + popupX = 0; + + int showFlags = CanDeferShow; + + if ( spaceBelow < szp.y ) + { + popupY = scrPos.y - szp.y; + showFlags |= ShowAbove; + } + +#if INSTALL_TOPLEV_HANDLER + // Put top level window event handler into place + if ( m_popupWinType == POPUPWIN_WXPOPUPWINDOW ) + { + if ( !m_toplevEvtHandler ) + m_toplevEvtHandler = new wxComboFrameEventHandler(this); + + wxWindow* toplev = ::wxGetTopLevelParent( this ); + wxASSERT( toplev ); + ((wxComboFrameEventHandler*)m_toplevEvtHandler)->OnPopup(); + toplev->PushEventHandler( m_toplevEvtHandler ); + } +#endif + + // Set string selection (must be this way instead of SetStringSelection) + if ( m_text ) + { + if ( !(m_iFlags & wxCC_NO_TEXT_AUTO_SELECT) ) + m_text->SelectAll(); + + m_popupInterface->SetStringValue( m_text->GetValue() ); + } + else + { + // This is neede since focus/selection indication may change when popup is shown + Refresh(); + } + + // This must be after SetStringValue + m_popupWinState = Animating; + + wxRect popupWinRect( popupX, popupY, szp.x, szp.y ); + + m_popup = popup; + if ( (m_iFlags & wxCC_IFLAG_DISABLE_POPUP_ANIM) || + AnimateShow( popupWinRect, showFlags ) ) + { + DoShowPopup( popupWinRect, showFlags ); + } +} + +bool wxComboCtrlBase::AnimateShow( const wxRect& WXUNUSED(rect), int WXUNUSED(flags) ) +{ + return true; +} + +void wxComboCtrlBase::DoShowPopup( const wxRect& rect, int WXUNUSED(flags) ) +{ + wxWindow* winPopup = m_winPopup; + + if ( IsPopupWindowState(Animating) ) + { + // Make sure the popup window is shown in the right position. + // Should not matter even if animation already did this. + + // Some platforms (GTK) may like SetSize and Move to be separate + // (though the bug was probably fixed). + winPopup->SetSize( rect ); + + winPopup->Show(); + + m_popupWinState = Visible; + } + else if ( IsPopupWindowState(Hidden) ) + { + // Animation was aborted + + wxASSERT( !winPopup->IsShown() ); + + m_popupWinState = Hidden; + } +} + +void wxComboCtrlBase::OnPopupDismiss() +{ + // Just in case, avoid double dismiss + if ( IsPopupWindowState(Hidden) ) + return; + + // This must be set before focus - otherwise there will be recursive + // OnPopupDismisses. + m_popupWinState = Hidden; + + //SetFocus(); + m_winPopup->Disable(); + + // Inform popup control itself + m_popupInterface->OnDismiss(); + + if ( m_popupExtraHandler ) + ((wxComboPopupExtraEventHandler*)m_popupExtraHandler)->OnPopupDismiss(); + +#if INSTALL_TOPLEV_HANDLER + // Remove top level window event handler + if ( m_toplevEvtHandler ) + { + wxWindow* toplev = ::wxGetTopLevelParent( this ); + if ( toplev ) + toplev->RemoveEventHandler( m_toplevEvtHandler ); + } +#endif + + m_timeCanAcceptClick = ::wxGetLocalTimeMillis(); + + if ( m_popupWinType == POPUPWIN_WXPOPUPTRANSIENTWINDOW ) + m_timeCanAcceptClick += 150; + + // If cursor not on dropdown button, then clear its state + // (technically not required by all ports, but do it for all just in case) + if ( !m_btnArea.Contains(ScreenToClient(::wxGetMousePosition())) ) + m_btnState = 0; + + // Return parent's tab traversal flag. + // See ShowPopup for notes. + if ( m_iFlags & wxCC_IFLAG_PARENT_TAB_TRAVERSAL ) + { + wxWindow* parent = GetParent(); + parent->SetWindowStyle( parent->GetWindowStyle() | wxTAB_TRAVERSAL ); + m_iFlags &= ~(wxCC_IFLAG_PARENT_TAB_TRAVERSAL); + } + + // refresh control (necessary even if m_text) + Refresh(); + + SetFocus(); +} + +void wxComboCtrlBase::HidePopup() +{ + // Should be able to call this without popup interface + if ( IsPopupWindowState(Hidden) ) + return; + + // transfer value and show it in textctrl, if any + if ( !IsPopupWindowState(Animating) ) + SetValue( m_popupInterface->GetStringValue() ); + + m_winPopup->Hide(); + + OnPopupDismiss(); +} + +// ---------------------------------------------------------------------------- +// customization methods +// ---------------------------------------------------------------------------- + +void wxComboCtrlBase::SetButtonPosition( int width, int height, + int side, int spacingX ) +{ + m_btnWid = width; + m_btnHei = height; + m_btnSide = side; + m_btnSpacingX = spacingX; + + if ( width > 0 || height > 0 || spacingX ) + m_iFlags |= wxCC_IFLAG_HAS_NONSTANDARD_BUTTON; + + RecalcAndRefresh(); +} + +wxSize wxComboCtrlBase::GetButtonSize() +{ + if ( m_btnSize.x > 0 ) + return m_btnSize; + + wxSize retSize(m_btnWid,m_btnHei); + + // Need to call CalculateAreas now if button size is + // is not explicitly specified. + if ( retSize.x <= 0 || retSize.y <= 0) + { + OnResize(); + + retSize = m_btnSize; + } + + return retSize; +} + +void wxComboCtrlBase::SetButtonBitmaps( const wxBitmap& bmpNormal, + bool blankButtonBg, + const wxBitmap& bmpPressed, + const wxBitmap& bmpHover, + const wxBitmap& bmpDisabled ) +{ + m_bmpNormal = bmpNormal; + m_blankButtonBg = blankButtonBg; + + if ( bmpPressed.Ok() ) + m_bmpPressed = bmpPressed; + else + m_bmpPressed = bmpNormal; + + if ( bmpHover.Ok() ) + m_bmpHover = bmpHover; + else + m_bmpHover = bmpNormal; + + if ( bmpDisabled.Ok() ) + m_bmpDisabled = bmpDisabled; + else + m_bmpDisabled = bmpNormal; + + RecalcAndRefresh(); +} + +void wxComboCtrlBase::SetCustomPaintWidth( int width ) +{ + if ( m_text ) + { + // move textctrl accordingly + wxRect r = m_text->GetRect(); + int inc = width - m_widthCustomPaint; + r.x += inc; + r.width -= inc; + m_text->SetSize( r ); + } + + m_widthCustomPaint = width; + + RecalcAndRefresh(); +} + +void wxComboCtrlBase::SetTextIndent( int indent ) +{ + if ( indent < 0 ) + { + m_absIndent = GetNativeTextIndent(); + m_iFlags &= ~(wxCC_IFLAG_INDENT_SET); + } + else + { + m_absIndent = indent; + m_iFlags |= wxCC_IFLAG_INDENT_SET; + } + + RecalcAndRefresh(); +} + +wxCoord wxComboCtrlBase::GetNativeTextIndent() const +{ + return DEFAULT_TEXT_INDENT; +} + +// ---------------------------------------------------------------------------- +// methods forwarded to wxTextCtrl +// ---------------------------------------------------------------------------- + +wxString wxComboCtrlBase::GetValue() const +{ + if ( m_text ) + return m_text->GetValue(); + return m_valueString; +} + +void wxComboCtrlBase::SetValueWithEvent(const wxString& value, bool withEvent) +{ + if ( m_text ) + { + if ( !withEvent ) + m_ignoreEvtText++; + + m_text->SetValue(value); + if ( !(m_iFlags & wxCC_NO_TEXT_AUTO_SELECT) ) + m_text->SelectAll(); + } + + // Since wxComboPopup may want to paint the combo as well, we need + // to set the string value here (as well as sometimes in ShowPopup). + if ( m_valueString != value ) + { + m_valueString = value; + + EnsurePopupControl(); + + if (m_popupInterface) + m_popupInterface->SetStringValue(value); + } + + Refresh(); +} + +void wxComboCtrlBase::SetValue(const wxString& value) +{ + SetValueWithEvent(value, false); +} + +// In this SetValue variant wxComboPopup::SetStringValue is not called +void wxComboCtrlBase::SetText(const wxString& value) +{ + // Unlike in SetValue(), this must be called here or + // the behaviour will no be consistent in readonlys. + EnsurePopupControl(); + + m_valueString = value; + + if ( m_text ) + { + m_ignoreEvtText++; + m_text->SetValue( value ); + } + + Refresh(); +} + +void wxComboCtrlBase::Copy() +{ + if ( m_text ) + m_text->Copy(); +} + +void wxComboCtrlBase::Cut() +{ + if ( m_text ) + m_text->Cut(); +} + +void wxComboCtrlBase::Paste() +{ + if ( m_text ) + m_text->Paste(); +} + +void wxComboCtrlBase::SetInsertionPoint(long pos) +{ + if ( m_text ) + m_text->SetInsertionPoint(pos); +} + +void wxComboCtrlBase::SetInsertionPointEnd() +{ + if ( m_text ) + m_text->SetInsertionPointEnd(); +} + +long wxComboCtrlBase::GetInsertionPoint() const +{ + if ( m_text ) + return m_text->GetInsertionPoint(); + + return 0; +} + +long wxComboCtrlBase::GetLastPosition() const +{ + if ( m_text ) + return m_text->GetLastPosition(); + + return 0; +} + +void wxComboCtrlBase::Replace(long from, long to, const wxString& value) +{ + if ( m_text ) + m_text->Replace(from, to, value); +} + +void wxComboCtrlBase::Remove(long from, long to) +{ + if ( m_text ) + m_text->Remove(from, to); +} + +void wxComboCtrlBase::SetSelection(long from, long to) +{ + if ( m_text ) + m_text->SetSelection(from, to); +} + +void wxComboCtrlBase::Undo() +{ + if ( m_text ) + m_text->Undo(); +} + +#endif // wxUSE_COMBOCTRL diff --git a/Source/3rd Party/wx/src/common/config.cpp b/Source/3rd Party/wx/src/common/config.cpp index 1079e46be..ce169563f 100644 --- a/Source/3rd Party/wx/src/common/config.cpp +++ b/Source/3rd Party/wx/src/common/config.cpp @@ -1,490 +1,490 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/config.cpp -// Purpose: implementation of wxConfigBase class -// Author: Vadim Zeitlin -// Modified by: -// Created: 07.04.98 -// RCS-ID: $Id: config.cpp 50711 2007-12-15 02:57:58Z VZ $ -// Copyright: (c) 1997 Karsten Ballueder Ballueder@usa.net -// Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif //__BORLANDC__ - -#ifndef wxUSE_CONFIG_NATIVE - #define wxUSE_CONFIG_NATIVE 1 -#endif - -#include "wx/config.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/app.h" - #include "wx/utils.h" - #include "wx/arrstr.h" - #include "wx/math.h" -#endif //WX_PRECOMP - -#if wxUSE_CONFIG && ((wxUSE_FILE && wxUSE_TEXTFILE) || wxUSE_CONFIG_NATIVE) - -#include "wx/file.h" - -#include -#include -#include // for INT_MAX - -// ---------------------------------------------------------------------------- -// global and class static variables -// ---------------------------------------------------------------------------- - -wxConfigBase *wxConfigBase::ms_pConfig = NULL; -bool wxConfigBase::ms_bAutoCreate = true; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxConfigBase -// ---------------------------------------------------------------------------- - -// Not all args will always be used by derived classes, but including them all -// in each class ensures compatibility. -wxConfigBase::wxConfigBase(const wxString& appName, - const wxString& vendorName, - const wxString& WXUNUSED(localFilename), - const wxString& WXUNUSED(globalFilename), - long style) - : m_appName(appName), m_vendorName(vendorName), m_style(style) -{ - m_bExpandEnvVars = true; - m_bRecordDefaults = false; -} - -wxConfigBase::~wxConfigBase() -{ - // required here for Darwin -} - -wxConfigBase *wxConfigBase::Set(wxConfigBase *pConfig) -{ - wxConfigBase *pOld = ms_pConfig; - ms_pConfig = pConfig; - return pOld; -} - -wxConfigBase *wxConfigBase::Create() -{ - if ( ms_bAutoCreate && ms_pConfig == NULL ) { - ms_pConfig = - #if defined(__WXMSW__) && wxUSE_CONFIG_NATIVE - new wxRegConfig(wxTheApp->GetAppName(), wxTheApp->GetVendorName()); - #elif defined(__WXPALMOS__) && wxUSE_CONFIG_NATIVE - new wxPrefConfig(wxTheApp->GetAppName()); - #else // either we're under Unix or wish to use files even under Windows - new wxFileConfig(wxTheApp->GetAppName()); - #endif - } - - return ms_pConfig; -} - -// ---------------------------------------------------------------------------- -// wxConfigBase reading entries -// ---------------------------------------------------------------------------- - -// implement both Read() overloads for the given type in terms of DoRead() -#define IMPLEMENT_READ_FOR_TYPE(name, type, deftype, extra) \ - bool wxConfigBase::Read(const wxString& key, type *val) const \ - { \ - wxCHECK_MSG( val, false, _T("wxConfig::Read(): NULL parameter") ); \ - \ - if ( !DoRead##name(key, val) ) \ - return false; \ - \ - *val = extra(*val); \ - \ - return true; \ - } \ - \ - bool wxConfigBase::Read(const wxString& key, \ - type *val, \ - deftype defVal) const \ - { \ - wxCHECK_MSG( val, false, _T("wxConfig::Read(): NULL parameter") ); \ - \ - bool read = DoRead##name(key, val); \ - if ( !read ) \ - { \ - if ( IsRecordingDefaults() ) \ - { \ - ((wxConfigBase *)this)->DoWrite##name(key, defVal); \ - } \ - \ - *val = defVal; \ - } \ - \ - *val = extra(*val); \ - \ - return read; \ - } - - -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 -{ - 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") ); - - *pi = (int)l; - - return true; -} - -bool wxConfigBase::DoReadBool(const wxString& key, bool* val) const -{ - wxCHECK_MSG( val, false, _T("wxConfig::Read(): NULL parameter") ); - - long l; - if ( !DoReadLong(key, &l) ) - return false; - - wxASSERT_MSG( l == 0 || l == 1, _T("bad bool value in wxConfig::DoReadInt") ); - - *val = l != 0; - - return true; -} - -bool wxConfigBase::DoReadDouble(const wxString& key, double* val) const -{ - wxString str; - if ( Read(key, &str) ) - { - return str.ToDouble(val); - } - - return false; -} - -// string reading helper -wxString wxConfigBase::ExpandEnvVars(const wxString& str) const -{ - wxString tmp; // Required for BC++ - if (IsExpandingEnvVars()) - tmp = wxExpandEnvVars(str); - else - tmp = str; - return tmp; -} - -// ---------------------------------------------------------------------------- -// wxConfigBase writing -// ---------------------------------------------------------------------------- - -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); -} - -// ---------------------------------------------------------------------------- -// wxConfigPathChanger -// ---------------------------------------------------------------------------- - -wxConfigPathChanger::wxConfigPathChanger(const wxConfigBase *pContainer, - const wxString& strEntry) -{ - m_bChanged = false; - m_pContainer = (wxConfigBase *)pContainer; - - // the path is everything which precedes the last slash - wxString strPath = strEntry.BeforeLast(wxCONFIG_PATH_SEPARATOR); - - // except in the special case of "/keyname" when there is nothing before "/" - if ( strPath.empty() && - ((!strEntry.empty()) && strEntry[0] == wxCONFIG_PATH_SEPARATOR) ) - { - strPath = wxCONFIG_PATH_SEPARATOR; - } - - if ( !strPath.empty() ) - { - if ( m_pContainer->GetPath() != strPath ) - { - // we do change the path so restore it later - m_bChanged = true; - - /* JACS: work around a memory bug that causes an assert - when using wxRegConfig, related to reference-counting. - Can be reproduced by removing (const wxChar*) below and - adding the following code to the config sample OnInit under - Windows: - - pConfig->SetPath(wxT("MySettings")); - pConfig->SetPath(wxT("..")); - int value; - pConfig->Read(_T("MainWindowX"), & value); - */ - m_strOldPath = (const wxChar*) m_pContainer->GetPath(); - if ( *m_strOldPath.c_str() != wxCONFIG_PATH_SEPARATOR ) - m_strOldPath += wxCONFIG_PATH_SEPARATOR; - m_pContainer->SetPath(strPath); - } - - // in any case, use the just the name, not full path - m_strName = strEntry.AfterLast(wxCONFIG_PATH_SEPARATOR); - } - else { - // it's a name only, without path - nothing to do - m_strName = strEntry; - } -} - -void wxConfigPathChanger::UpdateIfDeleted() -{ - // we don't have to do anything at all if we didn't change the path - if ( !m_bChanged ) - return; - - // find the deepest still existing parent path of the original path - while ( !m_pContainer->HasGroup(m_strOldPath) ) - { - m_strOldPath = m_strOldPath.BeforeLast(wxCONFIG_PATH_SEPARATOR); - if ( m_strOldPath.empty() ) - m_strOldPath = wxCONFIG_PATH_SEPARATOR; - } -} - -wxConfigPathChanger::~wxConfigPathChanger() -{ - // only restore path if it was changed - if ( m_bChanged ) { - m_pContainer->SetPath(m_strOldPath); - } -} - -// this is a wxConfig method but it's mainly used with wxConfigPathChanger -/* static */ -wxString wxConfigBase::RemoveTrailingSeparator(const wxString& key) -{ - wxString path(key); - - // don't remove the only separator from a root group path! - while ( path.length() > 1 ) - { - if ( *path.rbegin() != wxCONFIG_PATH_SEPARATOR ) - break; - - path.erase(path.end() - 1); - } - - return path; -} - -#endif // wxUSE_CONFIG - -// ---------------------------------------------------------------------------- -// static & global functions -// ---------------------------------------------------------------------------- - -// understands both Unix and Windows (but only under Windows) environment -// variables expansion: i.e. $var, $(var) and ${var} are always understood -// and in addition under Windows %var% is also. - -// don't change the values the enum elements: they must be equal -// to the matching [closing] delimiter. -enum Bracket -{ - Bracket_None, - Bracket_Normal = ')', - Bracket_Curly = '}', -#ifdef __WXMSW__ - Bracket_Windows = '%', // yeah, Windows people are a bit strange ;-) -#endif - Bracket_Max -}; - -wxString wxExpandEnvVars(const wxString& str) -{ - wxString strResult; - strResult.Alloc(str.length()); - - size_t m; - for ( size_t n = 0; n < str.length(); n++ ) { - switch ( str[n] ) { -#ifdef __WXMSW__ - case wxT('%'): -#endif //WINDOWS - case wxT('$'): - { - Bracket bracket; - #ifdef __WXMSW__ - if ( str[n] == wxT('%') ) - bracket = Bracket_Windows; - else - #endif //WINDOWS - if ( n == str.length() - 1 ) { - bracket = Bracket_None; - } - else { - switch ( str[n + 1] ) { - case wxT('('): - bracket = Bracket_Normal; - n++; // skip the bracket - break; - - case wxT('{'): - bracket = Bracket_Curly; - n++; // skip the bracket - break; - - default: - bracket = Bracket_None; - } - } - - m = n + 1; - - while ( m < str.length() && (wxIsalnum(str[m]) || str[m] == wxT('_')) ) - m++; - - wxString strVarName(str.c_str() + n + 1, m - n - 1); - -#ifdef __WXWINCE__ - const wxChar *pszValue = NULL; -#else - // NB: use wxGetEnv instead of wxGetenv as otherwise variables - // set through wxSetEnv may not be read correctly! - const wxChar *pszValue = NULL; - wxString tmp; - if (wxGetEnv(strVarName, &tmp)) - pszValue = tmp; -#endif - if ( pszValue != NULL ) { - strResult += pszValue; - } - else { - // variable doesn't exist => don't change anything - #ifdef __WXMSW__ - if ( bracket != Bracket_Windows ) - #endif - if ( bracket != Bracket_None ) - strResult << str[n - 1]; - strResult << str[n] << strVarName; - } - - // check the closing bracket - if ( bracket != Bracket_None ) { - if ( m == str.length() || str[m] != (wxChar)bracket ) { - // under MSW it's common to have '%' characters in the registry - // and it's annoying to have warnings about them each time, so - // ignroe them silently if they are not used for env vars - // - // under Unix, OTOH, this warning could be useful for the user to - // understand why isn't the variable expanded as intended - #ifndef __WXMSW__ - wxLogWarning(_("Environment variables expansion failed: missing '%c' at position %u in '%s'."), - (char)bracket, (unsigned int) (m + 1), str.c_str()); - #endif // __WXMSW__ - } - else { - // skip closing bracket unless the variables wasn't expanded - if ( pszValue == NULL ) - strResult << (wxChar)bracket; - m++; - } - } - - n = m - 1; // skip variable name - } - break; - - case '\\': - // backslash can be used to suppress special meaning of % and $ - if ( n != str.length() - 1 && - (str[n + 1] == wxT('%') || str[n + 1] == wxT('$')) ) { - strResult += str[++n]; - - break; - } - //else: fall through - - default: - strResult += str[n]; - } - } - - return strResult; -} - -// this function is used to properly interpret '..' in path -void wxSplitPath(wxArrayString& aParts, const wxChar *sz) -{ - aParts.clear(); - - wxString strCurrent; - const wxChar *pc = sz; - for ( ;; ) { - if ( *pc == wxT('\0') || *pc == wxCONFIG_PATH_SEPARATOR ) { - if ( strCurrent == wxT(".") ) { - // ignore - } - else if ( strCurrent == wxT("..") ) { - // go up one level - if ( aParts.size() == 0 ) - wxLogWarning(_("'%s' has extra '..', ignored."), sz); - else - aParts.erase(aParts.end() - 1); - - strCurrent.Empty(); - } - else if ( !strCurrent.empty() ) { - aParts.push_back(strCurrent); - strCurrent.Empty(); - } - //else: - // could log an error here, but we prefer to ignore extra '/' - - if ( *pc == wxT('\0') ) - break; - } - else - strCurrent += *pc; - - pc++; - } -} +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/config.cpp +// Purpose: implementation of wxConfigBase class +// Author: Vadim Zeitlin +// Modified by: +// Created: 07.04.98 +// RCS-ID: $Id: config.cpp 50711 2007-12-15 02:57:58Z VZ $ +// Copyright: (c) 1997 Karsten Ballueder Ballueder@usa.net +// Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif //__BORLANDC__ + +#ifndef wxUSE_CONFIG_NATIVE + #define wxUSE_CONFIG_NATIVE 1 +#endif + +#include "wx/config.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/app.h" + #include "wx/utils.h" + #include "wx/arrstr.h" + #include "wx/math.h" +#endif //WX_PRECOMP + +#if wxUSE_CONFIG && ((wxUSE_FILE && wxUSE_TEXTFILE) || wxUSE_CONFIG_NATIVE) + +#include "wx/file.h" + +#include +#include +#include // for INT_MAX + +// ---------------------------------------------------------------------------- +// global and class static variables +// ---------------------------------------------------------------------------- + +wxConfigBase *wxConfigBase::ms_pConfig = NULL; +bool wxConfigBase::ms_bAutoCreate = true; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxConfigBase +// ---------------------------------------------------------------------------- + +// Not all args will always be used by derived classes, but including them all +// in each class ensures compatibility. +wxConfigBase::wxConfigBase(const wxString& appName, + const wxString& vendorName, + const wxString& WXUNUSED(localFilename), + const wxString& WXUNUSED(globalFilename), + long style) + : m_appName(appName), m_vendorName(vendorName), m_style(style) +{ + m_bExpandEnvVars = true; + m_bRecordDefaults = false; +} + +wxConfigBase::~wxConfigBase() +{ + // required here for Darwin +} + +wxConfigBase *wxConfigBase::Set(wxConfigBase *pConfig) +{ + wxConfigBase *pOld = ms_pConfig; + ms_pConfig = pConfig; + return pOld; +} + +wxConfigBase *wxConfigBase::Create() +{ + if ( ms_bAutoCreate && ms_pConfig == NULL ) { + ms_pConfig = + #if defined(__WXMSW__) && wxUSE_CONFIG_NATIVE + new wxRegConfig(wxTheApp->GetAppName(), wxTheApp->GetVendorName()); + #elif defined(__WXPALMOS__) && wxUSE_CONFIG_NATIVE + new wxPrefConfig(wxTheApp->GetAppName()); + #else // either we're under Unix or wish to use files even under Windows + new wxFileConfig(wxTheApp->GetAppName()); + #endif + } + + return ms_pConfig; +} + +// ---------------------------------------------------------------------------- +// wxConfigBase reading entries +// ---------------------------------------------------------------------------- + +// implement both Read() overloads for the given type in terms of DoRead() +#define IMPLEMENT_READ_FOR_TYPE(name, type, deftype, extra) \ + bool wxConfigBase::Read(const wxString& key, type *val) const \ + { \ + wxCHECK_MSG( val, false, _T("wxConfig::Read(): NULL parameter") ); \ + \ + if ( !DoRead##name(key, val) ) \ + return false; \ + \ + *val = extra(*val); \ + \ + return true; \ + } \ + \ + bool wxConfigBase::Read(const wxString& key, \ + type *val, \ + deftype defVal) const \ + { \ + wxCHECK_MSG( val, false, _T("wxConfig::Read(): NULL parameter") ); \ + \ + bool read = DoRead##name(key, val); \ + if ( !read ) \ + { \ + if ( IsRecordingDefaults() ) \ + { \ + ((wxConfigBase *)this)->DoWrite##name(key, defVal); \ + } \ + \ + *val = defVal; \ + } \ + \ + *val = extra(*val); \ + \ + return read; \ + } + + +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 +{ + 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") ); + + *pi = (int)l; + + return true; +} + +bool wxConfigBase::DoReadBool(const wxString& key, bool* val) const +{ + wxCHECK_MSG( val, false, _T("wxConfig::Read(): NULL parameter") ); + + long l; + if ( !DoReadLong(key, &l) ) + return false; + + wxASSERT_MSG( l == 0 || l == 1, _T("bad bool value in wxConfig::DoReadInt") ); + + *val = l != 0; + + return true; +} + +bool wxConfigBase::DoReadDouble(const wxString& key, double* val) const +{ + wxString str; + if ( Read(key, &str) ) + { + return str.ToDouble(val); + } + + return false; +} + +// string reading helper +wxString wxConfigBase::ExpandEnvVars(const wxString& str) const +{ + wxString tmp; // Required for BC++ + if (IsExpandingEnvVars()) + tmp = wxExpandEnvVars(str); + else + tmp = str; + return tmp; +} + +// ---------------------------------------------------------------------------- +// wxConfigBase writing +// ---------------------------------------------------------------------------- + +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); +} + +// ---------------------------------------------------------------------------- +// wxConfigPathChanger +// ---------------------------------------------------------------------------- + +wxConfigPathChanger::wxConfigPathChanger(const wxConfigBase *pContainer, + const wxString& strEntry) +{ + m_bChanged = false; + m_pContainer = (wxConfigBase *)pContainer; + + // the path is everything which precedes the last slash + wxString strPath = strEntry.BeforeLast(wxCONFIG_PATH_SEPARATOR); + + // except in the special case of "/keyname" when there is nothing before "/" + if ( strPath.empty() && + ((!strEntry.empty()) && strEntry[0] == wxCONFIG_PATH_SEPARATOR) ) + { + strPath = wxCONFIG_PATH_SEPARATOR; + } + + if ( !strPath.empty() ) + { + if ( m_pContainer->GetPath() != strPath ) + { + // we do change the path so restore it later + m_bChanged = true; + + /* JACS: work around a memory bug that causes an assert + when using wxRegConfig, related to reference-counting. + Can be reproduced by removing (const wxChar*) below and + adding the following code to the config sample OnInit under + Windows: + + pConfig->SetPath(wxT("MySettings")); + pConfig->SetPath(wxT("..")); + int value; + pConfig->Read(_T("MainWindowX"), & value); + */ + m_strOldPath = (const wxChar*) m_pContainer->GetPath(); + if ( *m_strOldPath.c_str() != wxCONFIG_PATH_SEPARATOR ) + m_strOldPath += wxCONFIG_PATH_SEPARATOR; + m_pContainer->SetPath(strPath); + } + + // in any case, use the just the name, not full path + m_strName = strEntry.AfterLast(wxCONFIG_PATH_SEPARATOR); + } + else { + // it's a name only, without path - nothing to do + m_strName = strEntry; + } +} + +void wxConfigPathChanger::UpdateIfDeleted() +{ + // we don't have to do anything at all if we didn't change the path + if ( !m_bChanged ) + return; + + // find the deepest still existing parent path of the original path + while ( !m_pContainer->HasGroup(m_strOldPath) ) + { + m_strOldPath = m_strOldPath.BeforeLast(wxCONFIG_PATH_SEPARATOR); + if ( m_strOldPath.empty() ) + m_strOldPath = wxCONFIG_PATH_SEPARATOR; + } +} + +wxConfigPathChanger::~wxConfigPathChanger() +{ + // only restore path if it was changed + if ( m_bChanged ) { + m_pContainer->SetPath(m_strOldPath); + } +} + +// this is a wxConfig method but it's mainly used with wxConfigPathChanger +/* static */ +wxString wxConfigBase::RemoveTrailingSeparator(const wxString& key) +{ + wxString path(key); + + // don't remove the only separator from a root group path! + while ( path.length() > 1 ) + { + if ( *path.rbegin() != wxCONFIG_PATH_SEPARATOR ) + break; + + path.erase(path.end() - 1); + } + + return path; +} + +#endif // wxUSE_CONFIG + +// ---------------------------------------------------------------------------- +// static & global functions +// ---------------------------------------------------------------------------- + +// understands both Unix and Windows (but only under Windows) environment +// variables expansion: i.e. $var, $(var) and ${var} are always understood +// and in addition under Windows %var% is also. + +// don't change the values the enum elements: they must be equal +// to the matching [closing] delimiter. +enum Bracket +{ + Bracket_None, + Bracket_Normal = ')', + Bracket_Curly = '}', +#ifdef __WXMSW__ + Bracket_Windows = '%', // yeah, Windows people are a bit strange ;-) +#endif + Bracket_Max +}; + +wxString wxExpandEnvVars(const wxString& str) +{ + wxString strResult; + strResult.Alloc(str.length()); + + size_t m; + for ( size_t n = 0; n < str.length(); n++ ) { + switch ( str[n] ) { +#ifdef __WXMSW__ + case wxT('%'): +#endif //WINDOWS + case wxT('$'): + { + Bracket bracket; + #ifdef __WXMSW__ + if ( str[n] == wxT('%') ) + bracket = Bracket_Windows; + else + #endif //WINDOWS + if ( n == str.length() - 1 ) { + bracket = Bracket_None; + } + else { + switch ( str[n + 1] ) { + case wxT('('): + bracket = Bracket_Normal; + n++; // skip the bracket + break; + + case wxT('{'): + bracket = Bracket_Curly; + n++; // skip the bracket + break; + + default: + bracket = Bracket_None; + } + } + + m = n + 1; + + while ( m < str.length() && (wxIsalnum(str[m]) || str[m] == wxT('_')) ) + m++; + + wxString strVarName(str.c_str() + n + 1, m - n - 1); + +#ifdef __WXWINCE__ + const wxChar *pszValue = NULL; +#else + // NB: use wxGetEnv instead of wxGetenv as otherwise variables + // set through wxSetEnv may not be read correctly! + const wxChar *pszValue = NULL; + wxString tmp; + if (wxGetEnv(strVarName, &tmp)) + pszValue = tmp; +#endif + if ( pszValue != NULL ) { + strResult += pszValue; + } + else { + // variable doesn't exist => don't change anything + #ifdef __WXMSW__ + if ( bracket != Bracket_Windows ) + #endif + if ( bracket != Bracket_None ) + strResult << str[n - 1]; + strResult << str[n] << strVarName; + } + + // check the closing bracket + if ( bracket != Bracket_None ) { + if ( m == str.length() || str[m] != (wxChar)bracket ) { + // under MSW it's common to have '%' characters in the registry + // and it's annoying to have warnings about them each time, so + // ignroe them silently if they are not used for env vars + // + // under Unix, OTOH, this warning could be useful for the user to + // understand why isn't the variable expanded as intended + #ifndef __WXMSW__ + wxLogWarning(_("Environment variables expansion failed: missing '%c' at position %u in '%s'."), + (char)bracket, (unsigned int) (m + 1), str.c_str()); + #endif // __WXMSW__ + } + else { + // skip closing bracket unless the variables wasn't expanded + if ( pszValue == NULL ) + strResult << (wxChar)bracket; + m++; + } + } + + n = m - 1; // skip variable name + } + break; + + case '\\': + // backslash can be used to suppress special meaning of % and $ + if ( n != str.length() - 1 && + (str[n + 1] == wxT('%') || str[n + 1] == wxT('$')) ) { + strResult += str[++n]; + + break; + } + //else: fall through + + default: + strResult += str[n]; + } + } + + return strResult; +} + +// this function is used to properly interpret '..' in path +void wxSplitPath(wxArrayString& aParts, const wxChar *sz) +{ + aParts.clear(); + + wxString strCurrent; + const wxChar *pc = sz; + for ( ;; ) { + if ( *pc == wxT('\0') || *pc == wxCONFIG_PATH_SEPARATOR ) { + if ( strCurrent == wxT(".") ) { + // ignore + } + else if ( strCurrent == wxT("..") ) { + // go up one level + if ( aParts.size() == 0 ) + wxLogWarning(_("'%s' has extra '..', ignored."), sz); + else + aParts.erase(aParts.end() - 1); + + strCurrent.Empty(); + } + else if ( !strCurrent.empty() ) { + aParts.push_back(strCurrent); + strCurrent.Empty(); + } + //else: + // could log an error here, but we prefer to ignore extra '/' + + if ( *pc == wxT('\0') ) + break; + } + else + strCurrent += *pc; + + pc++; + } +} diff --git a/Source/3rd Party/wx/src/common/containr.cpp b/Source/3rd Party/wx/src/common/containr.cpp index 275ffb574..ffa9ce975 100644 --- a/Source/3rd Party/wx/src/common/containr.cpp +++ b/Source/3rd Party/wx/src/common/containr.cpp @@ -1,678 +1,678 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/containr.cpp -// Purpose: implementation of wxControlContainer -// Author: Vadim Zeitlin -// Modified by: -// Created: 06.08.01 -// RCS-ID: $Id: containr.cpp 44273 2007-01-21 01:21:45Z VZ $ -// Copyright: (c) 2001 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/event.h" - #include "wx/window.h" - #include "wx/scrolbar.h" - #include "wx/radiobut.h" - #include "wx/containr.h" -#endif //WX_PRECOMP - -// trace mask for focus messages -#define TRACE_FOCUS _T("focus") - -// ============================================================================ -// implementation -// ============================================================================ - -wxControlContainer::wxControlContainer(wxWindow *winParent) -{ - m_winParent = winParent; - m_winLastFocused = NULL; - m_inSetFocus = false; -} - -bool wxControlContainer::AcceptsFocus() const -{ - // if we're not shown or disabled, we can't accept focus - if ( m_winParent->IsShown() && m_winParent->IsEnabled() ) - { - // otherwise we can accept focus either if we have no children at all - // (in this case we're probably not used as a container) or only when - // at least one child will accept focus - wxWindowList::compatibility_iterator node = m_winParent->GetChildren().GetFirst(); - if ( !node ) - return true; - -#ifdef __WXMAC__ - // wxMac has eventually the two scrollbars as children, they don't count - // as real children in the algorithm mentioned above - bool hasRealChildren = false ; -#endif - - while ( node ) - { - wxWindow *child = node->GetData(); - node = node->GetNext(); - -#ifdef __WXMAC__ - if ( m_winParent->MacIsWindowScrollbar( child ) ) - continue; - hasRealChildren = true ; -#endif - if ( child->AcceptsFocus() ) - { - return true; - } - } - -#ifdef __WXMAC__ - if ( !hasRealChildren ) - return true ; -#endif - } - - return false; -} - -void wxControlContainer::SetLastFocus(wxWindow *win) -{ - // the panel itself should never get the focus at all but if it does happen - // temporarily (as it seems to do under wxGTK), at the very least don't - // forget our previous m_winLastFocused - if ( win != m_winParent ) - { - // if we're setting the focus - if ( win ) - { - // find the last _immediate_ child which got focus - wxWindow *winParent = win; - while ( winParent != m_winParent ) - { - win = winParent; - winParent = win->GetParent(); - - // Yes, this can happen, though in a totally pathological case. - // like when detaching a menubar from a frame with a child - // which has pushed itself as an event handler for the menubar. - // (under wxGTK) - - wxASSERT_MSG( winParent, - _T("Setting last focus for a window that is not our child?") ); - } - } - - m_winLastFocused = win; - - if ( win ) - { - wxLogTrace(TRACE_FOCUS, _T("Set last focus to %s(%s)"), - win->GetClassInfo()->GetClassName(), - win->GetLabel().c_str()); - } - else - { - wxLogTrace(TRACE_FOCUS, _T("No more last focus")); - } - } - - // propagate the last focus upwards so that our parent can set focus back - // to us if it loses it now and regains later - wxWindow *parent = m_winParent->GetParent(); - if ( parent ) - { - wxChildFocusEvent eventFocus(m_winParent); - parent->GetEventHandler()->ProcessEvent(eventFocus); - } -} - -// -------------------------------------------------------------------- -// The following four functions are used to find other radio buttons -// within the same group. Used by wxSetFocusToChild on wxMSW -// -------------------------------------------------------------------- - -#ifdef __WXMSW__ - -wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn) -{ - if ( btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) ) - return NULL; - - const wxWindowList& siblings = btn->GetParent()->GetChildren(); - wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn); - wxCHECK_MSG( nodeThis, NULL, _T("radio button not a child of its parent?") ); - - // Iterate over all previous siblings until we find the next radio button - wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious(); - wxRadioButton *prevBtn = 0; - while (nodeBefore) - { - prevBtn = wxDynamicCast(nodeBefore->GetData(), wxRadioButton); - if (prevBtn) - break; - - nodeBefore = nodeBefore->GetPrevious(); - } - - if (!prevBtn || prevBtn->HasFlag(wxRB_SINGLE)) - { - // no more buttons in group - return NULL; - } - - return prevBtn; -} - -wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn) -{ - if (btn->HasFlag(wxRB_SINGLE)) - return NULL; - - const wxWindowList& siblings = btn->GetParent()->GetChildren(); - wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn); - wxCHECK_MSG( nodeThis, NULL, _T("radio button not a child of its parent?") ); - - // Iterate over all previous siblings until we find the next radio button - wxWindowList::compatibility_iterator nodeNext = nodeThis->GetNext(); - wxRadioButton *nextBtn = 0; - while (nodeNext) - { - nextBtn = wxDynamicCast(nodeNext->GetData(), wxRadioButton); - if (nextBtn) - break; - - nodeNext = nodeNext->GetNext(); - } - - if ( !nextBtn || nextBtn->HasFlag(wxRB_GROUP) || nextBtn->HasFlag(wxRB_SINGLE) ) - { - // no more buttons or the first button of the next group - return NULL; - } - - return nextBtn; -} - -wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn) -{ - while (true) - { - wxRadioButton* prevBtn = wxGetPreviousButtonInGroup(btn); - if (!prevBtn) - return btn; - - btn = prevBtn; - } -} - -wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn) -{ - while (true) - { - wxRadioButton* nextBtn = wxGetNextButtonInGroup(btn); - if (!nextBtn) - return btn; - - btn = nextBtn; - } -} - -wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn) -{ - // Find currently selected button - if (btn->GetValue()) - return btn; - - if (btn->HasFlag(wxRB_SINGLE)) - return NULL; - - wxRadioButton *selBtn; - - // First check all previous buttons - for (selBtn = wxGetPreviousButtonInGroup(btn); selBtn; selBtn = wxGetPreviousButtonInGroup(selBtn)) - if (selBtn->GetValue()) - return selBtn; - - // Now all following buttons - for (selBtn = wxGetNextButtonInGroup(btn); selBtn; selBtn = wxGetNextButtonInGroup(selBtn)) - if (selBtn->GetValue()) - return selBtn; - - return NULL; -} - -#endif // __WXMSW__ - -// ---------------------------------------------------------------------------- -// Keyboard handling - this is the place where the TAB traversal logic is -// implemented. As this code is common to all ports, this ensures consistent -// behaviour even if we don't specify how exactly the wxNavigationKeyEvent are -// generated and this is done in platform specific code which also ensures that -// we can follow the given platform standards. -// ---------------------------------------------------------------------------- - -void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) -{ - wxWindow *parent = m_winParent->GetParent(); - - // the event is propagated downwards if the event emitter was our parent - bool goingDown = event.GetEventObject() == parent; - - const wxWindowList& children = m_winParent->GetChildren(); - - // if we have exactly one notebook-like child window (actually it could be - // any window that returns true from its HasMultiplePages()), then - // [Shift-]Ctrl-Tab and Ctrl-PageUp/Down keys should iterate over its pages - // even if the focus is outside of the control because this is how the - // standard MSW properties dialogs behave and we do it under other platforms - // as well because it seems like a good idea -- but we can always put this - // block inside "#ifdef __WXMSW__" if it's not suitable there - if ( event.IsWindowChange() && !goingDown ) - { - // check if we have a unique notebook-like child - wxWindow *bookctrl = NULL; - for ( wxWindowList::const_iterator i = children.begin(), - end = children.end(); - i != end; - ++i ) - { - wxWindow * const window = *i; - if ( window->HasMultiplePages() ) - { - if ( bookctrl ) - { - // this is the second book-like control already so don't do - // anything as we don't know which one should have its page - // changed - bookctrl = NULL; - break; - } - - bookctrl = window; - } - } - - if ( bookctrl ) - { - // make sure that we don't bubble up the event again from the book - // control resulting in infinite recursion - wxNavigationKeyEvent eventCopy(event); - eventCopy.SetEventObject(m_winParent); - if ( bookctrl->GetEventHandler()->ProcessEvent(eventCopy) ) - return; - } - } - - // there is not much to do if we don't have children and we're not - // interested in "notebook page change" events here - if ( !children.GetCount() || event.IsWindowChange() ) - { - // let the parent process it unless it already comes from our parent - // of we don't have any - if ( goingDown || - !parent || !parent->GetEventHandler()->ProcessEvent(event) ) - { - event.Skip(); - } - - return; - } - - // where are we going? - const bool forward = event.GetDirection(); - - // the node of the children list from which we should start looking for the - // next acceptable child - wxWindowList::compatibility_iterator node, start_node; - - // we should start from the first/last control and not from the one which - // had focus the last time if we're propagating the event downwards because - // for our parent we look like a single control - if ( goingDown ) - { - // just to be sure it's not used (normally this is not necessary, but - // doesn't hurt neither) - m_winLastFocused = (wxWindow *)NULL; - - // start from first or last depending on where we're going - node = forward ? children.GetFirst() : children.GetLast(); - } - else // going up - { - // try to find the child which has the focus currently - - // the event emitter might have done this for us - wxWindow *winFocus = event.GetCurrentFocus(); - - // but if not, we might know where the focus was ourselves - if (!winFocus) - winFocus = m_winLastFocused; - - // if still no luck, do it the hard way - if (!winFocus) - winFocus = wxWindow::FindFocus(); - - if ( winFocus ) - { -#ifdef __WXMSW__ - // If we are in a radio button group, start from the first item in the - // group - if ( event.IsFromTab() && wxIsKindOf(winFocus, wxRadioButton ) ) - winFocus = wxGetFirstButtonInGroup((wxRadioButton*)winFocus); -#endif - // ok, we found the focus - now is it our child? - start_node = children.Find( winFocus ); - } - - if ( !start_node && m_winLastFocused ) - { - // window which has focus isn't our child, fall back to the one - // which had the focus the last time - start_node = children.Find( m_winLastFocused ); - } - - // if we still didn't find anything, we should start with the first one - if ( !start_node ) - { - start_node = children.GetFirst(); - } - - // and the first child which we can try setting focus to is the next or - // the previous one - node = forward ? start_node->GetNext() : start_node->GetPrevious(); - } - - // we want to cycle over all elements passing by NULL - for ( ;; ) - { - // don't go into infinite loop - if ( start_node && node && node == start_node ) - break; - - // Have we come to the last or first item on the panel? - if ( !node ) - { - if ( !start_node ) - { - // exit now as otherwise we'd loop forever - break; - } - - if ( !goingDown ) - { - // Check if our (maybe grand) parent is another panel: if this - // is the case, they will know what to do with this navigation - // key and so give them the chance to process it instead of - // looping inside this panel (normally, the focus will go to - // the next/previous item after this panel in the parent - // panel). - wxWindow *focussed_child_of_parent = m_winParent; - while ( parent ) - { - // we don't want to tab into a different dialog or frame - if ( focussed_child_of_parent->IsTopLevel() ) - break; - - event.SetCurrentFocus( focussed_child_of_parent ); - if ( parent->GetEventHandler()->ProcessEvent( event ) ) - return; - - focussed_child_of_parent = parent; - - parent = parent->GetParent(); - } - } - //else: as the focus came from our parent, we definitely don't want - // to send it back to it! - - // no, we are not inside another panel so process this ourself - node = forward ? children.GetFirst() : children.GetLast(); - - continue; - } - - wxWindow *child = node->GetData(); - -#ifdef __WXMSW__ - if ( event.IsFromTab() ) - { - if ( wxIsKindOf(child, wxRadioButton) ) - { - // only radio buttons with either wxRB_GROUP or wxRB_SINGLE - // can be tabbed to - if ( child->HasFlag(wxRB_GROUP) ) - { - // need to tab into the active button within a group - wxRadioButton *rb = wxGetSelectedButtonInGroup((wxRadioButton*)child); - if ( rb ) - child = rb; - } - else if ( !child->HasFlag(wxRB_SINGLE) ) - { - node = forward ? node->GetNext() : node->GetPrevious(); - continue; - } - } - } - else if ( m_winLastFocused && - wxIsKindOf(m_winLastFocused, wxRadioButton) && - !m_winLastFocused->HasFlag(wxRB_SINGLE) ) - { - // cursor keys don't navigate out of a radio button group so - // find the correct radio button to focus - if ( forward ) - { - child = wxGetNextButtonInGroup((wxRadioButton*)m_winLastFocused); - if ( !child ) - { - // no next button in group, set it to the first button - child = wxGetFirstButtonInGroup((wxRadioButton*)m_winLastFocused); - } - } - else - { - child = wxGetPreviousButtonInGroup((wxRadioButton*)m_winLastFocused); - if ( !child ) - { - // no previous button in group, set it to the last button - child = wxGetLastButtonInGroup((wxRadioButton*)m_winLastFocused); - } - } - - if ( child == m_winLastFocused ) - { - // must be a group consisting of only one button therefore - // no need to send a navigation event - event.Skip(false); - return; - } - } -#endif // __WXMSW__ - - if ( child->AcceptsFocusFromKeyboard() ) - { - // if we're setting the focus to a child panel we should prevent it - // from giving it to the child which had the focus the last time - // and instead give it to the first/last child depending from which - // direction we're coming - event.SetEventObject(m_winParent); - - // disable propagation for this call as otherwise the event might - // bounce back to us. - wxPropagationDisabler disableProp(event); - if ( !child->GetEventHandler()->ProcessEvent(event) ) - { - // set it first in case SetFocusFromKbd() results in focus - // change too - m_winLastFocused = child; - - // everything is simple: just give focus to it - child->SetFocusFromKbd(); - } - //else: the child manages its focus itself - - event.Skip( false ); - - return; - } - - node = forward ? node->GetNext() : node->GetPrevious(); - } - - // we cycled through all of our children and none of them wanted to accept - // focus - event.Skip(); -} - -void wxControlContainer::HandleOnWindowDestroy(wxWindowBase *child) -{ - if ( child == m_winLastFocused ) - m_winLastFocused = NULL; -} - -// ---------------------------------------------------------------------------- -// focus handling -// ---------------------------------------------------------------------------- - -bool wxControlContainer::DoSetFocus() -{ - wxLogTrace(TRACE_FOCUS, _T("SetFocus on wxPanel 0x%p."), - m_winParent->GetHandle()); - - if (m_inSetFocus) - return true; - - // when the panel gets the focus we move the focus to either the last - // window that had the focus or the first one that can get it unless the - // focus had been already set to some other child - - wxWindow *win = wxWindow::FindFocus(); - while ( win ) - { - if ( win == m_winParent ) - { - // our child already has focus, don't take it away from it - return true; - } - - if ( win->IsTopLevel() ) - { - // don't look beyond the first top level parent - useless and - // unnecessary - break; - } - - win = win->GetParent(); - } - - // protect against infinite recursion: - m_inSetFocus = true; - - bool ret = SetFocusToChild(); - - m_inSetFocus = false; - - return ret; -} - -void wxControlContainer::HandleOnFocus(wxFocusEvent& event) -{ - wxLogTrace(TRACE_FOCUS, _T("OnFocus on wxPanel 0x%p, name: %s"), - m_winParent->GetHandle(), - m_winParent->GetName().c_str() ); - - DoSetFocus(); - - event.Skip(); -} - -bool wxControlContainer::SetFocusToChild() -{ - return wxSetFocusToChild(m_winParent, &m_winLastFocused); -} - -// ---------------------------------------------------------------------------- -// SetFocusToChild(): this function is used by wxPanel but also by wxFrame in -// wxMSW, this is why it is outside of wxControlContainer class -// ---------------------------------------------------------------------------- - -bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused) -{ - wxCHECK_MSG( win, false, _T("wxSetFocusToChild(): invalid window") ); - wxCHECK_MSG( childLastFocused, false, - _T("wxSetFocusToChild(): NULL child poonter") ); - - if ( *childLastFocused ) - { - // It might happen that the window got reparented - if ( (*childLastFocused)->GetParent() == win ) - { - wxLogTrace(TRACE_FOCUS, - _T("SetFocusToChild() => last child (0x%p)."), - (*childLastFocused)->GetHandle()); - - // not SetFocusFromKbd(): we're restoring focus back to the old - // window and not setting it as the result of a kbd action - (*childLastFocused)->SetFocus(); - return true; - } - else - { - // it doesn't count as such any more - *childLastFocused = (wxWindow *)NULL; - } - } - - // set the focus to the first child who wants it - wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); - while ( node ) - { - wxWindow *child = node->GetData(); - node = node->GetNext(); - -#ifdef __WXMAC__ - if ( child->GetParent()->MacIsWindowScrollbar( child ) ) - continue; -#endif - - if ( child->AcceptsFocusFromKeyboard() && !child->IsTopLevel() ) - { -#ifdef __WXMSW__ - // If a radiobutton is the first focusable child, search for the - // selected radiobutton in the same group - wxRadioButton* btn = wxDynamicCast(child, wxRadioButton); - if (btn) - { - wxRadioButton* selected = wxGetSelectedButtonInGroup(btn); - if (selected) - child = selected; - } -#endif - - wxLogTrace(TRACE_FOCUS, - _T("SetFocusToChild() => first child (0x%p)."), - child->GetHandle()); - - *childLastFocused = child; - child->SetFocusFromKbd(); - return true; - } - } - - return false; -} +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/containr.cpp +// Purpose: implementation of wxControlContainer +// Author: Vadim Zeitlin +// Modified by: +// Created: 06.08.01 +// RCS-ID: $Id: containr.cpp 44273 2007-01-21 01:21:45Z VZ $ +// Copyright: (c) 2001 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/event.h" + #include "wx/window.h" + #include "wx/scrolbar.h" + #include "wx/radiobut.h" + #include "wx/containr.h" +#endif //WX_PRECOMP + +// trace mask for focus messages +#define TRACE_FOCUS _T("focus") + +// ============================================================================ +// implementation +// ============================================================================ + +wxControlContainer::wxControlContainer(wxWindow *winParent) +{ + m_winParent = winParent; + m_winLastFocused = NULL; + m_inSetFocus = false; +} + +bool wxControlContainer::AcceptsFocus() const +{ + // if we're not shown or disabled, we can't accept focus + if ( m_winParent->IsShown() && m_winParent->IsEnabled() ) + { + // otherwise we can accept focus either if we have no children at all + // (in this case we're probably not used as a container) or only when + // at least one child will accept focus + wxWindowList::compatibility_iterator node = m_winParent->GetChildren().GetFirst(); + if ( !node ) + return true; + +#ifdef __WXMAC__ + // wxMac has eventually the two scrollbars as children, they don't count + // as real children in the algorithm mentioned above + bool hasRealChildren = false ; +#endif + + while ( node ) + { + wxWindow *child = node->GetData(); + node = node->GetNext(); + +#ifdef __WXMAC__ + if ( m_winParent->MacIsWindowScrollbar( child ) ) + continue; + hasRealChildren = true ; +#endif + if ( child->AcceptsFocus() ) + { + return true; + } + } + +#ifdef __WXMAC__ + if ( !hasRealChildren ) + return true ; +#endif + } + + return false; +} + +void wxControlContainer::SetLastFocus(wxWindow *win) +{ + // the panel itself should never get the focus at all but if it does happen + // temporarily (as it seems to do under wxGTK), at the very least don't + // forget our previous m_winLastFocused + if ( win != m_winParent ) + { + // if we're setting the focus + if ( win ) + { + // find the last _immediate_ child which got focus + wxWindow *winParent = win; + while ( winParent != m_winParent ) + { + win = winParent; + winParent = win->GetParent(); + + // Yes, this can happen, though in a totally pathological case. + // like when detaching a menubar from a frame with a child + // which has pushed itself as an event handler for the menubar. + // (under wxGTK) + + wxASSERT_MSG( winParent, + _T("Setting last focus for a window that is not our child?") ); + } + } + + m_winLastFocused = win; + + if ( win ) + { + wxLogTrace(TRACE_FOCUS, _T("Set last focus to %s(%s)"), + win->GetClassInfo()->GetClassName(), + win->GetLabel().c_str()); + } + else + { + wxLogTrace(TRACE_FOCUS, _T("No more last focus")); + } + } + + // propagate the last focus upwards so that our parent can set focus back + // to us if it loses it now and regains later + wxWindow *parent = m_winParent->GetParent(); + if ( parent ) + { + wxChildFocusEvent eventFocus(m_winParent); + parent->GetEventHandler()->ProcessEvent(eventFocus); + } +} + +// -------------------------------------------------------------------- +// The following four functions are used to find other radio buttons +// within the same group. Used by wxSetFocusToChild on wxMSW +// -------------------------------------------------------------------- + +#ifdef __WXMSW__ + +wxRadioButton* wxGetPreviousButtonInGroup(wxRadioButton *btn) +{ + if ( btn->HasFlag(wxRB_GROUP) || btn->HasFlag(wxRB_SINGLE) ) + return NULL; + + const wxWindowList& siblings = btn->GetParent()->GetChildren(); + wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn); + wxCHECK_MSG( nodeThis, NULL, _T("radio button not a child of its parent?") ); + + // Iterate over all previous siblings until we find the next radio button + wxWindowList::compatibility_iterator nodeBefore = nodeThis->GetPrevious(); + wxRadioButton *prevBtn = 0; + while (nodeBefore) + { + prevBtn = wxDynamicCast(nodeBefore->GetData(), wxRadioButton); + if (prevBtn) + break; + + nodeBefore = nodeBefore->GetPrevious(); + } + + if (!prevBtn || prevBtn->HasFlag(wxRB_SINGLE)) + { + // no more buttons in group + return NULL; + } + + return prevBtn; +} + +wxRadioButton* wxGetNextButtonInGroup(wxRadioButton *btn) +{ + if (btn->HasFlag(wxRB_SINGLE)) + return NULL; + + const wxWindowList& siblings = btn->GetParent()->GetChildren(); + wxWindowList::compatibility_iterator nodeThis = siblings.Find(btn); + wxCHECK_MSG( nodeThis, NULL, _T("radio button not a child of its parent?") ); + + // Iterate over all previous siblings until we find the next radio button + wxWindowList::compatibility_iterator nodeNext = nodeThis->GetNext(); + wxRadioButton *nextBtn = 0; + while (nodeNext) + { + nextBtn = wxDynamicCast(nodeNext->GetData(), wxRadioButton); + if (nextBtn) + break; + + nodeNext = nodeNext->GetNext(); + } + + if ( !nextBtn || nextBtn->HasFlag(wxRB_GROUP) || nextBtn->HasFlag(wxRB_SINGLE) ) + { + // no more buttons or the first button of the next group + return NULL; + } + + return nextBtn; +} + +wxRadioButton* wxGetFirstButtonInGroup(wxRadioButton *btn) +{ + while (true) + { + wxRadioButton* prevBtn = wxGetPreviousButtonInGroup(btn); + if (!prevBtn) + return btn; + + btn = prevBtn; + } +} + +wxRadioButton* wxGetLastButtonInGroup(wxRadioButton *btn) +{ + while (true) + { + wxRadioButton* nextBtn = wxGetNextButtonInGroup(btn); + if (!nextBtn) + return btn; + + btn = nextBtn; + } +} + +wxRadioButton* wxGetSelectedButtonInGroup(wxRadioButton *btn) +{ + // Find currently selected button + if (btn->GetValue()) + return btn; + + if (btn->HasFlag(wxRB_SINGLE)) + return NULL; + + wxRadioButton *selBtn; + + // First check all previous buttons + for (selBtn = wxGetPreviousButtonInGroup(btn); selBtn; selBtn = wxGetPreviousButtonInGroup(selBtn)) + if (selBtn->GetValue()) + return selBtn; + + // Now all following buttons + for (selBtn = wxGetNextButtonInGroup(btn); selBtn; selBtn = wxGetNextButtonInGroup(selBtn)) + if (selBtn->GetValue()) + return selBtn; + + return NULL; +} + +#endif // __WXMSW__ + +// ---------------------------------------------------------------------------- +// Keyboard handling - this is the place where the TAB traversal logic is +// implemented. As this code is common to all ports, this ensures consistent +// behaviour even if we don't specify how exactly the wxNavigationKeyEvent are +// generated and this is done in platform specific code which also ensures that +// we can follow the given platform standards. +// ---------------------------------------------------------------------------- + +void wxControlContainer::HandleOnNavigationKey( wxNavigationKeyEvent& event ) +{ + wxWindow *parent = m_winParent->GetParent(); + + // the event is propagated downwards if the event emitter was our parent + bool goingDown = event.GetEventObject() == parent; + + const wxWindowList& children = m_winParent->GetChildren(); + + // if we have exactly one notebook-like child window (actually it could be + // any window that returns true from its HasMultiplePages()), then + // [Shift-]Ctrl-Tab and Ctrl-PageUp/Down keys should iterate over its pages + // even if the focus is outside of the control because this is how the + // standard MSW properties dialogs behave and we do it under other platforms + // as well because it seems like a good idea -- but we can always put this + // block inside "#ifdef __WXMSW__" if it's not suitable there + if ( event.IsWindowChange() && !goingDown ) + { + // check if we have a unique notebook-like child + wxWindow *bookctrl = NULL; + for ( wxWindowList::const_iterator i = children.begin(), + end = children.end(); + i != end; + ++i ) + { + wxWindow * const window = *i; + if ( window->HasMultiplePages() ) + { + if ( bookctrl ) + { + // this is the second book-like control already so don't do + // anything as we don't know which one should have its page + // changed + bookctrl = NULL; + break; + } + + bookctrl = window; + } + } + + if ( bookctrl ) + { + // make sure that we don't bubble up the event again from the book + // control resulting in infinite recursion + wxNavigationKeyEvent eventCopy(event); + eventCopy.SetEventObject(m_winParent); + if ( bookctrl->GetEventHandler()->ProcessEvent(eventCopy) ) + return; + } + } + + // there is not much to do if we don't have children and we're not + // interested in "notebook page change" events here + if ( !children.GetCount() || event.IsWindowChange() ) + { + // let the parent process it unless it already comes from our parent + // of we don't have any + if ( goingDown || + !parent || !parent->GetEventHandler()->ProcessEvent(event) ) + { + event.Skip(); + } + + return; + } + + // where are we going? + const bool forward = event.GetDirection(); + + // the node of the children list from which we should start looking for the + // next acceptable child + wxWindowList::compatibility_iterator node, start_node; + + // we should start from the first/last control and not from the one which + // had focus the last time if we're propagating the event downwards because + // for our parent we look like a single control + if ( goingDown ) + { + // just to be sure it's not used (normally this is not necessary, but + // doesn't hurt neither) + m_winLastFocused = (wxWindow *)NULL; + + // start from first or last depending on where we're going + node = forward ? children.GetFirst() : children.GetLast(); + } + else // going up + { + // try to find the child which has the focus currently + + // the event emitter might have done this for us + wxWindow *winFocus = event.GetCurrentFocus(); + + // but if not, we might know where the focus was ourselves + if (!winFocus) + winFocus = m_winLastFocused; + + // if still no luck, do it the hard way + if (!winFocus) + winFocus = wxWindow::FindFocus(); + + if ( winFocus ) + { +#ifdef __WXMSW__ + // If we are in a radio button group, start from the first item in the + // group + if ( event.IsFromTab() && wxIsKindOf(winFocus, wxRadioButton ) ) + winFocus = wxGetFirstButtonInGroup((wxRadioButton*)winFocus); +#endif + // ok, we found the focus - now is it our child? + start_node = children.Find( winFocus ); + } + + if ( !start_node && m_winLastFocused ) + { + // window which has focus isn't our child, fall back to the one + // which had the focus the last time + start_node = children.Find( m_winLastFocused ); + } + + // if we still didn't find anything, we should start with the first one + if ( !start_node ) + { + start_node = children.GetFirst(); + } + + // and the first child which we can try setting focus to is the next or + // the previous one + node = forward ? start_node->GetNext() : start_node->GetPrevious(); + } + + // we want to cycle over all elements passing by NULL + for ( ;; ) + { + // don't go into infinite loop + if ( start_node && node && node == start_node ) + break; + + // Have we come to the last or first item on the panel? + if ( !node ) + { + if ( !start_node ) + { + // exit now as otherwise we'd loop forever + break; + } + + if ( !goingDown ) + { + // Check if our (maybe grand) parent is another panel: if this + // is the case, they will know what to do with this navigation + // key and so give them the chance to process it instead of + // looping inside this panel (normally, the focus will go to + // the next/previous item after this panel in the parent + // panel). + wxWindow *focussed_child_of_parent = m_winParent; + while ( parent ) + { + // we don't want to tab into a different dialog or frame + if ( focussed_child_of_parent->IsTopLevel() ) + break; + + event.SetCurrentFocus( focussed_child_of_parent ); + if ( parent->GetEventHandler()->ProcessEvent( event ) ) + return; + + focussed_child_of_parent = parent; + + parent = parent->GetParent(); + } + } + //else: as the focus came from our parent, we definitely don't want + // to send it back to it! + + // no, we are not inside another panel so process this ourself + node = forward ? children.GetFirst() : children.GetLast(); + + continue; + } + + wxWindow *child = node->GetData(); + +#ifdef __WXMSW__ + if ( event.IsFromTab() ) + { + if ( wxIsKindOf(child, wxRadioButton) ) + { + // only radio buttons with either wxRB_GROUP or wxRB_SINGLE + // can be tabbed to + if ( child->HasFlag(wxRB_GROUP) ) + { + // need to tab into the active button within a group + wxRadioButton *rb = wxGetSelectedButtonInGroup((wxRadioButton*)child); + if ( rb ) + child = rb; + } + else if ( !child->HasFlag(wxRB_SINGLE) ) + { + node = forward ? node->GetNext() : node->GetPrevious(); + continue; + } + } + } + else if ( m_winLastFocused && + wxIsKindOf(m_winLastFocused, wxRadioButton) && + !m_winLastFocused->HasFlag(wxRB_SINGLE) ) + { + // cursor keys don't navigate out of a radio button group so + // find the correct radio button to focus + if ( forward ) + { + child = wxGetNextButtonInGroup((wxRadioButton*)m_winLastFocused); + if ( !child ) + { + // no next button in group, set it to the first button + child = wxGetFirstButtonInGroup((wxRadioButton*)m_winLastFocused); + } + } + else + { + child = wxGetPreviousButtonInGroup((wxRadioButton*)m_winLastFocused); + if ( !child ) + { + // no previous button in group, set it to the last button + child = wxGetLastButtonInGroup((wxRadioButton*)m_winLastFocused); + } + } + + if ( child == m_winLastFocused ) + { + // must be a group consisting of only one button therefore + // no need to send a navigation event + event.Skip(false); + return; + } + } +#endif // __WXMSW__ + + if ( child->AcceptsFocusFromKeyboard() ) + { + // if we're setting the focus to a child panel we should prevent it + // from giving it to the child which had the focus the last time + // and instead give it to the first/last child depending from which + // direction we're coming + event.SetEventObject(m_winParent); + + // disable propagation for this call as otherwise the event might + // bounce back to us. + wxPropagationDisabler disableProp(event); + if ( !child->GetEventHandler()->ProcessEvent(event) ) + { + // set it first in case SetFocusFromKbd() results in focus + // change too + m_winLastFocused = child; + + // everything is simple: just give focus to it + child->SetFocusFromKbd(); + } + //else: the child manages its focus itself + + event.Skip( false ); + + return; + } + + node = forward ? node->GetNext() : node->GetPrevious(); + } + + // we cycled through all of our children and none of them wanted to accept + // focus + event.Skip(); +} + +void wxControlContainer::HandleOnWindowDestroy(wxWindowBase *child) +{ + if ( child == m_winLastFocused ) + m_winLastFocused = NULL; +} + +// ---------------------------------------------------------------------------- +// focus handling +// ---------------------------------------------------------------------------- + +bool wxControlContainer::DoSetFocus() +{ + wxLogTrace(TRACE_FOCUS, _T("SetFocus on wxPanel 0x%p."), + m_winParent->GetHandle()); + + if (m_inSetFocus) + return true; + + // when the panel gets the focus we move the focus to either the last + // window that had the focus or the first one that can get it unless the + // focus had been already set to some other child + + wxWindow *win = wxWindow::FindFocus(); + while ( win ) + { + if ( win == m_winParent ) + { + // our child already has focus, don't take it away from it + return true; + } + + if ( win->IsTopLevel() ) + { + // don't look beyond the first top level parent - useless and + // unnecessary + break; + } + + win = win->GetParent(); + } + + // protect against infinite recursion: + m_inSetFocus = true; + + bool ret = SetFocusToChild(); + + m_inSetFocus = false; + + return ret; +} + +void wxControlContainer::HandleOnFocus(wxFocusEvent& event) +{ + wxLogTrace(TRACE_FOCUS, _T("OnFocus on wxPanel 0x%p, name: %s"), + m_winParent->GetHandle(), + m_winParent->GetName().c_str() ); + + DoSetFocus(); + + event.Skip(); +} + +bool wxControlContainer::SetFocusToChild() +{ + return wxSetFocusToChild(m_winParent, &m_winLastFocused); +} + +// ---------------------------------------------------------------------------- +// SetFocusToChild(): this function is used by wxPanel but also by wxFrame in +// wxMSW, this is why it is outside of wxControlContainer class +// ---------------------------------------------------------------------------- + +bool wxSetFocusToChild(wxWindow *win, wxWindow **childLastFocused) +{ + wxCHECK_MSG( win, false, _T("wxSetFocusToChild(): invalid window") ); + wxCHECK_MSG( childLastFocused, false, + _T("wxSetFocusToChild(): NULL child poonter") ); + + if ( *childLastFocused ) + { + // It might happen that the window got reparented + if ( (*childLastFocused)->GetParent() == win ) + { + wxLogTrace(TRACE_FOCUS, + _T("SetFocusToChild() => last child (0x%p)."), + (*childLastFocused)->GetHandle()); + + // not SetFocusFromKbd(): we're restoring focus back to the old + // window and not setting it as the result of a kbd action + (*childLastFocused)->SetFocus(); + return true; + } + else + { + // it doesn't count as such any more + *childLastFocused = (wxWindow *)NULL; + } + } + + // set the focus to the first child who wants it + wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); + while ( node ) + { + wxWindow *child = node->GetData(); + node = node->GetNext(); + +#ifdef __WXMAC__ + if ( child->GetParent()->MacIsWindowScrollbar( child ) ) + continue; +#endif + + if ( child->AcceptsFocusFromKeyboard() && !child->IsTopLevel() ) + { +#ifdef __WXMSW__ + // If a radiobutton is the first focusable child, search for the + // selected radiobutton in the same group + wxRadioButton* btn = wxDynamicCast(child, wxRadioButton); + if (btn) + { + wxRadioButton* selected = wxGetSelectedButtonInGroup(btn); + if (selected) + child = selected; + } +#endif + + wxLogTrace(TRACE_FOCUS, + _T("SetFocusToChild() => first child (0x%p)."), + child->GetHandle()); + + *childLastFocused = child; + child->SetFocusFromKbd(); + return true; + } + } + + return false; +} diff --git a/Source/3rd Party/wx/src/common/convauto.cpp b/Source/3rd Party/wx/src/common/convauto.cpp index 540f180ff..3205b7bea 100644 --- a/Source/3rd Party/wx/src/common/convauto.cpp +++ b/Source/3rd Party/wx/src/common/convauto.cpp @@ -1,214 +1,214 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/convauto.cpp -// Purpose: implementation of wxConvAuto -// Author: Vadim Zeitlin -// Created: 2006-04-04 -// RCS-ID: $Id: convauto.cpp 38570 2006-04-05 14:37:47Z VZ $ -// Copyright: (c) 2006 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_WCHAR_T - -#ifndef WX_PRECOMP -#endif //WX_PRECOMP - -#include "wx/convauto.h" - -// ============================================================================ -// implementation -// ============================================================================ - -/* static */ -wxConvAuto::BOMType wxConvAuto::DetectBOM(const char *src, size_t srcLen) -{ - if ( srcLen < 2 ) - { - // minimal BOM is 2 bytes so bail out immediately and simplify the code - // below which wouldn't need to check for length for UTF-16 cases - return BOM_None; - } - - // examine the buffer for BOM presence - // - // see http://www.unicode.org/faq/utf_bom.html#BOM - switch ( *src++ ) - { - case '\0': - // could only be big endian UTF-32 (00 00 FE FF) - if ( srcLen >= 4 && - src[0] == '\0' && - src[1] == '\xfe' && - src[2] == '\xff' ) - { - return BOM_UTF32BE; - } - break; - - case '\xfe': - // could only be big endian UTF-16 (FE FF) - if ( *src++ == '\xff' ) - { - return BOM_UTF16BE; - } - break; - - case '\xff': - // could be either little endian UTF-16 or UTF-32, both start - // with FF FE - if ( *src++ == '\xfe' ) - { - return srcLen >= 4 && src[0] == '\0' && src[1] == '\0' - ? BOM_UTF32LE - : BOM_UTF16LE; - } - break; - - case '\xef': - // is this UTF-8 BOM (EF BB BF)? - if ( srcLen >= 3 && src[0] == '\xbb' && src[1] == '\xbf' ) - { - return BOM_UTF8; - } - break; - } - - return BOM_None; -} - -void wxConvAuto::InitFromBOM(BOMType bomType) -{ - m_consumedBOM = false; - - switch ( bomType ) - { - case BOM_UTF32BE: - m_conv = new wxMBConvUTF32BE; - m_ownsConv = true; - break; - - case BOM_UTF32LE: - m_conv = new wxMBConvUTF32LE; - m_ownsConv = true; - break; - - case BOM_UTF16BE: - m_conv = new wxMBConvUTF16BE; - m_ownsConv = true; - break; - - case BOM_UTF16LE: - m_conv = new wxMBConvUTF16LE; - m_ownsConv = true; - break; - - case BOM_UTF8: - m_conv = &wxConvUTF8; - m_ownsConv = false; - break; - - default: - wxFAIL_MSG( _T("unexpected BOM type") ); - // fall through: still need to create something - - case BOM_None: - InitWithDefault(); - m_consumedBOM = true; // as there is nothing to consume - } -} - -void wxConvAuto::SkipBOM(const char **src, size_t *len) const -{ - int ofs; - switch ( m_bomType ) - { - case BOM_UTF32BE: - case BOM_UTF32LE: - ofs = 4; - break; - - case BOM_UTF16BE: - case BOM_UTF16LE: - ofs = 2; - break; - - case BOM_UTF8: - ofs = 3; - break; - - default: - wxFAIL_MSG( _T("unexpected BOM type") ); - // fall through: still need to create something - - case BOM_None: - ofs = 0; - } - - *src += ofs; - if ( *len != (size_t)-1 ) - *len -= ofs; -} - -void wxConvAuto::InitFromInput(const char **src, size_t *len) -{ - m_bomType = DetectBOM(*src, *len); - InitFromBOM(m_bomType); - SkipBOM(src, len); -} - -size_t -wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - // we check BOM and create the appropriate conversion the first time we're - // called but we also need to ensure that the BOM is skipped not only - // during this initial call but also during the first call with non-NULL - // dst as typically we're first called with NULL dst to calculate the - // needed buffer size - wxConvAuto *self = wx_const_cast(wxConvAuto *, this); - if ( !m_conv ) - { - self->InitFromInput(&src, &srcLen); - if ( dst ) - self->m_consumedBOM = true; - } - - if ( !m_consumedBOM && dst ) - { - self->m_consumedBOM = true; - SkipBOM(&src, &srcLen); - } - - return m_conv->ToWChar(dst, dstLen, src, srcLen); -} - -size_t -wxConvAuto::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( !m_conv ) - { - // default to UTF-8 for the multibyte output - wx_const_cast(wxConvAuto *, this)->InitWithDefault(); - } - - return m_conv->FromWChar(dst, dstLen, src, srcLen); -} - -#endif // wxUSE_WCHAR_T - +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/convauto.cpp +// Purpose: implementation of wxConvAuto +// Author: Vadim Zeitlin +// Created: 2006-04-04 +// RCS-ID: $Id: convauto.cpp 38570 2006-04-05 14:37:47Z VZ $ +// Copyright: (c) 2006 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_WCHAR_T + +#ifndef WX_PRECOMP +#endif //WX_PRECOMP + +#include "wx/convauto.h" + +// ============================================================================ +// implementation +// ============================================================================ + +/* static */ +wxConvAuto::BOMType wxConvAuto::DetectBOM(const char *src, size_t srcLen) +{ + if ( srcLen < 2 ) + { + // minimal BOM is 2 bytes so bail out immediately and simplify the code + // below which wouldn't need to check for length for UTF-16 cases + return BOM_None; + } + + // examine the buffer for BOM presence + // + // see http://www.unicode.org/faq/utf_bom.html#BOM + switch ( *src++ ) + { + case '\0': + // could only be big endian UTF-32 (00 00 FE FF) + if ( srcLen >= 4 && + src[0] == '\0' && + src[1] == '\xfe' && + src[2] == '\xff' ) + { + return BOM_UTF32BE; + } + break; + + case '\xfe': + // could only be big endian UTF-16 (FE FF) + if ( *src++ == '\xff' ) + { + return BOM_UTF16BE; + } + break; + + case '\xff': + // could be either little endian UTF-16 or UTF-32, both start + // with FF FE + if ( *src++ == '\xfe' ) + { + return srcLen >= 4 && src[0] == '\0' && src[1] == '\0' + ? BOM_UTF32LE + : BOM_UTF16LE; + } + break; + + case '\xef': + // is this UTF-8 BOM (EF BB BF)? + if ( srcLen >= 3 && src[0] == '\xbb' && src[1] == '\xbf' ) + { + return BOM_UTF8; + } + break; + } + + return BOM_None; +} + +void wxConvAuto::InitFromBOM(BOMType bomType) +{ + m_consumedBOM = false; + + switch ( bomType ) + { + case BOM_UTF32BE: + m_conv = new wxMBConvUTF32BE; + m_ownsConv = true; + break; + + case BOM_UTF32LE: + m_conv = new wxMBConvUTF32LE; + m_ownsConv = true; + break; + + case BOM_UTF16BE: + m_conv = new wxMBConvUTF16BE; + m_ownsConv = true; + break; + + case BOM_UTF16LE: + m_conv = new wxMBConvUTF16LE; + m_ownsConv = true; + break; + + case BOM_UTF8: + m_conv = &wxConvUTF8; + m_ownsConv = false; + break; + + default: + wxFAIL_MSG( _T("unexpected BOM type") ); + // fall through: still need to create something + + case BOM_None: + InitWithDefault(); + m_consumedBOM = true; // as there is nothing to consume + } +} + +void wxConvAuto::SkipBOM(const char **src, size_t *len) const +{ + int ofs; + switch ( m_bomType ) + { + case BOM_UTF32BE: + case BOM_UTF32LE: + ofs = 4; + break; + + case BOM_UTF16BE: + case BOM_UTF16LE: + ofs = 2; + break; + + case BOM_UTF8: + ofs = 3; + break; + + default: + wxFAIL_MSG( _T("unexpected BOM type") ); + // fall through: still need to create something + + case BOM_None: + ofs = 0; + } + + *src += ofs; + if ( *len != (size_t)-1 ) + *len -= ofs; +} + +void wxConvAuto::InitFromInput(const char **src, size_t *len) +{ + m_bomType = DetectBOM(*src, *len); + InitFromBOM(m_bomType); + SkipBOM(src, len); +} + +size_t +wxConvAuto::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + // we check BOM and create the appropriate conversion the first time we're + // called but we also need to ensure that the BOM is skipped not only + // during this initial call but also during the first call with non-NULL + // dst as typically we're first called with NULL dst to calculate the + // needed buffer size + wxConvAuto *self = wx_const_cast(wxConvAuto *, this); + if ( !m_conv ) + { + self->InitFromInput(&src, &srcLen); + if ( dst ) + self->m_consumedBOM = true; + } + + if ( !m_consumedBOM && dst ) + { + self->m_consumedBOM = true; + SkipBOM(&src, &srcLen); + } + + return m_conv->ToWChar(dst, dstLen, src, srcLen); +} + +size_t +wxConvAuto::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( !m_conv ) + { + // default to UTF-8 for the multibyte output + wx_const_cast(wxConvAuto *, this)->InitWithDefault(); + } + + return m_conv->FromWChar(dst, dstLen, src, srcLen); +} + +#endif // wxUSE_WCHAR_T + diff --git a/Source/3rd Party/wx/src/common/cshelp.cpp b/Source/3rd Party/wx/src/common/cshelp.cpp index 181fd53b3..6bd3d5cc0 100644 --- a/Source/3rd Party/wx/src/common/cshelp.cpp +++ b/Source/3rd Party/wx/src/common/cshelp.cpp @@ -1,512 +1,512 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/cshelp.cpp -// Purpose: Context sensitive help class implementation -// Author: Julian Smart, Vadim Zeitlin -// Modified by: -// Created: 08/09/2000 -// RCS-ID: $Id: cshelp.cpp 52329 2008-03-05 13:20:26Z VZ $ -// Copyright: (c) 2000 Julian Smart, Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_HELP - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/module.h" -#endif - -#include "wx/tipwin.h" -#include "wx/cshelp.h" - -#if wxUSE_MS_HTML_HELP - #include "wx/msw/helpchm.h" // for ShowContextHelpPopup - #include "wx/utils.h" // for wxGetMousePosition() -#endif - -// ---------------------------------------------------------------------------- -// wxContextHelpEvtHandler private class -// ---------------------------------------------------------------------------- - -// This class exists in order to eat events until the left mouse button is -// pressed -class wxContextHelpEvtHandler: public wxEvtHandler -{ -public: - wxContextHelpEvtHandler(wxContextHelp* contextHelp) - { - m_contextHelp = contextHelp; - } - - virtual bool ProcessEvent(wxEvent& event); - -//// Data - wxContextHelp* m_contextHelp; - - DECLARE_NO_COPY_CLASS(wxContextHelpEvtHandler) -}; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxContextHelp -// ---------------------------------------------------------------------------- - -/* - * Invokes context-sensitive help - */ - - -IMPLEMENT_DYNAMIC_CLASS(wxContextHelp, wxObject) - -wxContextHelp::wxContextHelp(wxWindow* win, bool beginHelp) -{ - m_inHelp = false; - - if (beginHelp) - BeginContextHelp(win); -} - -wxContextHelp::~wxContextHelp() -{ - if (m_inHelp) - EndContextHelp(); -} - -// Not currently needed, but on some systems capture may not work as -// expected so we'll leave it here for now. -#ifdef __WXMOTIF__ -static void wxPushOrPopEventHandlers(wxContextHelp* help, wxWindow* win, bool push) -{ - if (push) - win->PushEventHandler(new wxContextHelpEvtHandler(help)); - else - win->PopEventHandler(true); - - wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); - while (node) - { - wxWindow* child = node->GetData(); - wxPushOrPopEventHandlers(help, child, push); - - node = node->GetNext(); - } -} -#endif - -// Begin 'context help mode' -bool wxContextHelp::BeginContextHelp(wxWindow* win) -{ - if (!win) - win = wxTheApp->GetTopWindow(); - if (!win) - return false; - - wxCursor cursor(wxCURSOR_QUESTION_ARROW); - wxCursor oldCursor = win->GetCursor(); - win->SetCursor(cursor); - -#ifdef __WXMAC__ - wxSetCursor(cursor); -#endif - - m_status = false; - -#ifdef __WXMOTIF__ - wxPushOrPopEventHandlers(this, win, true); -#else - win->PushEventHandler(new wxContextHelpEvtHandler(this)); -#endif - - win->CaptureMouse(); - - EventLoop(); - - win->ReleaseMouse(); - -#ifdef __WXMOTIF__ - wxPushOrPopEventHandlers(this, win, false); -#else - win->PopEventHandler(true); -#endif - - win->SetCursor(oldCursor); - -#ifdef __WXMAC__ - wxSetCursor(wxNullCursor); -#endif - - if (m_status) - { - wxPoint pt; - wxWindow* winAtPtr = wxFindWindowAtPointer(pt); - -#if 0 - if (winAtPtr) - { - printf("Picked %s (%d)\n", winAtPtr->GetName().c_str(), - winAtPtr->GetId()); - } -#endif - - if (winAtPtr) - DispatchEvent(winAtPtr, pt); - } - - return true; -} - -bool wxContextHelp::EndContextHelp() -{ - m_inHelp = false; - - return true; -} - -bool wxContextHelp::EventLoop() -{ - m_inHelp = true; - - while ( m_inHelp ) - { - if (wxTheApp->Pending()) - { - wxTheApp->Dispatch(); - } - else - { - wxTheApp->ProcessIdle(); - } - } - - return true; -} - -bool wxContextHelpEvtHandler::ProcessEvent(wxEvent& event) -{ - if (event.GetEventType() == wxEVT_LEFT_DOWN) - { - m_contextHelp->SetStatus(true); - m_contextHelp->EndContextHelp(); - return true; - } - - if ((event.GetEventType() == wxEVT_CHAR) || - (event.GetEventType() == wxEVT_KEY_DOWN) || - (event.GetEventType() == wxEVT_ACTIVATE) || - (event.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED)) - { - // May have already been set to true by a left-click - //m_contextHelp->SetStatus(false); - m_contextHelp->EndContextHelp(); - return true; - } - - if ((event.GetEventType() == wxEVT_PAINT) || - (event.GetEventType() == wxEVT_ERASE_BACKGROUND)) - { - event.Skip(); - return false; - } - - return true; -} - -// Dispatch the help event to the relevant window -bool wxContextHelp::DispatchEvent(wxWindow* win, const wxPoint& pt) -{ - wxCHECK_MSG( win, false, _T("win parameter can't be NULL") ); - - wxHelpEvent helpEvent(wxEVT_HELP, win->GetId(), pt, - wxHelpEvent::Origin_HelpButton); - helpEvent.SetEventObject(win); - - return win->GetEventHandler()->ProcessEvent(helpEvent); -} - -// ---------------------------------------------------------------------------- -// wxContextHelpButton -// ---------------------------------------------------------------------------- - -/* - * wxContextHelpButton - * You can add this to your dialogs (especially on non-Windows platforms) - * to put the application into context help mode. - */ - -#ifndef __WXPM__ - -static const char * csquery_xpm[] = { -"12 11 2 1", -" c None", -". c #000000", -" ", -" .... ", -" .. .. ", -" .. .. ", -" .. ", -" .. ", -" .. ", -" ", -" .. ", -" .. ", -" "}; - -#endif - -IMPLEMENT_CLASS(wxContextHelpButton, wxBitmapButton) - -BEGIN_EVENT_TABLE(wxContextHelpButton, wxBitmapButton) - EVT_BUTTON(wxID_CONTEXT_HELP, wxContextHelpButton::OnContextHelp) -END_EVENT_TABLE() - -wxContextHelpButton::wxContextHelpButton(wxWindow* parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style) -#if defined(__WXPM__) - : wxBitmapButton(parent, id, wxBitmap(wxCSQUERY_BITMAP - ,wxBITMAP_TYPE_RESOURCE - ), - pos, size, style) -#else - : wxBitmapButton(parent, id, wxBitmap(csquery_xpm), - pos, size, style) -#endif -{ -} - -void wxContextHelpButton::OnContextHelp(wxCommandEvent& WXUNUSED(event)) -{ - wxContextHelp contextHelp(GetParent()); -} - -// ---------------------------------------------------------------------------- -// wxHelpProvider -// ---------------------------------------------------------------------------- - -wxHelpProvider *wxHelpProvider::ms_helpProvider = (wxHelpProvider *)NULL; - -// trivial implementation of some methods which we don't want to make pure -// virtual for convenience - -void wxHelpProvider::AddHelp(wxWindowBase * WXUNUSED(window), - const wxString& WXUNUSED(text)) -{ -} - -void wxHelpProvider::AddHelp(wxWindowID WXUNUSED(id), - const wxString& WXUNUSED(text)) -{ -} - -// removes the association -void wxHelpProvider::RemoveHelp(wxWindowBase* WXUNUSED(window)) -{ -} - -wxHelpProvider::~wxHelpProvider() -{ -} - -wxString wxHelpProvider::GetHelpTextMaybeAtPoint(wxWindowBase *window) -{ - if ( m_helptextAtPoint != wxDefaultPosition || - m_helptextOrigin != wxHelpEvent::Origin_Unknown ) - { - wxCHECK_MSG( window, wxEmptyString, _T("window must not be NULL") ); - - wxPoint pt = m_helptextAtPoint; - wxHelpEvent::Origin origin = m_helptextOrigin; - - m_helptextAtPoint = wxDefaultPosition; - m_helptextOrigin = wxHelpEvent::Origin_Unknown; - - return window->GetHelpTextAtPoint(pt, origin); - } - - return GetHelp(window); -} - -// ---------------------------------------------------------------------------- -// wxSimpleHelpProvider -// ---------------------------------------------------------------------------- - -#define WINHASH_KEY(w) wxPtrToUInt(w) - -wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window) -{ - wxSimpleHelpProviderHashMap::iterator it = m_hashWindows.find(WINHASH_KEY(window)); - - if ( it == m_hashWindows.end() ) - { - it = m_hashIds.find(window->GetId()); - if ( it == m_hashIds.end() ) - return wxEmptyString; - } - - return it->second; -} - -void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text) -{ - m_hashWindows.erase(WINHASH_KEY(window)); - m_hashWindows[WINHASH_KEY(window)] = text; -} - -void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text) -{ - wxSimpleHelpProviderHashMap::key_type key = (wxSimpleHelpProviderHashMap::key_type)id; - m_hashIds.erase(key); - m_hashIds[key] = text; -} - -// removes the association -void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window) -{ - m_hashWindows.erase(WINHASH_KEY(window)); -} - -bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window) -{ -#if wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW -#if wxUSE_MS_HTML_HELP - // m_helptextAtPoint will be reset by GetHelpTextMaybeAtPoint(), stash it - const wxPoint posTooltip = m_helptextAtPoint; -#endif // wxUSE_MS_HTML_HELP - - const wxString text = GetHelpTextMaybeAtPoint(window); - - if ( !text.empty() ) - { - // use the native help popup style if it's available -#if wxUSE_MS_HTML_HELP - if ( !wxCHMHelpController::ShowContextHelpPopup - ( - text, - posTooltip, - (wxWindow *)window - ) ) -#endif // wxUSE_MS_HTML_HELP - { -#if wxUSE_TIPWINDOW - static wxTipWindow* s_tipWindow = NULL; - - if ( s_tipWindow ) - { - // Prevent s_tipWindow being nulled in OnIdle, thereby removing - // the chance for the window to be closed by ShowHelp - s_tipWindow->SetTipWindowPtr(NULL); - s_tipWindow->Close(); - } - - s_tipWindow = new wxTipWindow((wxWindow *)window, text, - 100, &s_tipWindow); -#else // !wxUSE_TIPWINDOW - // we tried wxCHMHelpController but it failed and we don't have - // wxTipWindow to fall back on, so - return false; -#endif // wxUSE_TIPWINDOW - } - - return true; - } -#else // !wxUSE_MS_HTML_HELP && !wxUSE_TIPWINDOW - wxUnusedVar(window); -#endif // wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW - - return false; -} - -// ---------------------------------------------------------------------------- -// wxHelpControllerHelpProvider -// ---------------------------------------------------------------------------- - -wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc) -{ - m_helpController = hc; -} - -bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window) -{ - const wxString text = GetHelpTextMaybeAtPoint(window); - - if ( text.empty() ) - return false; - - if ( m_helpController ) - { - // if it's a numeric topic, show it - long topic; - if ( text.ToLong(&topic) ) - return m_helpController->DisplayContextPopup(topic); - - // otherwise show the text directly - if ( m_helpController->DisplayTextPopup(text, wxGetMousePosition()) ) - return true; - } - - // if there is no help controller or it's not capable of showing the help, - // fallback to the default method - return wxSimpleHelpProvider::ShowHelp(window); -} - -// Convenience function for turning context id into wxString -wxString wxContextId(int id) -{ - return wxString::Format(_T("%d"), id); -} - -// ---------------------------------------------------------------------------- -// wxHelpProviderModule: module responsible for cleaning up help provider. -// ---------------------------------------------------------------------------- - -class wxHelpProviderModule : public wxModule -{ -public: - bool OnInit(); - void OnExit(); - -private: - DECLARE_DYNAMIC_CLASS(wxHelpProviderModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule) - -bool wxHelpProviderModule::OnInit() -{ - // Probably we don't want to do anything by default, - // since it could pull in extra code - // wxHelpProvider::Set(new wxSimpleHelpProvider); - - return true; -} - -void wxHelpProviderModule::OnExit() -{ - if (wxHelpProvider::Get()) - { - delete wxHelpProvider::Get(); - wxHelpProvider::Set(NULL); - } -} - -#endif // wxUSE_HELP +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/cshelp.cpp +// Purpose: Context sensitive help class implementation +// Author: Julian Smart, Vadim Zeitlin +// Modified by: +// Created: 08/09/2000 +// RCS-ID: $Id: cshelp.cpp 52329 2008-03-05 13:20:26Z VZ $ +// Copyright: (c) 2000 Julian Smart, Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_HELP + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/module.h" +#endif + +#include "wx/tipwin.h" +#include "wx/cshelp.h" + +#if wxUSE_MS_HTML_HELP + #include "wx/msw/helpchm.h" // for ShowContextHelpPopup + #include "wx/utils.h" // for wxGetMousePosition() +#endif + +// ---------------------------------------------------------------------------- +// wxContextHelpEvtHandler private class +// ---------------------------------------------------------------------------- + +// This class exists in order to eat events until the left mouse button is +// pressed +class wxContextHelpEvtHandler: public wxEvtHandler +{ +public: + wxContextHelpEvtHandler(wxContextHelp* contextHelp) + { + m_contextHelp = contextHelp; + } + + virtual bool ProcessEvent(wxEvent& event); + +//// Data + wxContextHelp* m_contextHelp; + + DECLARE_NO_COPY_CLASS(wxContextHelpEvtHandler) +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxContextHelp +// ---------------------------------------------------------------------------- + +/* + * Invokes context-sensitive help + */ + + +IMPLEMENT_DYNAMIC_CLASS(wxContextHelp, wxObject) + +wxContextHelp::wxContextHelp(wxWindow* win, bool beginHelp) +{ + m_inHelp = false; + + if (beginHelp) + BeginContextHelp(win); +} + +wxContextHelp::~wxContextHelp() +{ + if (m_inHelp) + EndContextHelp(); +} + +// Not currently needed, but on some systems capture may not work as +// expected so we'll leave it here for now. +#ifdef __WXMOTIF__ +static void wxPushOrPopEventHandlers(wxContextHelp* help, wxWindow* win, bool push) +{ + if (push) + win->PushEventHandler(new wxContextHelpEvtHandler(help)); + else + win->PopEventHandler(true); + + wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); + while (node) + { + wxWindow* child = node->GetData(); + wxPushOrPopEventHandlers(help, child, push); + + node = node->GetNext(); + } +} +#endif + +// Begin 'context help mode' +bool wxContextHelp::BeginContextHelp(wxWindow* win) +{ + if (!win) + win = wxTheApp->GetTopWindow(); + if (!win) + return false; + + wxCursor cursor(wxCURSOR_QUESTION_ARROW); + wxCursor oldCursor = win->GetCursor(); + win->SetCursor(cursor); + +#ifdef __WXMAC__ + wxSetCursor(cursor); +#endif + + m_status = false; + +#ifdef __WXMOTIF__ + wxPushOrPopEventHandlers(this, win, true); +#else + win->PushEventHandler(new wxContextHelpEvtHandler(this)); +#endif + + win->CaptureMouse(); + + EventLoop(); + + win->ReleaseMouse(); + +#ifdef __WXMOTIF__ + wxPushOrPopEventHandlers(this, win, false); +#else + win->PopEventHandler(true); +#endif + + win->SetCursor(oldCursor); + +#ifdef __WXMAC__ + wxSetCursor(wxNullCursor); +#endif + + if (m_status) + { + wxPoint pt; + wxWindow* winAtPtr = wxFindWindowAtPointer(pt); + +#if 0 + if (winAtPtr) + { + printf("Picked %s (%d)\n", winAtPtr->GetName().c_str(), + winAtPtr->GetId()); + } +#endif + + if (winAtPtr) + DispatchEvent(winAtPtr, pt); + } + + return true; +} + +bool wxContextHelp::EndContextHelp() +{ + m_inHelp = false; + + return true; +} + +bool wxContextHelp::EventLoop() +{ + m_inHelp = true; + + while ( m_inHelp ) + { + if (wxTheApp->Pending()) + { + wxTheApp->Dispatch(); + } + else + { + wxTheApp->ProcessIdle(); + } + } + + return true; +} + +bool wxContextHelpEvtHandler::ProcessEvent(wxEvent& event) +{ + if (event.GetEventType() == wxEVT_LEFT_DOWN) + { + m_contextHelp->SetStatus(true); + m_contextHelp->EndContextHelp(); + return true; + } + + if ((event.GetEventType() == wxEVT_CHAR) || + (event.GetEventType() == wxEVT_KEY_DOWN) || + (event.GetEventType() == wxEVT_ACTIVATE) || + (event.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED)) + { + // May have already been set to true by a left-click + //m_contextHelp->SetStatus(false); + m_contextHelp->EndContextHelp(); + return true; + } + + if ((event.GetEventType() == wxEVT_PAINT) || + (event.GetEventType() == wxEVT_ERASE_BACKGROUND)) + { + event.Skip(); + return false; + } + + return true; +} + +// Dispatch the help event to the relevant window +bool wxContextHelp::DispatchEvent(wxWindow* win, const wxPoint& pt) +{ + wxCHECK_MSG( win, false, _T("win parameter can't be NULL") ); + + wxHelpEvent helpEvent(wxEVT_HELP, win->GetId(), pt, + wxHelpEvent::Origin_HelpButton); + helpEvent.SetEventObject(win); + + return win->GetEventHandler()->ProcessEvent(helpEvent); +} + +// ---------------------------------------------------------------------------- +// wxContextHelpButton +// ---------------------------------------------------------------------------- + +/* + * wxContextHelpButton + * You can add this to your dialogs (especially on non-Windows platforms) + * to put the application into context help mode. + */ + +#ifndef __WXPM__ + +static const char * csquery_xpm[] = { +"12 11 2 1", +" c None", +". c #000000", +" ", +" .... ", +" .. .. ", +" .. .. ", +" .. ", +" .. ", +" .. ", +" ", +" .. ", +" .. ", +" "}; + +#endif + +IMPLEMENT_CLASS(wxContextHelpButton, wxBitmapButton) + +BEGIN_EVENT_TABLE(wxContextHelpButton, wxBitmapButton) + EVT_BUTTON(wxID_CONTEXT_HELP, wxContextHelpButton::OnContextHelp) +END_EVENT_TABLE() + +wxContextHelpButton::wxContextHelpButton(wxWindow* parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style) +#if defined(__WXPM__) + : wxBitmapButton(parent, id, wxBitmap(wxCSQUERY_BITMAP + ,wxBITMAP_TYPE_RESOURCE + ), + pos, size, style) +#else + : wxBitmapButton(parent, id, wxBitmap(csquery_xpm), + pos, size, style) +#endif +{ +} + +void wxContextHelpButton::OnContextHelp(wxCommandEvent& WXUNUSED(event)) +{ + wxContextHelp contextHelp(GetParent()); +} + +// ---------------------------------------------------------------------------- +// wxHelpProvider +// ---------------------------------------------------------------------------- + +wxHelpProvider *wxHelpProvider::ms_helpProvider = (wxHelpProvider *)NULL; + +// trivial implementation of some methods which we don't want to make pure +// virtual for convenience + +void wxHelpProvider::AddHelp(wxWindowBase * WXUNUSED(window), + const wxString& WXUNUSED(text)) +{ +} + +void wxHelpProvider::AddHelp(wxWindowID WXUNUSED(id), + const wxString& WXUNUSED(text)) +{ +} + +// removes the association +void wxHelpProvider::RemoveHelp(wxWindowBase* WXUNUSED(window)) +{ +} + +wxHelpProvider::~wxHelpProvider() +{ +} + +wxString wxHelpProvider::GetHelpTextMaybeAtPoint(wxWindowBase *window) +{ + if ( m_helptextAtPoint != wxDefaultPosition || + m_helptextOrigin != wxHelpEvent::Origin_Unknown ) + { + wxCHECK_MSG( window, wxEmptyString, _T("window must not be NULL") ); + + wxPoint pt = m_helptextAtPoint; + wxHelpEvent::Origin origin = m_helptextOrigin; + + m_helptextAtPoint = wxDefaultPosition; + m_helptextOrigin = wxHelpEvent::Origin_Unknown; + + return window->GetHelpTextAtPoint(pt, origin); + } + + return GetHelp(window); +} + +// ---------------------------------------------------------------------------- +// wxSimpleHelpProvider +// ---------------------------------------------------------------------------- + +#define WINHASH_KEY(w) wxPtrToUInt(w) + +wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window) +{ + wxSimpleHelpProviderHashMap::iterator it = m_hashWindows.find(WINHASH_KEY(window)); + + if ( it == m_hashWindows.end() ) + { + it = m_hashIds.find(window->GetId()); + if ( it == m_hashIds.end() ) + return wxEmptyString; + } + + return it->second; +} + +void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text) +{ + m_hashWindows.erase(WINHASH_KEY(window)); + m_hashWindows[WINHASH_KEY(window)] = text; +} + +void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text) +{ + wxSimpleHelpProviderHashMap::key_type key = (wxSimpleHelpProviderHashMap::key_type)id; + m_hashIds.erase(key); + m_hashIds[key] = text; +} + +// removes the association +void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window) +{ + m_hashWindows.erase(WINHASH_KEY(window)); +} + +bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window) +{ +#if wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW +#if wxUSE_MS_HTML_HELP + // m_helptextAtPoint will be reset by GetHelpTextMaybeAtPoint(), stash it + const wxPoint posTooltip = m_helptextAtPoint; +#endif // wxUSE_MS_HTML_HELP + + const wxString text = GetHelpTextMaybeAtPoint(window); + + if ( !text.empty() ) + { + // use the native help popup style if it's available +#if wxUSE_MS_HTML_HELP + if ( !wxCHMHelpController::ShowContextHelpPopup + ( + text, + posTooltip, + (wxWindow *)window + ) ) +#endif // wxUSE_MS_HTML_HELP + { +#if wxUSE_TIPWINDOW + static wxTipWindow* s_tipWindow = NULL; + + if ( s_tipWindow ) + { + // Prevent s_tipWindow being nulled in OnIdle, thereby removing + // the chance for the window to be closed by ShowHelp + s_tipWindow->SetTipWindowPtr(NULL); + s_tipWindow->Close(); + } + + s_tipWindow = new wxTipWindow((wxWindow *)window, text, + 100, &s_tipWindow); +#else // !wxUSE_TIPWINDOW + // we tried wxCHMHelpController but it failed and we don't have + // wxTipWindow to fall back on, so + return false; +#endif // wxUSE_TIPWINDOW + } + + return true; + } +#else // !wxUSE_MS_HTML_HELP && !wxUSE_TIPWINDOW + wxUnusedVar(window); +#endif // wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW + + return false; +} + +// ---------------------------------------------------------------------------- +// wxHelpControllerHelpProvider +// ---------------------------------------------------------------------------- + +wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc) +{ + m_helpController = hc; +} + +bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window) +{ + const wxString text = GetHelpTextMaybeAtPoint(window); + + if ( text.empty() ) + return false; + + if ( m_helpController ) + { + // if it's a numeric topic, show it + long topic; + if ( text.ToLong(&topic) ) + return m_helpController->DisplayContextPopup(topic); + + // otherwise show the text directly + if ( m_helpController->DisplayTextPopup(text, wxGetMousePosition()) ) + return true; + } + + // if there is no help controller or it's not capable of showing the help, + // fallback to the default method + return wxSimpleHelpProvider::ShowHelp(window); +} + +// Convenience function for turning context id into wxString +wxString wxContextId(int id) +{ + return wxString::Format(_T("%d"), id); +} + +// ---------------------------------------------------------------------------- +// wxHelpProviderModule: module responsible for cleaning up help provider. +// ---------------------------------------------------------------------------- + +class wxHelpProviderModule : public wxModule +{ +public: + bool OnInit(); + void OnExit(); + +private: + DECLARE_DYNAMIC_CLASS(wxHelpProviderModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule) + +bool wxHelpProviderModule::OnInit() +{ + // Probably we don't want to do anything by default, + // since it could pull in extra code + // wxHelpProvider::Set(new wxSimpleHelpProvider); + + return true; +} + +void wxHelpProviderModule::OnExit() +{ + if (wxHelpProvider::Get()) + { + delete wxHelpProvider::Get(); + wxHelpProvider::Set(NULL); + } +} + +#endif // wxUSE_HELP diff --git a/Source/3rd Party/wx/src/common/ctrlcmn.cpp b/Source/3rd Party/wx/src/common/ctrlcmn.cpp index a10e48160..9326835e9 100644 --- a/Source/3rd Party/wx/src/common/ctrlcmn.cpp +++ b/Source/3rd Party/wx/src/common/ctrlcmn.cpp @@ -1,188 +1,188 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/ctrlcmn.cpp -// Purpose: wxControl common interface -// Author: Vadim Zeitlin -// Modified by: -// Created: 26.07.99 -// RCS-ID: $Id: ctrlcmn.cpp 40329 2006-07-25 18:40:04Z VZ $ -// Copyright: (c) 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_CONTROLS - -#include "wx/control.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/radiobut.h" - #include "wx/statbmp.h" - #include "wx/bitmap.h" - #include "wx/utils.h" // for wxStripMenuCodes() -#endif - -const wxChar wxControlNameStr[] = wxT("control"); - -// ============================================================================ -// implementation -// ============================================================================ - -wxControlBase::~wxControlBase() -{ - // this destructor is required for Darwin -} - -bool wxControlBase::Create(wxWindow *parent, - wxWindowID id, - const wxPoint &pos, - const wxSize &size, - long style, - const wxValidator& wxVALIDATOR_PARAM(validator), - const wxString &name) -{ - bool ret = wxWindow::Create(parent, id, pos, size, style, name); - -#if wxUSE_VALIDATORS - if ( ret ) - SetValidator(validator); -#endif // wxUSE_VALIDATORS - - return ret; -} - -bool wxControlBase::CreateControl(wxWindowBase *parent, - wxWindowID id, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name) -{ - // even if it's possible to create controls without parents in some port, - // it should surely be discouraged because it doesn't work at all under - // Windows - wxCHECK_MSG( parent, false, wxT("all controls must have parents") ); - - if ( !CreateBase(parent, id, pos, size, style, validator, name) ) - return false; - - parent->AddChild(this); - - return true; -} - -/* static */ -wxString wxControlBase::GetLabelText(const wxString& label) -{ - // we don't want strip the TABs here, just the mnemonics - return wxStripMenuCodes(label, wxStrip_Mnemonics); -} - -void wxControlBase::Command(wxCommandEvent& event) -{ - (void)GetEventHandler()->ProcessEvent(event); -} - -void wxControlBase::InitCommandEvent(wxCommandEvent& event) const -{ - event.SetEventObject((wxControlBase *)this); // const_cast - - // event.SetId(GetId()); -- this is usuall done in the event ctor - - switch ( m_clientDataType ) - { - case wxClientData_Void: - event.SetClientData(GetClientData()); - break; - - case wxClientData_Object: - event.SetClientObject(GetClientObject()); - break; - - case wxClientData_None: - // nothing to do - ; - } -} - - -void wxControlBase::SetLabel( const wxString &label ) -{ - InvalidateBestSize(); - wxWindow::SetLabel(label); -} - -bool wxControlBase::SetFont(const wxFont& font) -{ - InvalidateBestSize(); - return wxWindow::SetFont(font); -} - -// wxControl-specific processing after processing the update event -void wxControlBase::DoUpdateWindowUI(wxUpdateUIEvent& event) -{ - // call inherited - wxWindowBase::DoUpdateWindowUI(event); - - // update label - if ( event.GetSetText() ) - { - if ( event.GetText() != GetLabel() ) - SetLabel(event.GetText()); - } - - // Unfortunately we don't yet have common base class for - // wxRadioButton, so we handle updates of radiobuttons here. - // TODO: If once wxRadioButtonBase will exist, move this code there. -#if wxUSE_RADIOBTN - if ( event.GetSetChecked() ) - { - wxRadioButton *radiobtn = wxDynamicCastThis(wxRadioButton); - if ( radiobtn ) - radiobtn->SetValue(event.GetChecked()); - } -#endif // wxUSE_RADIOBTN -} - -// ---------------------------------------------------------------------------- -// wxStaticBitmap -// ---------------------------------------------------------------------------- - -#if wxUSE_STATBMP - -wxStaticBitmapBase::~wxStaticBitmapBase() -{ - // this destructor is required for Darwin -} - -wxSize wxStaticBitmapBase::DoGetBestSize() const -{ - wxSize best; - wxBitmap bmp = GetBitmap(); - if ( bmp.Ok() ) - best = wxSize(bmp.GetWidth(), bmp.GetHeight()); - else - // this is completely arbitrary - best = wxSize(16, 16); - CacheBestSize(best); - return best; -} - -#endif // wxUSE_STATBMP - -#endif // wxUSE_CONTROLS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/ctrlcmn.cpp +// Purpose: wxControl common interface +// Author: Vadim Zeitlin +// Modified by: +// Created: 26.07.99 +// RCS-ID: $Id: ctrlcmn.cpp 40329 2006-07-25 18:40:04Z VZ $ +// Copyright: (c) 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_CONTROLS + +#include "wx/control.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/radiobut.h" + #include "wx/statbmp.h" + #include "wx/bitmap.h" + #include "wx/utils.h" // for wxStripMenuCodes() +#endif + +const wxChar wxControlNameStr[] = wxT("control"); + +// ============================================================================ +// implementation +// ============================================================================ + +wxControlBase::~wxControlBase() +{ + // this destructor is required for Darwin +} + +bool wxControlBase::Create(wxWindow *parent, + wxWindowID id, + const wxPoint &pos, + const wxSize &size, + long style, + const wxValidator& wxVALIDATOR_PARAM(validator), + const wxString &name) +{ + bool ret = wxWindow::Create(parent, id, pos, size, style, name); + +#if wxUSE_VALIDATORS + if ( ret ) + SetValidator(validator); +#endif // wxUSE_VALIDATORS + + return ret; +} + +bool wxControlBase::CreateControl(wxWindowBase *parent, + wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + // even if it's possible to create controls without parents in some port, + // it should surely be discouraged because it doesn't work at all under + // Windows + wxCHECK_MSG( parent, false, wxT("all controls must have parents") ); + + if ( !CreateBase(parent, id, pos, size, style, validator, name) ) + return false; + + parent->AddChild(this); + + return true; +} + +/* static */ +wxString wxControlBase::GetLabelText(const wxString& label) +{ + // we don't want strip the TABs here, just the mnemonics + return wxStripMenuCodes(label, wxStrip_Mnemonics); +} + +void wxControlBase::Command(wxCommandEvent& event) +{ + (void)GetEventHandler()->ProcessEvent(event); +} + +void wxControlBase::InitCommandEvent(wxCommandEvent& event) const +{ + event.SetEventObject((wxControlBase *)this); // const_cast + + // event.SetId(GetId()); -- this is usuall done in the event ctor + + switch ( m_clientDataType ) + { + case wxClientData_Void: + event.SetClientData(GetClientData()); + break; + + case wxClientData_Object: + event.SetClientObject(GetClientObject()); + break; + + case wxClientData_None: + // nothing to do + ; + } +} + + +void wxControlBase::SetLabel( const wxString &label ) +{ + InvalidateBestSize(); + wxWindow::SetLabel(label); +} + +bool wxControlBase::SetFont(const wxFont& font) +{ + InvalidateBestSize(); + return wxWindow::SetFont(font); +} + +// wxControl-specific processing after processing the update event +void wxControlBase::DoUpdateWindowUI(wxUpdateUIEvent& event) +{ + // call inherited + wxWindowBase::DoUpdateWindowUI(event); + + // update label + if ( event.GetSetText() ) + { + if ( event.GetText() != GetLabel() ) + SetLabel(event.GetText()); + } + + // Unfortunately we don't yet have common base class for + // wxRadioButton, so we handle updates of radiobuttons here. + // TODO: If once wxRadioButtonBase will exist, move this code there. +#if wxUSE_RADIOBTN + if ( event.GetSetChecked() ) + { + wxRadioButton *radiobtn = wxDynamicCastThis(wxRadioButton); + if ( radiobtn ) + radiobtn->SetValue(event.GetChecked()); + } +#endif // wxUSE_RADIOBTN +} + +// ---------------------------------------------------------------------------- +// wxStaticBitmap +// ---------------------------------------------------------------------------- + +#if wxUSE_STATBMP + +wxStaticBitmapBase::~wxStaticBitmapBase() +{ + // this destructor is required for Darwin +} + +wxSize wxStaticBitmapBase::DoGetBestSize() const +{ + wxSize best; + wxBitmap bmp = GetBitmap(); + if ( bmp.Ok() ) + best = wxSize(bmp.GetWidth(), bmp.GetHeight()); + else + // this is completely arbitrary + best = wxSize(16, 16); + CacheBestSize(best); + return best; +} + +#endif // wxUSE_STATBMP + +#endif // wxUSE_CONTROLS diff --git a/Source/3rd Party/wx/src/common/ctrlsub.cpp b/Source/3rd Party/wx/src/common/ctrlsub.cpp index 4a036d39b..387b174cc 100644 --- a/Source/3rd Party/wx/src/common/ctrlsub.cpp +++ b/Source/3rd Party/wx/src/common/ctrlsub.cpp @@ -1,197 +1,197 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/ctrlsub.cpp -// Purpose: wxItemContainer implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 22.10.99 -// RCS-ID: $Id: ctrlsub.cpp 39077 2006-05-06 19:05:50Z VZ $ -// Copyright: (c) 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_CONTROLS - -#ifndef WX_PRECOMP - #include "wx/ctrlsub.h" - #include "wx/arrstr.h" -#endif - -IMPLEMENT_ABSTRACT_CLASS(wxControlWithItems, wxControl) - -// ============================================================================ -// wxItemContainerImmutable implementation -// ============================================================================ - -wxItemContainerImmutable::~wxItemContainerImmutable() -{ - // this destructor is required for Darwin -} - -// ---------------------------------------------------------------------------- -// selection -// ---------------------------------------------------------------------------- - -wxString wxItemContainerImmutable::GetStringSelection() const -{ - wxString s; - - int sel = GetSelection(); - if ( sel != wxNOT_FOUND ) - s = GetString((unsigned int)sel); - - return s; -} - -bool wxItemContainerImmutable::SetStringSelection(const wxString& s) -{ - const int sel = FindString(s); - if ( sel == wxNOT_FOUND ) - return false; - - SetSelection(sel); - - return true; -} - -wxArrayString wxItemContainerImmutable::GetStrings() const -{ - wxArrayString result; - - const unsigned int count = GetCount(); - result.Alloc(count); - for ( unsigned int n = 0; n < count; n++ ) - result.Add(GetString(n)); - - return result; -} - -// ============================================================================ -// wxItemContainer implementation -// ============================================================================ - -wxItemContainer::~wxItemContainer() -{ - // this destructor is required for Darwin -} - -// ---------------------------------------------------------------------------- -// appending items -// ---------------------------------------------------------------------------- - -void wxItemContainer::Append(const wxArrayString& strings) -{ - const size_t count = strings.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - Append(strings[n]); - } -} - -int wxItemContainer::Insert(const wxString& item, unsigned int pos, void *clientData) -{ - int n = DoInsert(item, pos); - if ( n != wxNOT_FOUND ) - SetClientData(n, clientData); - - return n; -} - -int wxItemContainer::Insert(const wxString& item, unsigned int pos, wxClientData *clientData) -{ - int n = DoInsert(item, pos); - if ( n != wxNOT_FOUND ) - SetClientObject(n, clientData); - - return n; -} - -// ---------------------------------------------------------------------------- -// client data -// ---------------------------------------------------------------------------- - -void wxItemContainer::SetClientObject(unsigned int n, wxClientData *data) -{ - wxASSERT_MSG( m_clientDataItemsType != wxClientData_Void, - wxT("can't have both object and void client data") ); - - // when we call SetClientObject() for the first time, m_clientDataItemsType - // is still wxClientData_None and so calling DoGetItemClientObject() would - // fail (in addition to being useless) - don't do it - if ( m_clientDataItemsType == wxClientData_Object ) - { - wxClientData *clientDataOld = DoGetItemClientObject(n); - if ( clientDataOld ) - delete clientDataOld; - } - else // m_clientDataItemsType == wxClientData_None - { - // now we have object client data - m_clientDataItemsType = wxClientData_Object; - } - - DoSetItemClientObject(n, data); -} - -wxClientData *wxItemContainer::GetClientObject(unsigned int n) const -{ - wxASSERT_MSG( m_clientDataItemsType == wxClientData_Object, - wxT("this window doesn't have object client data") ); - - return DoGetItemClientObject(n); -} - -void wxItemContainer::SetClientData(unsigned int n, void *data) -{ - wxASSERT_MSG( m_clientDataItemsType != wxClientData_Object, - wxT("can't have both object and void client data") ); - - DoSetItemClientData(n, data); - m_clientDataItemsType = wxClientData_Void; -} - -void *wxItemContainer::GetClientData(unsigned int n) const -{ - wxASSERT_MSG( m_clientDataItemsType == wxClientData_Void, - wxT("this window doesn't have void client data") ); - - return DoGetItemClientData(n); -} - -// ============================================================================ -// wxControlWithItems implementation -// ============================================================================ - -void wxControlWithItems::InitCommandEventWithItems(wxCommandEvent& event, int n) -{ - InitCommandEvent(event); - - if ( n != wxNOT_FOUND ) - { - if ( HasClientObjectData() ) - event.SetClientObject(GetClientObject(n)); - else if ( HasClientUntypedData() ) - event.SetClientData(GetClientData(n)); - } -} - -wxControlWithItems::~wxControlWithItems() -{ - // this destructor is required for Darwin -} - -#endif // wxUSE_CONTROLS +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/ctrlsub.cpp +// Purpose: wxItemContainer implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 22.10.99 +// RCS-ID: $Id: ctrlsub.cpp 39077 2006-05-06 19:05:50Z VZ $ +// Copyright: (c) 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_CONTROLS + +#ifndef WX_PRECOMP + #include "wx/ctrlsub.h" + #include "wx/arrstr.h" +#endif + +IMPLEMENT_ABSTRACT_CLASS(wxControlWithItems, wxControl) + +// ============================================================================ +// wxItemContainerImmutable implementation +// ============================================================================ + +wxItemContainerImmutable::~wxItemContainerImmutable() +{ + // this destructor is required for Darwin +} + +// ---------------------------------------------------------------------------- +// selection +// ---------------------------------------------------------------------------- + +wxString wxItemContainerImmutable::GetStringSelection() const +{ + wxString s; + + int sel = GetSelection(); + if ( sel != wxNOT_FOUND ) + s = GetString((unsigned int)sel); + + return s; +} + +bool wxItemContainerImmutable::SetStringSelection(const wxString& s) +{ + const int sel = FindString(s); + if ( sel == wxNOT_FOUND ) + return false; + + SetSelection(sel); + + return true; +} + +wxArrayString wxItemContainerImmutable::GetStrings() const +{ + wxArrayString result; + + const unsigned int count = GetCount(); + result.Alloc(count); + for ( unsigned int n = 0; n < count; n++ ) + result.Add(GetString(n)); + + return result; +} + +// ============================================================================ +// wxItemContainer implementation +// ============================================================================ + +wxItemContainer::~wxItemContainer() +{ + // this destructor is required for Darwin +} + +// ---------------------------------------------------------------------------- +// appending items +// ---------------------------------------------------------------------------- + +void wxItemContainer::Append(const wxArrayString& strings) +{ + const size_t count = strings.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + Append(strings[n]); + } +} + +int wxItemContainer::Insert(const wxString& item, unsigned int pos, void *clientData) +{ + int n = DoInsert(item, pos); + if ( n != wxNOT_FOUND ) + SetClientData(n, clientData); + + return n; +} + +int wxItemContainer::Insert(const wxString& item, unsigned int pos, wxClientData *clientData) +{ + int n = DoInsert(item, pos); + if ( n != wxNOT_FOUND ) + SetClientObject(n, clientData); + + return n; +} + +// ---------------------------------------------------------------------------- +// client data +// ---------------------------------------------------------------------------- + +void wxItemContainer::SetClientObject(unsigned int n, wxClientData *data) +{ + wxASSERT_MSG( m_clientDataItemsType != wxClientData_Void, + wxT("can't have both object and void client data") ); + + // when we call SetClientObject() for the first time, m_clientDataItemsType + // is still wxClientData_None and so calling DoGetItemClientObject() would + // fail (in addition to being useless) - don't do it + if ( m_clientDataItemsType == wxClientData_Object ) + { + wxClientData *clientDataOld = DoGetItemClientObject(n); + if ( clientDataOld ) + delete clientDataOld; + } + else // m_clientDataItemsType == wxClientData_None + { + // now we have object client data + m_clientDataItemsType = wxClientData_Object; + } + + DoSetItemClientObject(n, data); +} + +wxClientData *wxItemContainer::GetClientObject(unsigned int n) const +{ + wxASSERT_MSG( m_clientDataItemsType == wxClientData_Object, + wxT("this window doesn't have object client data") ); + + return DoGetItemClientObject(n); +} + +void wxItemContainer::SetClientData(unsigned int n, void *data) +{ + wxASSERT_MSG( m_clientDataItemsType != wxClientData_Object, + wxT("can't have both object and void client data") ); + + DoSetItemClientData(n, data); + m_clientDataItemsType = wxClientData_Void; +} + +void *wxItemContainer::GetClientData(unsigned int n) const +{ + wxASSERT_MSG( m_clientDataItemsType == wxClientData_Void, + wxT("this window doesn't have void client data") ); + + return DoGetItemClientData(n); +} + +// ============================================================================ +// wxControlWithItems implementation +// ============================================================================ + +void wxControlWithItems::InitCommandEventWithItems(wxCommandEvent& event, int n) +{ + InitCommandEvent(event); + + if ( n != wxNOT_FOUND ) + { + if ( HasClientObjectData() ) + event.SetClientObject(GetClientObject(n)); + else if ( HasClientUntypedData() ) + event.SetClientData(GetClientData(n)); + } +} + +wxControlWithItems::~wxControlWithItems() +{ + // this destructor is required for Darwin +} + +#endif // wxUSE_CONTROLS diff --git a/Source/3rd Party/wx/src/common/datacmn.cpp b/Source/3rd Party/wx/src/common/datacmn.cpp new file mode 100644 index 000000000..e82b5ead5 --- /dev/null +++ b/Source/3rd Party/wx/src/common/datacmn.cpp @@ -0,0 +1,83 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: common/datacmn.cpp +// Purpose: contains definitions of various global wxWidgets variables +// Author: Vadim Zeitlin +// Modified by: +// Created: 10.04.03 (from src/*/data.cpp files) +// RCS-ID: $Id: datacmn.cpp 43874 2006-12-09 14:52:59Z VZ $ +// Copyright: (c) 1997-2002 wxWidgets development team +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#endif // WX_PRECOMP + +#include "wx/accel.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// 'Null' objects +#if wxUSE_ACCEL +wxAcceleratorTable wxNullAcceleratorTable; +#endif // wxUSE_ACCEL + +// Default window names +extern WXDLLEXPORT_DATA(const wxChar) wxButtonNameStr[] = wxT("button"); +extern WXDLLEXPORT_DATA(const wxChar) wxCheckBoxNameStr[] = wxT("check"); +extern WXDLLEXPORT_DATA(const wxChar) wxComboBoxNameStr[] = wxT("comboBox"); +extern WXDLLEXPORT_DATA(const wxChar) wxDialogNameStr[] = wxT("dialog"); +extern WXDLLEXPORT_DATA(const wxChar) wxFrameNameStr[] = wxT("frame"); +extern WXDLLEXPORT_DATA(const wxChar) wxStaticBoxNameStr[] = wxT("groupBox"); +extern WXDLLEXPORT_DATA(const wxChar) wxListBoxNameStr[] = wxT("listBox"); +extern WXDLLEXPORT_DATA(const wxChar) wxStaticLineNameStr[] = wxT("staticLine"); +extern WXDLLEXPORT_DATA(const wxChar) wxStaticTextNameStr[] = wxT("staticText"); +extern WXDLLEXPORT_DATA(const wxChar) wxStaticBitmapNameStr[] = wxT("staticBitmap"); +extern WXDLLEXPORT_DATA(const wxChar) wxNotebookNameStr[] = wxT("notebook"); +extern WXDLLEXPORT_DATA(const wxChar) wxPanelNameStr[] = wxT("panel"); +extern WXDLLEXPORT_DATA(const wxChar) wxRadioBoxNameStr[] = wxT("radioBox"); +extern WXDLLEXPORT_DATA(const wxChar) wxRadioButtonNameStr[] = wxT("radioButton"); +extern WXDLLEXPORT_DATA(const wxChar) wxBitmapRadioButtonNameStr[] = wxT("radioButton"); +extern WXDLLEXPORT_DATA(const wxChar) wxScrollBarNameStr[] = wxT("scrollBar"); +extern WXDLLEXPORT_DATA(const wxChar) wxSliderNameStr[] = wxT("slider"); +extern WXDLLEXPORT_DATA(const wxChar) wxStatusLineNameStr[] = wxT("status_line"); +extern WXDLLEXPORT_DATA(const wxChar) wxTextCtrlNameStr[] = wxT("text"); +extern WXDLLEXPORT_DATA(const wxChar) wxTreeCtrlNameStr[] = wxT("treeCtrl"); +extern WXDLLEXPORT_DATA(const wxChar) wxToolBarNameStr[] = wxT("toolbar"); + +// Default messages +extern WXDLLEXPORT_DATA(const wxChar) wxMessageBoxCaptionStr[] = wxT("Message"); +extern WXDLLEXPORT_DATA(const wxChar) wxFileSelectorPromptStr[] = wxT("Select a file"); +extern WXDLLEXPORT_DATA(const wxChar) wxDirSelectorPromptStr[] = wxT("Select a directory"); + +// Other default strings +extern WXDLLEXPORT_DATA(const wxChar) wxFileSelectorDefaultWildcardStr[] = +#if defined(__WXMSW__) || defined(__OS2__) + wxT("*.*") +#else // Unix/Mac + wxT("*") +#endif + ; +extern WXDLLEXPORT_DATA(const wxChar) wxDirDialogNameStr[] = wxT("wxDirCtrl"); +extern WXDLLEXPORT_DATA(const wxChar) wxDirDialogDefaultFolderStr[] = wxT("/"); + +extern WXDLLEXPORT_DATA(const wxChar) wxFileDialogNameStr[] = wxT("filedlg"); +#if defined(__WXMSW__) || defined(__OS2__) +WXDLLEXPORT_DATA(const wxChar *) wxUserResourceStr = wxT("TEXT"); +#endif diff --git a/Source/3rd Party/wx/src/common/datetime.cpp b/Source/3rd Party/wx/src/common/datetime.cpp index 1b2f9345b..30db343e8 100644 --- a/Source/3rd Party/wx/src/common/datetime.cpp +++ b/Source/3rd Party/wx/src/common/datetime.cpp @@ -1,4615 +1,4615 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/datetime.cpp -// Purpose: implementation of time/date related classes -// Author: Vadim Zeitlin -// Modified by: -// Created: 11.05.99 -// RCS-ID: $Id: datetime.cpp 65730 2010-10-02 16:50:34Z TIK $ -// Copyright: (c) 1999 Vadim Zeitlin -// parts of code taken from sndcal library by Scott E. Lee: -// -// Copyright 1993-1995, Scott E. Lee, all rights reserved. -// Permission granted to use, copy, modify, distribute and sell -// so long as the above copyright and this permission statement -// are retained in all copies. -// -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -/* - * Implementation notes: - * - * 1. the time is stored as a 64bit integer containing the signed number of - * milliseconds since Jan 1. 1970 (the Unix Epoch) - so it is always - * expressed in GMT. - * - * 2. the range is thus something about 580 million years, but due to current - * algorithms limitations, only dates from Nov 24, 4714BC are handled - * - * 3. standard ANSI C functions are used to do time calculations whenever - * possible, i.e. when the date is in the range Jan 1, 1970 to 2038 - * - * 4. otherwise, the calculations are done by converting the date to/from JDN - * first (the range limitation mentioned above comes from here: the - * algorithm used by Scott E. Lee's code only works for positive JDNs, more - * or less) - * - * 5. the object constructed for the given DD-MM-YYYY HH:MM:SS corresponds to - * this moment in local time and may be converted to the object - * corresponding to the same date/time in another time zone by using - * ToTimezone() - * - * 6. the conversions to the current (or any other) timezone are done when the - * internal time representation is converted to the broken-down one in - * wxDateTime::Tm. - */ - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if !defined(wxUSE_DATETIME) || wxUSE_DATETIME - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/wrapwin.h" - #endif - #include "wx/string.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/stopwatch.h" // for wxGetLocalTimeMillis() - #include "wx/module.h" -#endif // WX_PRECOMP - -#include "wx/thread.h" -#include "wx/tokenzr.h" - -#include - -#ifdef __WINDOWS__ - #include - #ifndef __WXWINCE__ - #include - #endif -#endif - -#include "wx/datetime.h" - -const long wxDateTime::TIME_T_FACTOR = 1000l; - -#if wxUSE_EXTENDED_RTTI - -template<> void wxStringReadValue(const wxString &s , wxDateTime &data ) -{ - data.ParseFormat(s,wxT("%Y-%m-%d %H:%M:%S")) ; -} - -template<> void wxStringWriteValue(wxString &s , const wxDateTime &data ) -{ - s = data.Format(wxT("%Y-%m-%d %H:%M:%S")) ; -} - -wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter , wxFromStringConverter) - -#endif - -// -// ---------------------------------------------------------------------------- -// conditional compilation -// ---------------------------------------------------------------------------- - -#if defined(HAVE_STRPTIME) && defined(__GLIBC__) && \ - ((__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0)) - // glibc 2.0.7 strptime() is broken - the following snippet causes it to - // crash (instead of just failing): - // - // strncpy(buf, "Tue Dec 21 20:25:40 1999", 128); - // strptime(buf, "%x", &tm); - // - // so don't use it - #undef HAVE_STRPTIME -#endif // broken strptime() - -#if defined(HAVE_STRPTIME) && defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS - // configure detects strptime as linkable because it's in the OS X - // System library but MSL headers don't declare it. - -// char *strptime(const char *, const char *, struct tm *); - // However, we DON'T want to just provide it here because we would - // crash and/or overwrite data when strptime from OS X tries - // to fill in MW's struct tm which is two fields shorter (no TZ stuff) - // So for now let's just say we don't have strptime - #undef HAVE_STRPTIME -#endif - -#if defined(__MWERKS__) && wxUSE_UNICODE - #include -#endif - -// define a special symbol for VC8 instead of writing tests for 1400 repeatedly -#ifdef __VISUALC__ - #if __VISUALC__ >= 1400 - #define __VISUALC8__ - #endif -#endif - -#if !defined(WX_TIMEZONE) && !defined(WX_GMTOFF_IN_TM) - #if defined(__WXPALMOS__) - #define WX_GMTOFF_IN_TM - #elif defined(__WXMSW__) - static long wxGetTimeZone() - { - TIME_ZONE_INFORMATION info; - GetTimeZoneInformation(&info); - long timeZone = info.Bias * 60; // convert minutes to seconds - return timeZone; - } - #define WX_TIMEZONE wxGetTimeZone() - #elif defined(__VISAGECPP__) - #define WX_TIMEZONE _timezone - #elif defined(__MWERKS__) - long wxmw_timezone = 28800; - #define WX_TIMEZONE wxmw_timezone - #elif defined(__DARWIN__) - #define WX_GMTOFF_IN_TM - #else // unknown platform - try timezone - #define WX_TIMEZONE timezone - #endif -#endif // !WX_TIMEZONE && !WX_GMTOFF_IN_TM - -// everyone has strftime except Win CE unless VC8 is used -#if !defined(__WXWINCE__) || defined(__VISUALC8__) - #define HAVE_STRFTIME -#endif - -// NB: VC8 safe time functions could/should be used for wxMSW as well probably -#if defined(__WXWINCE__) && defined(__VISUALC8__) - -struct tm *wxLocaltime_r(const time_t *t, struct tm* tm) -{ - __time64_t t64 = *t; - return _localtime64_s(tm, &t64) == 0 ? tm : NULL; -} - -struct tm *wxGmtime_r(const time_t* t, struct tm* tm) -{ - __time64_t t64 = *t; - return _gmtime64_s(tm, &t64) == 0 ? tm : NULL; -} - -#else // !wxWinCE with VC8 - -#if (!defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)) && wxUSE_THREADS && !defined(__WINDOWS__) -static wxMutex timeLock; -#endif - -#ifndef HAVE_LOCALTIME_R -struct tm *wxLocaltime_r(const time_t* ticks, struct tm* temp) -{ -#if wxUSE_THREADS && !defined(__WINDOWS__) - // No need to waste time with a mutex on windows since it's using - // thread local storage for localtime anyway. - wxMutexLocker locker(timeLock); -#endif - - // Borland CRT crashes when passed 0 ticks for some reason, see SF bug 1704438 -#ifdef __BORLANDC__ - if ( !*ticks ) - return NULL; -#endif - - const tm * const t = localtime(ticks); - if ( !t ) - return NULL; - - memcpy(temp, t, sizeof(struct tm)); - return temp; -} -#endif // !HAVE_LOCALTIME_R - -#ifndef HAVE_GMTIME_R -struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp) -{ -#if wxUSE_THREADS && !defined(__WINDOWS__) - // No need to waste time with a mutex on windows since it's - // using thread local storage for gmtime anyway. - wxMutexLocker locker(timeLock); -#endif - -#ifdef __BORLANDC__ - if ( !*ticks ) - return NULL; -#endif - - const tm * const t = gmtime(ticks); - if ( !t ) - return NULL; - - memcpy(temp, gmtime(ticks), sizeof(struct tm)); - return temp; -} -#endif // !HAVE_GMTIME_R - -#endif // wxWinCE with VC8/other platforms - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- - -// debugging helper: just a convenient replacement of wxCHECK() -#define wxDATETIME_CHECK(expr, msg) \ - wxCHECK2_MSG(expr, *this = wxInvalidDateTime; return *this, msg) - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -class wxDateTimeHolidaysModule : public wxModule -{ -public: - virtual bool OnInit() - { - wxDateTimeHolidayAuthority::AddAuthority(new wxDateTimeWorkDays); - - return true; - } - - virtual void OnExit() - { - wxDateTimeHolidayAuthority::ClearAllAuthorities(); - wxDateTimeHolidayAuthority::ms_authorities.clear(); - } - -private: - DECLARE_DYNAMIC_CLASS(wxDateTimeHolidaysModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxDateTimeHolidaysModule, wxModule) - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// some trivial ones -static const int MONTHS_IN_YEAR = 12; - -static const int SEC_PER_MIN = 60; - -static const int MIN_PER_HOUR = 60; - -static const int HOURS_PER_DAY = 24; - -static const long SECONDS_PER_DAY = 86400l; - -static const int DAYS_PER_WEEK = 7; - -static const long MILLISECONDS_PER_DAY = 86400000l; - -// this is the integral part of JDN of the midnight of Jan 1, 1970 -// (i.e. JDN(Jan 1, 1970) = 2440587.5) -static const long EPOCH_JDN = 2440587l; - -// used only in asserts -#ifdef __WXDEBUG__ -// the date of JDN -0.5 (as we don't work with fractional parts, this is the -// reference date for us) is Nov 24, 4714BC -static const int JDN_0_YEAR = -4713; -static const int JDN_0_MONTH = wxDateTime::Nov; -static const int JDN_0_DAY = 24; -#endif // __WXDEBUG__ - -// the constants used for JDN calculations -static const long JDN_OFFSET = 32046l; -static const long DAYS_PER_5_MONTHS = 153l; -static const long DAYS_PER_4_YEARS = 1461l; -static const long DAYS_PER_400_YEARS = 146097l; - -// this array contains the cumulated number of days in all previous months for -// normal and leap years -static const wxDateTime::wxDateTime_t gs_cumulatedDays[2][MONTHS_IN_YEAR] = -{ - { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }, - { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 } -}; - -// ---------------------------------------------------------------------------- -// global data -// ---------------------------------------------------------------------------- - -const wxChar * wxDefaultDateTimeFormat = wxT("%c"); -const wxChar * wxDefaultTimeSpanFormat = wxT("%H:%M:%S"); - -// in the fine tradition of ANSI C we use our equivalent of (time_t)-1 to -// indicate an invalid wxDateTime object -const wxDateTime wxDefaultDateTime; - -wxDateTime::Country wxDateTime::ms_country = wxDateTime::Country_Unknown; - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -// debugger helper: shows what the date really is -#ifdef __WXDEBUG__ -extern const wxChar *wxDumpDate(const wxDateTime* dt) -{ - static wxChar buf[128]; - - wxStrcpy(buf, dt->Format(_T("%Y-%m-%d (%a) %H:%M:%S"))); - - return buf; -} -#endif // Debug - -// get the number of days in the given month of the given year -static inline -wxDateTime::wxDateTime_t GetNumOfDaysInMonth(int year, wxDateTime::Month month) -{ - // the number of days in month in Julian/Gregorian calendar: the first line - // is for normal years, the second one is for the leap ones - static wxDateTime::wxDateTime_t daysInMonth[2][MONTHS_IN_YEAR] = - { - { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, - { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } - }; - - return daysInMonth[wxDateTime::IsLeapYear(year)][month]; -} - -// returns the time zone in the C sense, i.e. the difference UTC - local -// (in seconds) -static int GetTimeZone() -{ -#ifdef WX_GMTOFF_IN_TM - // set to true when the timezone is set - static bool s_timezoneSet = false; - static long gmtoffset = LONG_MAX; // invalid timezone - - // ensure that the timezone variable is set by calling wxLocaltime_r - if ( !s_timezoneSet ) - { - // just call wxLocaltime_r() instead of figuring out whether this - // system supports tzset(), _tzset() or something else - time_t t = 0; - struct tm tm; - - wxLocaltime_r(&t, &tm); - s_timezoneSet = true; - - // note that GMT offset is the opposite of time zone and so to return - // consistent results in both WX_GMTOFF_IN_TM and !WX_GMTOFF_IN_TM - // cases we have to negate it - gmtoffset = -tm.tm_gmtoff; - } - return (int)gmtoffset; -#else // !WX_GMTOFF_IN_TM - return WX_TIMEZONE; -#endif // WX_GMTOFF_IN_TM/!WX_GMTOFF_IN_TM -} - -// return the integral part of the JDN for the midnight of the given date (to -// get the real JDN you need to add 0.5, this is, in fact, JDN of the -// noon of the previous day) -static long GetTruncatedJDN(wxDateTime::wxDateTime_t day, - wxDateTime::Month mon, - int year) -{ - // CREDIT: code below is by Scott E. Lee (but bugs are mine) - - // check the date validity - wxASSERT_MSG( - (year > JDN_0_YEAR) || - ((year == JDN_0_YEAR) && (mon > JDN_0_MONTH)) || - ((year == JDN_0_YEAR) && (mon == JDN_0_MONTH) && (day >= JDN_0_DAY)), - _T("date out of range - can't convert to JDN") - ); - - // make the year positive to avoid problems with negative numbers division - year += 4800; - - // months are counted from March here - int month; - if ( mon >= wxDateTime::Mar ) - { - month = mon - 2; - } - else - { - month = mon + 10; - year--; - } - - // now we can simply add all the contributions together - return ((year / 100) * DAYS_PER_400_YEARS) / 4 - + ((year % 100) * DAYS_PER_4_YEARS) / 4 - + (month * DAYS_PER_5_MONTHS + 2) / 5 - + day - - JDN_OFFSET; -} - -#ifdef HAVE_STRFTIME - -// this function is a wrapper around strftime(3) adding error checking -static wxString CallStrftime(const wxChar *format, const tm* tm) -{ - wxChar buf[4096]; - // Create temp wxString here to work around mingw/cygwin bug 1046059 - // http://sourceforge.net/tracker/?func=detail&atid=102435&aid=1046059&group_id=2435 - wxString s; - - if ( !wxStrftime(buf, WXSIZEOF(buf), format, tm) ) - { - // buffer is too small? - wxFAIL_MSG(_T("strftime() failed")); - } - - s = buf; - return s; -} - -#endif // HAVE_STRFTIME - -#ifdef HAVE_STRPTIME - -#if wxUSE_UNIX && !defined(HAVE_STRPTIME_DECL) - // configure detected that we had strptime() but not its declaration, - // provide it ourselves - extern "C" char *strptime(const char *, const char *, struct tm *); -#endif - -// Unicode-friendly strptime() wrapper -static const wxChar * -CallStrptime(const wxChar *input, const char *fmt, tm *tm) -{ - // the problem here is that strptime() returns pointer into the string we - // passed to it while we're really interested in the pointer into the - // original, Unicode, string so we try to transform the pointer back -#if wxUSE_UNICODE - wxCharBuffer inputMB(wxConvertWX2MB(input)); -#else // ASCII - const char * const inputMB = input; -#endif // Unicode/Ascii - - const char *result = strptime(inputMB, fmt, tm); - if ( !result ) - return NULL; - -#if wxUSE_UNICODE - // FIXME: this is wrong in presence of surrogates &c - return input + (result - inputMB.data()); -#else // ASCII - return result; -#endif // Unicode/Ascii -} - -#endif // HAVE_STRPTIME - -// if year and/or month have invalid values, replace them with the current ones -static void ReplaceDefaultYearMonthWithCurrent(int *year, - wxDateTime::Month *month) -{ - struct tm *tmNow = NULL; - struct tm tmstruct; - - if ( *year == wxDateTime::Inv_Year ) - { - tmNow = wxDateTime::GetTmNow(&tmstruct); - - *year = 1900 + tmNow->tm_year; - } - - if ( *month == wxDateTime::Inv_Month ) - { - if ( !tmNow ) - tmNow = wxDateTime::GetTmNow(&tmstruct); - - *month = (wxDateTime::Month)tmNow->tm_mon; - } -} - -// fll the struct tm with default values -static void InitTm(struct tm& tm) -{ - // struct tm may have etxra fields (undocumented and with unportable - // names) which, nevertheless, must be set to 0 - memset(&tm, 0, sizeof(struct tm)); - - tm.tm_mday = 1; // mday 0 is invalid - tm.tm_year = 76; // any valid year - tm.tm_isdst = -1; // auto determine -} - -// parsing helpers -// --------------- - -// return the month if the string is a month name or Inv_Month otherwise -static wxDateTime::Month GetMonthFromName(const wxString& name, int flags) -{ - wxDateTime::Month mon; - for ( mon = wxDateTime::Jan; mon < wxDateTime::Inv_Month; wxNextMonth(mon) ) - { - // case-insensitive comparison either one of or with both abbreviated - // and not versions - if ( flags & wxDateTime::Name_Full ) - { - if ( name.CmpNoCase(wxDateTime:: - GetMonthName(mon, wxDateTime::Name_Full)) == 0 ) - { - break; - } - } - - if ( flags & wxDateTime::Name_Abbr ) - { - if ( name.CmpNoCase(wxDateTime:: - GetMonthName(mon, wxDateTime::Name_Abbr)) == 0 ) - { - break; - } - } - } - - return mon; -} - -// return the weekday if the string is a weekday name or Inv_WeekDay otherwise -static wxDateTime::WeekDay GetWeekDayFromName(const wxString& name, int flags) -{ - wxDateTime::WeekDay wd; - for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) ) - { - // case-insensitive comparison either one of or with both abbreviated - // and not versions - if ( flags & wxDateTime::Name_Full ) - { - if ( name.CmpNoCase(wxDateTime:: - GetWeekDayName(wd, wxDateTime::Name_Full)) == 0 ) - { - break; - } - } - - if ( flags & wxDateTime::Name_Abbr ) - { - if ( name.CmpNoCase(wxDateTime:: - GetWeekDayName(wd, wxDateTime::Name_Abbr)) == 0 ) - { - break; - } - } - } - - return wd; -} - -/* static */ -struct tm *wxDateTime::GetTmNow(struct tm *tmstruct) -{ - time_t t = GetTimeNow(); - return wxLocaltime_r(&t, tmstruct); -} - -// scans all digits (but no more than len) and returns the resulting number -static bool GetNumericToken(size_t len, const wxChar*& p, unsigned long *number) -{ - size_t n = 1; - wxString s; - while ( wxIsdigit(*p) ) - { - s += *p++; - - if ( len && ++n > len ) - break; - } - - return !s.empty() && s.ToULong(number); -} - -// scans all alphabetic characters and returns the resulting string -static wxString GetAlphaToken(const wxChar*& p) -{ - wxString s; - while ( wxIsalpha(*p) ) - { - s += *p++; - } - - return s; -} - -// ============================================================================ -// implementation of wxDateTime -// ============================================================================ - -// ---------------------------------------------------------------------------- -// struct Tm -// ---------------------------------------------------------------------------- - -wxDateTime::Tm::Tm() -{ - year = (wxDateTime_t)wxDateTime::Inv_Year; - mon = wxDateTime::Inv_Month; - mday = 0; - hour = min = sec = msec = 0; - wday = wxDateTime::Inv_WeekDay; -} - -wxDateTime::Tm::Tm(const struct tm& tm, const TimeZone& tz) - : m_tz(tz) -{ - msec = 0; - sec = (wxDateTime::wxDateTime_t)tm.tm_sec; - min = (wxDateTime::wxDateTime_t)tm.tm_min; - hour = (wxDateTime::wxDateTime_t)tm.tm_hour; - mday = (wxDateTime::wxDateTime_t)tm.tm_mday; - mon = (wxDateTime::Month)tm.tm_mon; - year = 1900 + tm.tm_year; - wday = (wxDateTime::wxDateTime_t)tm.tm_wday; - yday = (wxDateTime::wxDateTime_t)tm.tm_yday; -} - -bool wxDateTime::Tm::IsValid() const -{ - // we allow for the leap seconds, although we don't use them (yet) - return (year != wxDateTime::Inv_Year) && (mon != wxDateTime::Inv_Month) && - (mday <= GetNumOfDaysInMonth(year, mon)) && - (hour < 24) && (min < 60) && (sec < 62) && (msec < 1000); -} - -void wxDateTime::Tm::ComputeWeekDay() -{ - // compute the week day from day/month/year: we use the dumbest algorithm - // possible: just compute our JDN and then use the (simple to derive) - // formula: weekday = (JDN + 1.5) % 7 - wday = (wxDateTime::wxDateTime_t)((GetTruncatedJDN(mday, mon, year) + 2) % 7); -} - -void wxDateTime::Tm::AddMonths(int monDiff) -{ - // normalize the months field - while ( monDiff < -mon ) - { - year--; - - monDiff += MONTHS_IN_YEAR; - } - - while ( monDiff + mon >= MONTHS_IN_YEAR ) - { - year++; - - monDiff -= MONTHS_IN_YEAR; - } - - mon = (wxDateTime::Month)(mon + monDiff); - - wxASSERT_MSG( mon >= 0 && mon < MONTHS_IN_YEAR, _T("logic error") ); - - // NB: we don't check here that the resulting date is valid, this function - // is private and the caller must check it if needed -} - -void wxDateTime::Tm::AddDays(int dayDiff) -{ - // normalize the days field - while ( dayDiff + mday < 1 ) - { - AddMonths(-1); - - dayDiff += GetNumOfDaysInMonth(year, mon); - } - - mday = (wxDateTime::wxDateTime_t)( mday + dayDiff ); - while ( mday > GetNumOfDaysInMonth(year, mon) ) - { - mday -= GetNumOfDaysInMonth(year, mon); - - AddMonths(1); - } - - wxASSERT_MSG( mday > 0 && mday <= GetNumOfDaysInMonth(year, mon), - _T("logic error") ); -} - -// ---------------------------------------------------------------------------- -// class TimeZone -// ---------------------------------------------------------------------------- - -wxDateTime::TimeZone::TimeZone(wxDateTime::TZ tz) -{ - switch ( tz ) - { - case wxDateTime::Local: - // get the offset from C RTL: it returns the difference GMT-local - // while we want to have the offset _from_ GMT, hence the '-' - m_offset = -GetTimeZone(); - break; - - case wxDateTime::GMT_12: - case wxDateTime::GMT_11: - case wxDateTime::GMT_10: - case wxDateTime::GMT_9: - case wxDateTime::GMT_8: - case wxDateTime::GMT_7: - case wxDateTime::GMT_6: - case wxDateTime::GMT_5: - case wxDateTime::GMT_4: - case wxDateTime::GMT_3: - case wxDateTime::GMT_2: - case wxDateTime::GMT_1: - m_offset = -3600*(wxDateTime::GMT0 - tz); - break; - - case wxDateTime::GMT0: - case wxDateTime::GMT1: - case wxDateTime::GMT2: - case wxDateTime::GMT3: - case wxDateTime::GMT4: - case wxDateTime::GMT5: - case wxDateTime::GMT6: - case wxDateTime::GMT7: - case wxDateTime::GMT8: - case wxDateTime::GMT9: - case wxDateTime::GMT10: - case wxDateTime::GMT11: - case wxDateTime::GMT12: - case wxDateTime::GMT13: - m_offset = 3600*(tz - wxDateTime::GMT0); - break; - - case wxDateTime::A_CST: - // Central Standard Time in use in Australia = UTC + 9.5 - m_offset = 60l*(9*MIN_PER_HOUR + MIN_PER_HOUR/2); - break; - - default: - wxFAIL_MSG( _T("unknown time zone") ); - } -} - -// ---------------------------------------------------------------------------- -// static functions -// ---------------------------------------------------------------------------- - -/* static */ -bool wxDateTime::IsLeapYear(int year, wxDateTime::Calendar cal) -{ - if ( year == Inv_Year ) - year = GetCurrentYear(); - - if ( cal == Gregorian ) - { - // in Gregorian calendar leap years are those divisible by 4 except - // those divisible by 100 unless they're also divisible by 400 - // (in some countries, like Russia and Greece, additional corrections - // exist, but they won't manifest themselves until 2700) - return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)); - } - else if ( cal == Julian ) - { - // in Julian calendar the rule is simpler - return year % 4 == 0; - } - else - { - wxFAIL_MSG(_T("unknown calendar")); - - return false; - } -} - -/* static */ -int wxDateTime::GetCentury(int year) -{ - return year > 0 ? year / 100 : year / 100 - 1; -} - -/* static */ -int wxDateTime::ConvertYearToBC(int year) -{ - // year 0 is BC 1 - return year > 0 ? year : year - 1; -} - -/* static */ -int wxDateTime::GetCurrentYear(wxDateTime::Calendar cal) -{ - switch ( cal ) - { - case Gregorian: - return Now().GetYear(); - - case Julian: - wxFAIL_MSG(_T("TODO")); - break; - - default: - wxFAIL_MSG(_T("unsupported calendar")); - break; - } - - return Inv_Year; -} - -/* static */ -wxDateTime::Month wxDateTime::GetCurrentMonth(wxDateTime::Calendar cal) -{ - switch ( cal ) - { - case Gregorian: - return Now().GetMonth(); - - case Julian: - wxFAIL_MSG(_T("TODO")); - break; - - default: - wxFAIL_MSG(_T("unsupported calendar")); - break; - } - - return Inv_Month; -} - -/* static */ -wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(int year, Calendar cal) -{ - if ( year == Inv_Year ) - { - // take the current year if none given - year = GetCurrentYear(); - } - - switch ( cal ) - { - case Gregorian: - case Julian: - return IsLeapYear(year) ? 366 : 365; - - default: - wxFAIL_MSG(_T("unsupported calendar")); - break; - } - - return 0; -} - -/* static */ -wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(wxDateTime::Month month, - int year, - wxDateTime::Calendar cal) -{ - wxCHECK_MSG( month < MONTHS_IN_YEAR, 0, _T("invalid month") ); - - if ( cal == Gregorian || cal == Julian ) - { - if ( year == Inv_Year ) - { - // take the current year if none given - year = GetCurrentYear(); - } - - return GetNumOfDaysInMonth(year, month); - } - else - { - wxFAIL_MSG(_T("unsupported calendar")); - - return 0; - } -} - -/* static */ -wxString wxDateTime::GetMonthName(wxDateTime::Month month, - wxDateTime::NameFlags flags) -{ - wxCHECK_MSG( month != Inv_Month, wxEmptyString, _T("invalid month") ); -#ifdef HAVE_STRFTIME - // notice that we must set all the fields to avoid confusing libc (GNU one - // gets confused to a crash if we don't do this) - tm tm; - InitTm(tm); - tm.tm_mon = month; - - return CallStrftime(flags == Name_Abbr ? _T("%b") : _T("%B"), &tm); -#else // !HAVE_STRFTIME - wxString ret; - switch(month) - { - case Jan: - ret = (flags == Name_Abbr ? wxT("Jan"): wxT("January")); - break; - case Feb: - ret = (flags == Name_Abbr ? wxT("Feb"): wxT("Febuary")); - break; - case Mar: - ret = (flags == Name_Abbr ? wxT("Mar"): wxT("March")); - break; - case Apr: - ret = (flags == Name_Abbr ? wxT("Apr"): wxT("April")); - break; - case May: - ret = (flags == Name_Abbr ? wxT("May"): wxT("May")); - break; - case Jun: - ret = (flags == Name_Abbr ? wxT("Jun"): wxT("June")); - break; - case Jul: - ret = (flags == Name_Abbr ? wxT("Jul"): wxT("July")); - break; - case Aug: - ret = (flags == Name_Abbr ? wxT("Aug"): wxT("August")); - break; - case Sep: - ret = (flags == Name_Abbr ? wxT("Sep"): wxT("September")); - break; - case Oct: - ret = (flags == Name_Abbr ? wxT("Oct"): wxT("October")); - break; - case Nov: - ret = (flags == Name_Abbr ? wxT("Nov"): wxT("November")); - break; - case Dec: - ret = (flags == Name_Abbr ? wxT("Dec"): wxT("December")); - break; - } - return ret; -#endif // HAVE_STRFTIME/!HAVE_STRFTIME -} - -/* static */ -wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday, - wxDateTime::NameFlags flags) -{ - wxCHECK_MSG( wday != Inv_WeekDay, wxEmptyString, _T("invalid weekday") ); -#ifdef HAVE_STRFTIME - // take some arbitrary Sunday (but notice that the day should be such that - // after adding wday to it below we still have a valid date, e.g. don't - // take 28 here!) - tm tm; - InitTm(tm); - tm.tm_mday = 21; - tm.tm_mon = Nov; - tm.tm_year = 99; - - // and offset it by the number of days needed to get the correct wday - tm.tm_mday += wday; - - // call mktime() to normalize it... - (void)mktime(&tm); - - // ... and call strftime() - return CallStrftime(flags == Name_Abbr ? _T("%a") : _T("%A"), &tm); -#else // !HAVE_STRFTIME - wxString ret; - switch(wday) - { - case Sun: - ret = (flags == Name_Abbr ? wxT("Sun") : wxT("Sunday")); - break; - case Mon: - ret = (flags == Name_Abbr ? wxT("Mon") : wxT("Monday")); - break; - case Tue: - ret = (flags == Name_Abbr ? wxT("Tue") : wxT("Tuesday")); - break; - case Wed: - ret = (flags == Name_Abbr ? wxT("Wed") : wxT("Wednesday")); - break; - case Thu: - ret = (flags == Name_Abbr ? wxT("Thu") : wxT("Thursday")); - break; - case Fri: - ret = (flags == Name_Abbr ? wxT("Fri") : wxT("Friday")); - break; - case Sat: - ret = (flags == Name_Abbr ? wxT("Sat") : wxT("Saturday")); - break; - } - return ret; -#endif // HAVE_STRFTIME/!HAVE_STRFTIME -} - -/* static */ -void wxDateTime::GetAmPmStrings(wxString *am, wxString *pm) -{ - tm tm; - InitTm(tm); - wxChar buffer[64]; - // @Note: Do not call 'CallStrftime' here! CallStrftime checks the return code - // and causes an assertion failed if the buffer is to small (which is good) - OR - - // if strftime does not return anything because the format string is invalid - OR - - // if there are no 'am' / 'pm' tokens defined for the current locale (which is not good). - // wxDateTime::ParseTime will try several different formats to parse the time. - // As a result, GetAmPmStrings might get called, even if the current locale - // does not define any 'am' / 'pm' tokens. In this case, wxStrftime would - // assert, even though it is a perfectly legal use. - if ( am ) - { - if (wxStrftime(buffer, sizeof(buffer)/sizeof(wxChar), _T("%p"), &tm) > 0) - *am = wxString(buffer); - else - *am = wxString(); - } - if ( pm ) - { - tm.tm_hour = 13; - if (wxStrftime(buffer, sizeof(buffer)/sizeof(wxChar), _T("%p"), &tm) > 0) - *pm = wxString(buffer); - else - *pm = wxString(); - } -} - -// ---------------------------------------------------------------------------- -// Country stuff: date calculations depend on the country (DST, work days, -// ...), so we need to know which rules to follow. -// ---------------------------------------------------------------------------- - -/* static */ -wxDateTime::Country wxDateTime::GetCountry() -{ - // TODO use LOCALE_ICOUNTRY setting under Win32 -#ifndef __WXWINCE__ - if ( ms_country == Country_Unknown ) - { - // try to guess from the time zone name - time_t t = time(NULL); - struct tm tmstruct; - struct tm *tm = wxLocaltime_r(&t, &tmstruct); - - wxString tz = CallStrftime(_T("%Z"), tm); - if ( tz == _T("WET") || tz == _T("WEST") ) - { - ms_country = UK; - } - else if ( tz == _T("CET") || tz == _T("CEST") ) - { - ms_country = Country_EEC; - } - else if ( tz == _T("MSK") || tz == _T("MSD") ) - { - ms_country = Russia; - } - else if ( tz == _T("AST") || tz == _T("ADT") || - tz == _T("EST") || tz == _T("EDT") || - tz == _T("CST") || tz == _T("CDT") || - tz == _T("MST") || tz == _T("MDT") || - tz == _T("PST") || tz == _T("PDT") ) - { - ms_country = USA; - } - else - { - // well, choose a default one - ms_country = USA; - } - } -#else // __WXWINCE__ - ms_country = USA; -#endif // !__WXWINCE__/__WXWINCE__ - - return ms_country; -} - -/* static */ -void wxDateTime::SetCountry(wxDateTime::Country country) -{ - ms_country = country; -} - -/* static */ -bool wxDateTime::IsWestEuropeanCountry(Country country) -{ - if ( country == Country_Default ) - { - country = GetCountry(); - } - - return (Country_WesternEurope_Start <= country) && - (country <= Country_WesternEurope_End); -} - -// ---------------------------------------------------------------------------- -// DST calculations: we use 3 different rules for the West European countries, -// USA and for the rest of the world. This is undoubtedly false for many -// countries, but I lack the necessary info (and the time to gather it), -// please add the other rules here! -// ---------------------------------------------------------------------------- - -/* static */ -bool wxDateTime::IsDSTApplicable(int year, Country country) -{ - if ( year == Inv_Year ) - { - // take the current year if none given - year = GetCurrentYear(); - } - - if ( country == Country_Default ) - { - country = GetCountry(); - } - - switch ( country ) - { - case USA: - case UK: - // DST was first observed in the US and UK during WWI, reused - // during WWII and used again since 1966 - return year >= 1966 || - (year >= 1942 && year <= 1945) || - (year == 1918 || year == 1919); - - default: - // assume that it started after WWII - return year > 1950; - } -} - -/* static */ -wxDateTime wxDateTime::GetBeginDST(int year, Country country) -{ - if ( year == Inv_Year ) - { - // take the current year if none given - year = GetCurrentYear(); - } - - if ( country == Country_Default ) - { - country = GetCountry(); - } - - if ( !IsDSTApplicable(year, country) ) - { - return wxInvalidDateTime; - } - - wxDateTime dt; - - if ( IsWestEuropeanCountry(country) || (country == Russia) ) - { - // DST begins at 1 a.m. GMT on the last Sunday of March - if ( !dt.SetToLastWeekDay(Sun, Mar, year) ) - { - // weird... - wxFAIL_MSG( _T("no last Sunday in March?") ); - } - - dt += wxTimeSpan::Hours(1); - - // disable DST tests because it could result in an infinite recursion! - dt.MakeGMT(true); - } - else switch ( country ) - { - case USA: - switch ( year ) - { - case 1918: - case 1919: - // don't know for sure - assume it was in effect all year - - case 1943: - case 1944: - case 1945: - dt.Set(1, Jan, year); - break; - - case 1942: - // DST was installed Feb 2, 1942 by the Congress - dt.Set(2, Feb, year); - break; - - // Oil embargo changed the DST period in the US - case 1974: - dt.Set(6, Jan, 1974); - break; - - case 1975: - dt.Set(23, Feb, 1975); - break; - - default: - // before 1986, DST begun on the last Sunday of April, but - // in 1986 Reagan changed it to begin at 2 a.m. of the - // first Sunday in April - if ( year < 1986 ) - { - if ( !dt.SetToLastWeekDay(Sun, Apr, year) ) - { - // weird... - wxFAIL_MSG( _T("no first Sunday in April?") ); - } - } - else if ( year > 2006 ) - // Energy Policy Act of 2005, Pub. L. no. 109-58, 119 Stat 594 (2005). - // Starting in 2007, daylight time begins in the United States on the - // second Sunday in March and ends on the first Sunday in November - { - if ( !dt.SetToWeekDay(Sun, 2, Mar, year) ) - { - // weird... - wxFAIL_MSG( _T("no second Sunday in March?") ); - } - } - else - { - if ( !dt.SetToWeekDay(Sun, 1, Apr, year) ) - { - // weird... - wxFAIL_MSG( _T("no first Sunday in April?") ); - } - } - - dt += wxTimeSpan::Hours(2); - - // TODO what about timezone?? - } - - break; - - default: - // assume Mar 30 as the start of the DST for the rest of the world - // - totally bogus, of course - dt.Set(30, Mar, year); - } - - return dt; -} - -/* static */ -wxDateTime wxDateTime::GetEndDST(int year, Country country) -{ - if ( year == Inv_Year ) - { - // take the current year if none given - year = GetCurrentYear(); - } - - if ( country == Country_Default ) - { - country = GetCountry(); - } - - if ( !IsDSTApplicable(year, country) ) - { - return wxInvalidDateTime; - } - - wxDateTime dt; - - if ( IsWestEuropeanCountry(country) || (country == Russia) ) - { - // DST ends at 1 a.m. GMT on the last Sunday of October - if ( !dt.SetToLastWeekDay(Sun, Oct, year) ) - { - // weirder and weirder... - wxFAIL_MSG( _T("no last Sunday in October?") ); - } - - dt += wxTimeSpan::Hours(1); - - // disable DST tests because it could result in an infinite recursion! - dt.MakeGMT(true); - } - else switch ( country ) - { - case USA: - switch ( year ) - { - case 1918: - case 1919: - // don't know for sure - assume it was in effect all year - - case 1943: - case 1944: - dt.Set(31, Dec, year); - break; - - case 1945: - // the time was reset after the end of the WWII - dt.Set(30, Sep, year); - break; - - default: // default for switch (year) - if ( year > 2006 ) - // Energy Policy Act of 2005, Pub. L. no. 109-58, 119 Stat 594 (2005). - // Starting in 2007, daylight time begins in the United States on the - // second Sunday in March and ends on the first Sunday in November - { - if ( !dt.SetToWeekDay(Sun, 1, Nov, year) ) - { - // weird... - wxFAIL_MSG( _T("no first Sunday in November?") ); - } - } - else - // pre-2007 - // DST ends at 2 a.m. on the last Sunday of October - { - if ( !dt.SetToLastWeekDay(Sun, Oct, year) ) - { - // weirder and weirder... - wxFAIL_MSG( _T("no last Sunday in October?") ); - } - } - - dt += wxTimeSpan::Hours(2); - - // TODO: what about timezone?? - } - break; - - default: // default for switch (country) - // assume October 26th as the end of the DST - totally bogus too - dt.Set(26, Oct, year); - } - - return dt; -} - -// ---------------------------------------------------------------------------- -// constructors and assignment operators -// ---------------------------------------------------------------------------- - -// return the current time with ms precision -/* static */ wxDateTime wxDateTime::UNow() -{ - return wxDateTime(wxGetLocalTimeMillis()); -} - -// the values in the tm structure contain the local time -wxDateTime& wxDateTime::Set(const struct tm& tm) -{ - struct tm tm2(tm); - time_t timet = mktime(&tm2); - - if ( timet == (time_t)-1 ) - { - // mktime() rather unintuitively fails for Jan 1, 1970 if the hour is - // less than timezone - try to make it work for this case - if ( tm2.tm_year == 70 && tm2.tm_mon == 0 && tm2.tm_mday == 1 ) - { - return Set((time_t)( - GetTimeZone() + - tm2.tm_hour * MIN_PER_HOUR * SEC_PER_MIN + - tm2.tm_min * SEC_PER_MIN + - tm2.tm_sec)); - } - - wxFAIL_MSG( _T("mktime() failed") ); - - *this = wxInvalidDateTime; - - return *this; - } - else - { - return Set(timet); - } -} - -wxDateTime& wxDateTime::Set(wxDateTime_t hour, - wxDateTime_t minute, - wxDateTime_t second, - wxDateTime_t millisec) -{ - // we allow seconds to be 61 to account for the leap seconds, even if we - // don't use them really - wxDATETIME_CHECK( hour < 24 && - second < 62 && - minute < 60 && - millisec < 1000, - _T("Invalid time in wxDateTime::Set()") ); - - // get the current date from system - struct tm tmstruct; - struct tm *tm = GetTmNow(&tmstruct); - - wxDATETIME_CHECK( tm, _T("wxLocaltime_r() failed") ); - - // make a copy so it isn't clobbered by the call to mktime() below - struct tm tm1(*tm); - - // adjust the time - tm1.tm_hour = hour; - tm1.tm_min = minute; - tm1.tm_sec = second; - - // and the DST in case it changes on this date - struct tm tm2(tm1); - mktime(&tm2); - if ( tm2.tm_isdst != tm1.tm_isdst ) - tm1.tm_isdst = tm2.tm_isdst; - - (void)Set(tm1); - - // and finally adjust milliseconds - return SetMillisecond(millisec); -} - -wxDateTime& wxDateTime::Set(wxDateTime_t day, - Month month, - int year, - wxDateTime_t hour, - wxDateTime_t minute, - wxDateTime_t second, - wxDateTime_t millisec) -{ - wxDATETIME_CHECK( hour < 24 && - second < 62 && - minute < 60 && - millisec < 1000, - _T("Invalid time in wxDateTime::Set()") ); - - ReplaceDefaultYearMonthWithCurrent(&year, &month); - - wxDATETIME_CHECK( (0 < day) && (day <= GetNumberOfDays(month, year)), - _T("Invalid date in wxDateTime::Set()") ); - - // the range of time_t type (inclusive) - static const int yearMinInRange = 1970; - static const int yearMaxInRange = 2037; - - // test only the year instead of testing for the exact end of the Unix - // time_t range - it doesn't bring anything to do more precise checks - if ( year >= yearMinInRange && year <= yearMaxInRange ) - { - // use the standard library version if the date is in range - this is - // probably more efficient than our code - struct tm tm; - tm.tm_year = year - 1900; - tm.tm_mon = month; - tm.tm_mday = day; - tm.tm_hour = hour; - tm.tm_min = minute; - tm.tm_sec = second; - tm.tm_isdst = -1; // mktime() will guess it - - (void)Set(tm); - - // and finally adjust milliseconds - if (IsValid()) - SetMillisecond(millisec); - - return *this; - } - else - { - // do time calculations ourselves: we want to calculate the number of - // milliseconds between the given date and the epoch - - // get the JDN for the midnight of this day - m_time = GetTruncatedJDN(day, month, year); - m_time -= EPOCH_JDN; - m_time *= SECONDS_PER_DAY * TIME_T_FACTOR; - - // JDN corresponds to GMT, we take localtime - Add(wxTimeSpan(hour, minute, second + GetTimeZone(), millisec)); - } - - return *this; -} - -wxDateTime& wxDateTime::Set(double jdn) -{ - // so that m_time will be 0 for the midnight of Jan 1, 1970 which is jdn - // EPOCH_JDN + 0.5 - jdn -= EPOCH_JDN + 0.5; - - m_time.Assign(jdn*MILLISECONDS_PER_DAY); - - // JDNs always are in UTC, so we don't need any adjustments for time zone - - return *this; -} - -wxDateTime& wxDateTime::ResetTime() -{ - Tm tm = GetTm(); - - if ( tm.hour || tm.min || tm.sec || tm.msec ) - { - tm.msec = - tm.sec = - tm.min = - tm.hour = 0; - - Set(tm); - } - - return *this; -} - -wxDateTime wxDateTime::GetDateOnly() const -{ - Tm tm = GetTm(); - tm.msec = - tm.sec = - tm.min = - tm.hour = 0; - return wxDateTime(tm); -} - -// ---------------------------------------------------------------------------- -// DOS Date and Time Format functions -// ---------------------------------------------------------------------------- -// the dos date and time value is an unsigned 32 bit value in the format: -// YYYYYYYMMMMDDDDDhhhhhmmmmmmsssss -// -// Y = year offset from 1980 (0-127) -// M = month (1-12) -// D = day of month (1-31) -// h = hour (0-23) -// m = minute (0-59) -// s = bisecond (0-29) each bisecond indicates two seconds -// ---------------------------------------------------------------------------- - -wxDateTime& wxDateTime::SetFromDOS(unsigned long ddt) -{ - struct tm tm; - InitTm(tm); - - long year = ddt & 0xFE000000; - year >>= 25; - year += 80; - tm.tm_year = year; - - long month = ddt & 0x1E00000; - month >>= 21; - month -= 1; - tm.tm_mon = month; - - long day = ddt & 0x1F0000; - day >>= 16; - tm.tm_mday = day; - - long hour = ddt & 0xF800; - hour >>= 11; - tm.tm_hour = hour; - - long minute = ddt & 0x7E0; - minute >>= 5; - tm.tm_min = minute; - - long second = ddt & 0x1F; - tm.tm_sec = second * 2; - - return Set(mktime(&tm)); -} - -unsigned long wxDateTime::GetAsDOS() const -{ - unsigned long ddt; - time_t ticks = GetTicks(); - struct tm tmstruct; - struct tm *tm = wxLocaltime_r(&ticks, &tmstruct); - wxCHECK_MSG( tm, ULONG_MAX, _T("time can't be represented in DOS format") ); - - long year = tm->tm_year; - year -= 80; - year <<= 25; - - long month = tm->tm_mon; - month += 1; - month <<= 21; - - long day = tm->tm_mday; - day <<= 16; - - long hour = tm->tm_hour; - hour <<= 11; - - long minute = tm->tm_min; - minute <<= 5; - - long second = tm->tm_sec; - second /= 2; - - ddt = year | month | day | hour | minute | second; - return ddt; -} - -// ---------------------------------------------------------------------------- -// time_t <-> broken down time conversions -// ---------------------------------------------------------------------------- - -wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - time_t time = GetTicks(); - if ( time != (time_t)-1 ) - { - // use C RTL functions - struct tm tmstruct; - tm *tm; - if ( tz.GetOffset() == -GetTimeZone() ) - { - // we are working with local time - tm = wxLocaltime_r(&time, &tmstruct); - - // should never happen - wxCHECK_MSG( tm, Tm(), _T("wxLocaltime_r() failed") ); - } - else - { - time += (time_t)tz.GetOffset(); -#if defined(__VMS__) || defined(__WATCOMC__) // time is unsigned so avoid warning - int time2 = (int) time; - if ( time2 >= 0 ) -#else - if ( time >= 0 ) -#endif - { - tm = wxGmtime_r(&time, &tmstruct); - - // should never happen - wxCHECK_MSG( tm, Tm(), _T("wxGmtime_r() failed") ); - } - else - { - tm = (struct tm *)NULL; - } - } - - if ( tm ) - { - // adjust the milliseconds - Tm tm2(*tm, tz); - long timeOnly = (m_time % MILLISECONDS_PER_DAY).ToLong(); - tm2.msec = (wxDateTime_t)(timeOnly % 1000); - return tm2; - } - //else: use generic code below - } - - // remember the time and do the calculations with the date only - this - // eliminates rounding errors of the floating point arithmetics - - wxLongLong timeMidnight = m_time + tz.GetOffset() * 1000; - - long timeOnly = (timeMidnight % MILLISECONDS_PER_DAY).ToLong(); - - // we want to always have positive time and timeMidnight to be really - // the midnight before it - if ( timeOnly < 0 ) - { - timeOnly = MILLISECONDS_PER_DAY + timeOnly; - } - - timeMidnight -= timeOnly; - - // calculate the Gregorian date from JDN for the midnight of our date: - // this will yield day, month (in 1..12 range) and year - - // actually, this is the JDN for the noon of the previous day - long jdn = (timeMidnight / MILLISECONDS_PER_DAY).ToLong() + EPOCH_JDN; - - // CREDIT: code below is by Scott E. Lee (but bugs are mine) - - wxASSERT_MSG( jdn > -2, _T("JDN out of range") ); - - // calculate the century - long temp = (jdn + JDN_OFFSET) * 4 - 1; - long century = temp / DAYS_PER_400_YEARS; - - // then the year and day of year (1 <= dayOfYear <= 366) - temp = ((temp % DAYS_PER_400_YEARS) / 4) * 4 + 3; - long year = (century * 100) + (temp / DAYS_PER_4_YEARS); - long dayOfYear = (temp % DAYS_PER_4_YEARS) / 4 + 1; - - // and finally the month and day of the month - temp = dayOfYear * 5 - 3; - long month = temp / DAYS_PER_5_MONTHS; - long day = (temp % DAYS_PER_5_MONTHS) / 5 + 1; - - // month is counted from March - convert to normal - if ( month < 10 ) - { - month += 3; - } - else - { - year += 1; - month -= 9; - } - - // year is offset by 4800 - year -= 4800; - - // check that the algorithm gave us something reasonable - wxASSERT_MSG( (0 < month) && (month <= 12), _T("invalid month") ); - wxASSERT_MSG( (1 <= day) && (day < 32), _T("invalid day") ); - - // construct Tm from these values - Tm tm; - tm.year = (int)year; - tm.mon = (Month)(month - 1); // algorithm yields 1 for January, not 0 - tm.mday = (wxDateTime_t)day; - tm.msec = (wxDateTime_t)(timeOnly % 1000); - timeOnly -= tm.msec; - timeOnly /= 1000; // now we have time in seconds - - tm.sec = (wxDateTime_t)(timeOnly % SEC_PER_MIN); - timeOnly -= tm.sec; - timeOnly /= SEC_PER_MIN; // now we have time in minutes - - tm.min = (wxDateTime_t)(timeOnly % MIN_PER_HOUR); - timeOnly -= tm.min; - - tm.hour = (wxDateTime_t)(timeOnly / MIN_PER_HOUR); - - return tm; -} - -wxDateTime& wxDateTime::SetYear(int year) -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - Tm tm(GetTm()); - tm.year = year; - Set(tm); - - return *this; -} - -wxDateTime& wxDateTime::SetMonth(Month month) -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - Tm tm(GetTm()); - tm.mon = month; - Set(tm); - - return *this; -} - -wxDateTime& wxDateTime::SetDay(wxDateTime_t mday) -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - Tm tm(GetTm()); - tm.mday = mday; - Set(tm); - - return *this; -} - -wxDateTime& wxDateTime::SetHour(wxDateTime_t hour) -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - Tm tm(GetTm()); - tm.hour = hour; - Set(tm); - - return *this; -} - -wxDateTime& wxDateTime::SetMinute(wxDateTime_t min) -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - Tm tm(GetTm()); - tm.min = min; - Set(tm); - - return *this; -} - -wxDateTime& wxDateTime::SetSecond(wxDateTime_t sec) -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - Tm tm(GetTm()); - tm.sec = sec; - Set(tm); - - return *this; -} - -wxDateTime& wxDateTime::SetMillisecond(wxDateTime_t millisecond) -{ - wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); - - // we don't need to use GetTm() for this one - m_time -= m_time % 1000l; - m_time += millisecond; - - return *this; -} - -// ---------------------------------------------------------------------------- -// wxDateTime arithmetics -// ---------------------------------------------------------------------------- - -wxDateTime& wxDateTime::Add(const wxDateSpan& diff) -{ - Tm tm(GetTm()); - - tm.year += diff.GetYears(); - tm.AddMonths(diff.GetMonths()); - - // check that the resulting date is valid - if ( tm.mday > GetNumOfDaysInMonth(tm.year, tm.mon) ) - { - // We suppose that when adding one month to Jan 31 we want to get Feb - // 28 (or 29), i.e. adding a month to the last day of the month should - // give the last day of the next month which is quite logical. - // - // Unfortunately, there is no logic way to understand what should - // Jan 30 + 1 month be - Feb 28 too or Feb 27 (assuming non leap year)? - // We make it Feb 28 (last day too), but it is highly questionable. - tm.mday = GetNumOfDaysInMonth(tm.year, tm.mon); - } - - tm.AddDays(diff.GetTotalDays()); - - Set(tm); - - wxASSERT_MSG( IsSameTime(tm), - _T("Add(wxDateSpan) shouldn't modify time") ); - - return *this; -} - -// ---------------------------------------------------------------------------- -// Weekday and monthday stuff -// ---------------------------------------------------------------------------- - -// convert Sun, Mon, ..., Sat into 6, 0, ..., 5 -static inline int ConvertWeekDayToMondayBase(int wd) -{ - return wd == wxDateTime::Sun ? 6 : wd - 1; -} - -/* static */ -wxDateTime -wxDateTime::SetToWeekOfYear(int year, wxDateTime_t numWeek, WeekDay wd) -{ - wxASSERT_MSG( numWeek > 0, - _T("invalid week number: weeks are counted from 1") ); - - // Jan 4 always lies in the 1st week of the year - wxDateTime dt(4, Jan, year); - dt.SetToWeekDayInSameWeek(wd); - dt += wxDateSpan::Weeks(numWeek - 1); - - return dt; -} - -#if WXWIN_COMPATIBILITY_2_6 -// use a separate function to avoid warnings about using deprecated -// SetToTheWeek in GetWeek below -static wxDateTime -SetToTheWeek(int year, - wxDateTime::wxDateTime_t numWeek, - wxDateTime::WeekDay weekday, - wxDateTime::WeekFlags flags) -{ - // Jan 4 always lies in the 1st week of the year - wxDateTime dt(4, wxDateTime::Jan, year); - dt.SetToWeekDayInSameWeek(weekday, flags); - dt += wxDateSpan::Weeks(numWeek - 1); - - return dt; -} - -bool wxDateTime::SetToTheWeek(wxDateTime_t numWeek, - WeekDay weekday, - WeekFlags flags) -{ - int year = GetYear(); - *this = ::SetToTheWeek(year, numWeek, weekday, flags); - if ( GetYear() != year ) - { - // oops... numWeek was too big - return false; - } - - return true; -} - -wxDateTime wxDateTime::GetWeek(wxDateTime_t numWeek, - WeekDay weekday, - WeekFlags flags) const -{ - return ::SetToTheWeek(GetYear(), numWeek, weekday, flags); -} -#endif // WXWIN_COMPATIBILITY_2_6 - -wxDateTime& wxDateTime::SetToLastMonthDay(Month month, - int year) -{ - // take the current month/year if none specified - if ( year == Inv_Year ) - year = GetYear(); - if ( month == Inv_Month ) - month = GetMonth(); - - return Set(GetNumOfDaysInMonth(year, month), month, year); -} - -wxDateTime& wxDateTime::SetToWeekDayInSameWeek(WeekDay weekday, WeekFlags flags) -{ - wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") ); - - int wdayDst = weekday, - wdayThis = GetWeekDay(); - if ( wdayDst == wdayThis ) - { - // nothing to do - return *this; - } - - if ( flags == Default_First ) - { - flags = GetCountry() == USA ? Sunday_First : Monday_First; - } - - // the logic below based on comparing weekday and wdayThis works if Sun (0) - // is the first day in the week, but breaks down for Monday_First case so - // we adjust the week days in this case - if ( flags == Monday_First ) - { - if ( wdayThis == Sun ) - wdayThis += 7; - if ( wdayDst == Sun ) - wdayDst += 7; - } - //else: Sunday_First, nothing to do - - // go forward or back in time to the day we want - if ( wdayDst < wdayThis ) - { - return Subtract(wxDateSpan::Days(wdayThis - wdayDst)); - } - else // weekday > wdayThis - { - return Add(wxDateSpan::Days(wdayDst - wdayThis)); - } -} - -wxDateTime& wxDateTime::SetToNextWeekDay(WeekDay weekday) -{ - wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") ); - - int diff; - WeekDay wdayThis = GetWeekDay(); - if ( weekday == wdayThis ) - { - // nothing to do - return *this; - } - else if ( weekday < wdayThis ) - { - // need to advance a week - diff = 7 - (wdayThis - weekday); - } - else // weekday > wdayThis - { - diff = weekday - wdayThis; - } - - return Add(wxDateSpan::Days(diff)); -} - -wxDateTime& wxDateTime::SetToPrevWeekDay(WeekDay weekday) -{ - wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") ); - - int diff; - WeekDay wdayThis = GetWeekDay(); - if ( weekday == wdayThis ) - { - // nothing to do - return *this; - } - else if ( weekday > wdayThis ) - { - // need to go to previous week - diff = 7 - (weekday - wdayThis); - } - else // weekday < wdayThis - { - diff = wdayThis - weekday; - } - - return Subtract(wxDateSpan::Days(diff)); -} - -bool wxDateTime::SetToWeekDay(WeekDay weekday, - int n, - Month month, - int year) -{ - wxCHECK_MSG( weekday != Inv_WeekDay, false, _T("invalid weekday") ); - - // we don't check explicitly that -5 <= n <= 5 because we will return false - // anyhow in such case - but may be should still give an assert for it? - - // take the current month/year if none specified - ReplaceDefaultYearMonthWithCurrent(&year, &month); - - wxDateTime dt; - - // TODO this probably could be optimised somehow... - - if ( n > 0 ) - { - // get the first day of the month - dt.Set(1, month, year); - - // get its wday - WeekDay wdayFirst = dt.GetWeekDay(); - - // go to the first weekday of the month - int diff = weekday - wdayFirst; - if ( diff < 0 ) - diff += 7; - - // add advance n-1 weeks more - diff += 7*(n - 1); - - dt += wxDateSpan::Days(diff); - } - else // count from the end of the month - { - // get the last day of the month - dt.SetToLastMonthDay(month, year); - - // get its wday - WeekDay wdayLast = dt.GetWeekDay(); - - // go to the last weekday of the month - int diff = wdayLast - weekday; - if ( diff < 0 ) - diff += 7; - - // and rewind n-1 weeks from there - diff += 7*(-n - 1); - - dt -= wxDateSpan::Days(diff); - } - - // check that it is still in the same month - if ( dt.GetMonth() == month ) - { - *this = dt; - - return true; - } - else - { - // no such day in this month - return false; - } -} - -static inline -wxDateTime::wxDateTime_t GetDayOfYearFromTm(const wxDateTime::Tm& tm) -{ - return (wxDateTime::wxDateTime_t)(gs_cumulatedDays[wxDateTime::IsLeapYear(tm.year)][tm.mon] + tm.mday); -} - -wxDateTime::wxDateTime_t wxDateTime::GetDayOfYear(const TimeZone& tz) const -{ - return GetDayOfYearFromTm(GetTm(tz)); -} - -wxDateTime::wxDateTime_t -wxDateTime::GetWeekOfYear(wxDateTime::WeekFlags flags, const TimeZone& tz) const -{ - if ( flags == Default_First ) - { - flags = GetCountry() == USA ? Sunday_First : Monday_First; - } - - Tm tm(GetTm(tz)); - wxDateTime_t nDayInYear = GetDayOfYearFromTm(tm); - - int wdTarget = GetWeekDay(tz); - int wdYearStart = wxDateTime(1, Jan, GetYear()).GetWeekDay(); - int week; - if ( flags == Sunday_First ) - { - // FIXME: First week is not calculated correctly. - week = (nDayInYear - wdTarget + 7) / 7; - if ( wdYearStart == Wed || wdYearStart == Thu ) - week++; - } - else // week starts with monday - { - // adjust the weekdays to non-US style. - wdYearStart = ConvertWeekDayToMondayBase(wdYearStart); - wdTarget = ConvertWeekDayToMondayBase(wdTarget); - - // quoting from http://www.cl.cam.ac.uk/~mgk25/iso-time.html: - // - // Week 01 of a year is per definition the first week that has the - // Thursday in this year, which is equivalent to the week that - // contains the fourth day of January. In other words, the first - // week of a new year is the week that has the majority of its - // days in the new year. Week 01 might also contain days from the - // previous year and the week before week 01 of a year is the last - // week (52 or 53) of the previous year even if it contains days - // from the new year. A week starts with Monday (day 1) and ends - // with Sunday (day 7). - // - - // if Jan 1 is Thursday or less, it is in the first week of this year - if ( wdYearStart < 4 ) - { - // count the number of entire weeks between Jan 1 and this date - week = (nDayInYear + wdYearStart + 6 - wdTarget)/7; - - // be careful to check for overflow in the next year - if ( week == 53 && tm.mday - wdTarget > 28 ) - week = 1; - } - else // Jan 1 is in the last week of the previous year - { - // check if we happen to be at the last week of previous year: - if ( tm.mon == Jan && tm.mday < 8 - wdYearStart ) - week = wxDateTime(31, Dec, GetYear()-1).GetWeekOfYear(); - else - week = (nDayInYear + wdYearStart - 1 - wdTarget)/7; - } - } - - return (wxDateTime::wxDateTime_t)week; -} - -wxDateTime::wxDateTime_t wxDateTime::GetWeekOfMonth(wxDateTime::WeekFlags flags, - const TimeZone& tz) const -{ - Tm tm = GetTm(tz); - const wxDateTime dateFirst = wxDateTime(1, tm.mon, tm.year); - const wxDateTime::WeekDay wdFirst = dateFirst.GetWeekDay(); - - if ( flags == Default_First ) - { - flags = GetCountry() == USA ? Sunday_First : Monday_First; - } - - // compute offset of dateFirst from the beginning of the week - int firstOffset; - if ( flags == Sunday_First ) - firstOffset = wdFirst - Sun; - else - firstOffset = wdFirst == Sun ? DAYS_PER_WEEK - 1 : wdFirst - Mon; - - return (wxDateTime::wxDateTime_t)((tm.mday - 1 + firstOffset)/7 + 1); -} - -wxDateTime& wxDateTime::SetToYearDay(wxDateTime::wxDateTime_t yday) -{ - int year = GetYear(); - wxDATETIME_CHECK( (0 < yday) && (yday <= GetNumberOfDays(year)), - _T("invalid year day") ); - - bool isLeap = IsLeapYear(year); - for ( Month mon = Jan; mon < Inv_Month; wxNextMonth(mon) ) - { - // for Dec, we can't compare with gs_cumulatedDays[mon + 1], but we - // don't need it neither - because of the CHECK above we know that - // yday lies in December then - if ( (mon == Dec) || (yday <= gs_cumulatedDays[isLeap][mon + 1]) ) - { - Set((wxDateTime::wxDateTime_t)(yday - gs_cumulatedDays[isLeap][mon]), mon, year); - - break; - } - } - - return *this; -} - -// ---------------------------------------------------------------------------- -// Julian day number conversion and related stuff -// ---------------------------------------------------------------------------- - -double wxDateTime::GetJulianDayNumber() const -{ - return m_time.ToDouble() / MILLISECONDS_PER_DAY + EPOCH_JDN + 0.5; -} - -double wxDateTime::GetRataDie() const -{ - // March 1 of the year 0 is Rata Die day -306 and JDN 1721119.5 - return GetJulianDayNumber() - 1721119.5 - 306; -} - -// ---------------------------------------------------------------------------- -// timezone and DST stuff -// ---------------------------------------------------------------------------- - -int wxDateTime::IsDST(wxDateTime::Country country) const -{ - wxCHECK_MSG( country == Country_Default, -1, - _T("country support not implemented") ); - - // use the C RTL for the dates in the standard range - time_t timet = GetTicks(); - if ( timet != (time_t)-1 ) - { - struct tm tmstruct; - tm *tm = wxLocaltime_r(&timet, &tmstruct); - - wxCHECK_MSG( tm, -1, _T("wxLocaltime_r() failed") ); - - return tm->tm_isdst; - } - else - { - int year = GetYear(); - - if ( !IsDSTApplicable(year, country) ) - { - // no DST time in this year in this country - return -1; - } - - return IsBetween(GetBeginDST(year, country), GetEndDST(year, country)); - } -} - -wxDateTime& wxDateTime::MakeTimezone(const TimeZone& tz, bool noDST) -{ - long secDiff = GetTimeZone() + tz.GetOffset(); - - // we need to know whether DST is or not in effect for this date unless - // the test disabled by the caller - if ( !noDST && (IsDST() == 1) ) - { - // FIXME we assume that the DST is always shifted by 1 hour - secDiff -= 3600; - } - - return Add(wxTimeSpan::Seconds(secDiff)); -} - -wxDateTime& wxDateTime::MakeFromTimezone(const TimeZone& tz, bool noDST) -{ - long secDiff = GetTimeZone() + tz.GetOffset(); - - // we need to know whether DST is or not in effect for this date unless - // the test disabled by the caller - if ( !noDST && (IsDST() == 1) ) - { - // FIXME we assume that the DST is always shifted by 1 hour - secDiff -= 3600; - } - - return Subtract(wxTimeSpan::Seconds(secDiff)); -} - -// ---------------------------------------------------------------------------- -// wxDateTime to/from text representations -// ---------------------------------------------------------------------------- - -wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const -{ - wxCHECK_MSG( format, wxEmptyString, _T("NULL format in wxDateTime::Format") ); - - time_t time = GetTicks(); - - // we have to use our own implementation if the date is out of range of - // strftime() or if we use non standard specificators -#ifdef HAVE_STRFTIME - if ( (time != (time_t)-1) && !wxStrstr(format, _T("%l")) ) - { - // use strftime() - struct tm tmstruct; - struct tm *tm; - if ( tz.GetOffset() == -GetTimeZone() ) - { - // we are working with local time - tm = wxLocaltime_r(&time, &tmstruct); - - // should never happen - wxCHECK_MSG( tm, wxEmptyString, _T("wxLocaltime_r() failed") ); - } - else - { - time += (int)tz.GetOffset(); - -#if defined(__VMS__) || defined(__WATCOMC__) // time is unsigned so avoid warning - int time2 = (int) time; - if ( time2 >= 0 ) -#else - if ( time >= 0 ) -#endif - { - tm = wxGmtime_r(&time, &tmstruct); - - // should never happen - wxCHECK_MSG( tm, wxEmptyString, _T("wxGmtime_r() failed") ); - } - else - { - tm = (struct tm *)NULL; - } - } - - if ( tm ) - { - return CallStrftime(format, tm); - } - } - //else: use generic code below -#endif // HAVE_STRFTIME - - // we only parse ANSI C format specifications here, no POSIX 2 - // complications, no GNU extensions but we do add support for a "%l" format - // specifier allowing to get the number of milliseconds - Tm tm = GetTm(tz); - - // used for calls to strftime() when we only deal with time - struct tm tmTimeOnly; - memset(&tmTimeOnly, 0, sizeof(tmTimeOnly)); - tmTimeOnly.tm_hour = tm.hour; - tmTimeOnly.tm_min = tm.min; - tmTimeOnly.tm_sec = tm.sec; - tmTimeOnly.tm_wday = 0; - tmTimeOnly.tm_yday = 0; - tmTimeOnly.tm_mday = 1; // any date will do, use 1976-01-01 - tmTimeOnly.tm_mon = 0; - tmTimeOnly.tm_year = 76; - tmTimeOnly.tm_isdst = 0; // no DST, we adjust for tz ourselves - - wxString tmp, res, fmt; - for ( const wxChar *p = format; *p; p++ ) - { - if ( *p != _T('%') ) - { - // copy as is - res += *p; - - continue; - } - - // set the default format - switch ( *++p ) - { - case _T('Y'): // year has 4 digits - fmt = _T("%04d"); - break; - - case _T('j'): // day of year has 3 digits - case _T('l'): // milliseconds have 3 digits - fmt = _T("%03d"); - break; - - case _T('w'): // week day as number has only one - fmt = _T("%d"); - break; - - default: - // it's either another valid format specifier in which case - // the format is "%02d" (for all the rest) or we have the - // field width preceding the format in which case it will - // override the default format anyhow - fmt = _T("%02d"); - } - - bool restart = true; - while ( restart ) - { - restart = false; - - // start of the format specification - switch ( *p ) - { - case _T('a'): // a weekday name - case _T('A'): - // second parameter should be true for abbreviated names - res += GetWeekDayName(tm.GetWeekDay(), - *p == _T('a') ? Name_Abbr : Name_Full); - break; - - case _T('b'): // a month name - case _T('B'): - res += GetMonthName(tm.mon, - *p == _T('b') ? Name_Abbr : Name_Full); - break; - - case _T('c'): // locale default date and time representation - case _T('x'): // locale default date representation -#ifdef HAVE_STRFTIME - // - // the problem: there is no way to know what do these format - // specifications correspond to for the current locale. - // - // the solution: use a hack and still use strftime(): first - // find the YEAR which is a year in the strftime() range (1970 - // - 2038) whose Jan 1 falls on the same week day as the Jan 1 - // of the real year. Then make a copy of the format and - // replace all occurrences of YEAR in it with some unique - // string not appearing anywhere else in it, then use - // strftime() to format the date in year YEAR and then replace - // YEAR back by the real year and the unique replacement - // string back with YEAR. Notice that "all occurrences of YEAR" - // means all occurrences of 4 digit as well as 2 digit form! - // - // the bugs: we assume that neither of %c nor %x contains any - // fields which may change between the YEAR and real year. For - // example, the week number (%U, %W) and the day number (%j) - // will change if one of these years is leap and the other one - // is not! - { - // find the YEAR: normally, for any year X, Jan 1 or the - // year X + 28 is the same weekday as Jan 1 of X (because - // the weekday advances by 1 for each normal X and by 2 - // for each leap X, hence by 5 every 4 years or by 35 - // which is 0 mod 7 every 28 years) but this rule breaks - // down if there are years between X and Y which are - // divisible by 4 but not leap (i.e. divisible by 100 but - // not 400), hence the correction. - - int yearReal = GetYear(tz); - int mod28 = yearReal % 28; - - // be careful to not go too far - we risk to leave the - // supported range - int year; - if ( mod28 < 10 ) - { - year = 1988 + mod28; // 1988 == 0 (mod 28) - } - else - { - year = 1970 + mod28 - 10; // 1970 == 10 (mod 28) - } - - int nCentury = year / 100, - nCenturyReal = yearReal / 100; - - // need to adjust for the years divisble by 400 which are - // not leap but are counted like leap ones if we just take - // the number of centuries in between for nLostWeekDays - int nLostWeekDays = (nCentury - nCenturyReal) - - (nCentury / 4 - nCenturyReal / 4); - - // we have to gain back the "lost" weekdays: note that the - // effect of this loop is to not do anything to - // nLostWeekDays (which we won't use any more), but to - // (indirectly) set the year correctly - while ( (nLostWeekDays % 7) != 0 ) - { - nLostWeekDays += year++ % 4 ? 1 : 2; - } - - // Keep year below 2000 so the 2digit year number - // can never match the month or day of the month - if (year>=2000) year-=28; - // at any rate, we couldn't go further than 1988 + 9 + 28! - wxASSERT_MSG( year < 2030, - _T("logic error in wxDateTime::Format") ); - - wxString strYear, strYear2; - strYear.Printf(_T("%d"), year); - strYear2.Printf(_T("%d"), year % 100); - - // find four strings not occurring in format (this is surely - // not the optimal way of doing it... improvements welcome!) - wxString fmt2 = format; - wxString replacement,replacement2,replacement3,replacement4; - for (int rnr=1; rnr<5 ; rnr++) - { - wxString r = (wxChar)-rnr; - while ( fmt2.Find(r) != wxNOT_FOUND ) - { - r << (wxChar)-rnr; - } - - switch (rnr) - { - case 1: replacement=r; break; - case 2: replacement2=r; break; - case 3: replacement3=r; break; - case 4: replacement4=r; break; - } - } - // replace all occurrences of year with it - bool wasReplaced = fmt2.Replace(strYear, replacement) > 0; - // evaluation order ensures we always attempt the replacement. - wasReplaced = (fmt2.Replace(strYear2, replacement2) > 0) || wasReplaced; - - // use strftime() to format the same date but in supported - // year - // - // NB: we assume that strftime() doesn't check for the - // date validity and will happily format the date - // corresponding to Feb 29 of a non leap year (which - // may happen if yearReal was leap and year is not) - struct tm tmAdjusted; - InitTm(tmAdjusted); - tmAdjusted.tm_hour = tm.hour; - tmAdjusted.tm_min = tm.min; - tmAdjusted.tm_sec = tm.sec; - tmAdjusted.tm_wday = tm.GetWeekDay(); - tmAdjusted.tm_yday = GetDayOfYear(); - tmAdjusted.tm_mday = tm.mday; - tmAdjusted.tm_mon = tm.mon; - tmAdjusted.tm_year = year - 1900; - tmAdjusted.tm_isdst = 0; // no DST, already adjusted - wxString str = CallStrftime(*p == _T('c') ? _T("%c") - : _T("%x"), - &tmAdjusted); - - // now replace the occurrence of 1999 with the real year - // we do this in two stages to stop the 2 digit year - // matching any substring of the 4 digit year. - // Any day,month hours and minutes components should be safe due - // to ensuring the range of the years. - wxString strYearReal, strYearReal2; - strYearReal.Printf(_T("%04d"), yearReal); - strYearReal2.Printf(_T("%02d"), yearReal % 100); - str.Replace(strYear, replacement3); - str.Replace(strYear2,replacement4); - str.Replace(replacement3, strYearReal); - str.Replace(replacement4, strYearReal2); - - // and replace back all occurrences of replacement string - if ( wasReplaced ) - { - str.Replace(replacement2, strYear2); - str.Replace(replacement, strYear); - } - - res += str; - } -#else // !HAVE_STRFTIME - // Use "%m/%d/%y %H:%M:%S" format instead - res += wxString::Format(wxT("%02d/%02d/%04d %02d:%02d:%02d"), - tm.mon+1,tm.mday, tm.year, tm.hour, tm.min, tm.sec); -#endif // HAVE_STRFTIME/!HAVE_STRFTIME - break; - - case _T('d'): // day of a month (01-31) - res += wxString::Format(fmt, tm.mday); - break; - - case _T('H'): // hour in 24h format (00-23) - res += wxString::Format(fmt, tm.hour); - break; - - case _T('I'): // hour in 12h format (01-12) - { - // 24h -> 12h, 0h -> 12h too - int hour12 = tm.hour > 12 ? tm.hour - 12 - : tm.hour ? tm.hour : 12; - res += wxString::Format(fmt, hour12); - } - break; - - case _T('j'): // day of the year - res += wxString::Format(fmt, GetDayOfYear(tz)); - break; - - case _T('l'): // milliseconds (NOT STANDARD) - res += wxString::Format(fmt, GetMillisecond(tz)); - break; - - case _T('m'): // month as a number (01-12) - res += wxString::Format(fmt, tm.mon + 1); - break; - - case _T('M'): // minute as a decimal number (00-59) - res += wxString::Format(fmt, tm.min); - break; - - case _T('p'): // AM or PM string -#ifdef HAVE_STRFTIME - res += CallStrftime(_T("%p"), &tmTimeOnly); -#else // !HAVE_STRFTIME - res += (tmTimeOnly.tm_hour > 12) ? wxT("pm") : wxT("am"); -#endif // HAVE_STRFTIME/!HAVE_STRFTIME - break; - - case _T('S'): // second as a decimal number (00-61) - res += wxString::Format(fmt, tm.sec); - break; - - case _T('U'): // week number in the year (Sunday 1st week day) - res += wxString::Format(fmt, GetWeekOfYear(Sunday_First, tz)); - break; - - case _T('W'): // week number in the year (Monday 1st week day) - res += wxString::Format(fmt, GetWeekOfYear(Monday_First, tz)); - break; - - case _T('w'): // weekday as a number (0-6), Sunday = 0 - res += wxString::Format(fmt, tm.GetWeekDay()); - break; - - // case _T('x'): -- handled with "%c" - - case _T('X'): // locale default time representation - // just use strftime() to format the time for us -#ifdef HAVE_STRFTIME - res += CallStrftime(_T("%X"), &tmTimeOnly); -#else // !HAVE_STRFTIME - res += wxString::Format(wxT("%02d:%02d:%02d"),tm.hour, tm.min, tm.sec); -#endif // HAVE_STRFTIME/!HAVE_STRFTIME - break; - - case _T('y'): // year without century (00-99) - res += wxString::Format(fmt, tm.year % 100); - break; - - case _T('Y'): // year with century - res += wxString::Format(fmt, tm.year); - break; - - case _T('Z'): // timezone name -#ifdef HAVE_STRFTIME - res += CallStrftime(_T("%Z"), &tmTimeOnly); -#endif - break; - - default: - // is it the format width? - for( fmt.clear(); - *p == _T('-') || *p == _T('+') || - *p == _T(' ') || wxIsdigit(*p); - ++p ) - { - fmt += *p; - } - - if ( !fmt.empty() ) - { - // we've only got the flags and width so far in fmt - fmt.Prepend(_T('%')); - fmt.Append(_T('d')); - - restart = true; - - break; - } - - // no, it wasn't the width - wxFAIL_MSG(_T("unknown format specificator")); - - // fall through and just copy it nevertheless - - case _T('%'): // a percent sign - res += *p; - break; - - case 0: // the end of string - wxFAIL_MSG(_T("missing format at the end of string")); - - // just put the '%' which was the last char in format - res += _T('%'); - break; - } - } - } - - return res; -} - -// this function parses a string in (strict) RFC 822 format: see the section 5 -// of the RFC for the detailed description, but briefly it's something of the -// form "Sat, 18 Dec 1999 00:48:30 +0100" -// -// this function is "strict" by design - it must reject anything except true -// RFC822 time specs. -// -// TODO a great candidate for using reg exps -const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) -{ - wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); - - const wxChar *p = date; - const wxChar *comma = wxStrchr(p, _T(',')); - if ( comma ) - { - // the part before comma is the weekday - - // skip it for now - we don't use but might check that it really - // corresponds to the specfied date - p = comma + 1; - - if ( *p != _T(' ') ) - { - wxLogDebug(_T("no space after weekday in RFC822 time spec")); - - return (wxChar *)NULL; - } - - p++; // skip space - } - - // the following 1 or 2 digits are the day number - if ( !wxIsdigit(*p) ) - { - wxLogDebug(_T("day number expected in RFC822 time spec, none found")); - - return (wxChar *)NULL; - } - - wxDateTime_t day = (wxDateTime_t)(*p++ - _T('0')); - if ( wxIsdigit(*p) ) - { - day *= 10; - day = (wxDateTime_t)(day + (*p++ - _T('0'))); - } - - if ( *p++ != _T(' ') ) - { - return (wxChar *)NULL; - } - - // the following 3 letters specify the month - wxString monName(p, 3); - Month mon; - if ( monName == _T("Jan") ) - mon = Jan; - else if ( monName == _T("Feb") ) - mon = Feb; - else if ( monName == _T("Mar") ) - mon = Mar; - else if ( monName == _T("Apr") ) - mon = Apr; - else if ( monName == _T("May") ) - mon = May; - else if ( monName == _T("Jun") ) - mon = Jun; - else if ( monName == _T("Jul") ) - mon = Jul; - else if ( monName == _T("Aug") ) - mon = Aug; - else if ( monName == _T("Sep") ) - mon = Sep; - else if ( monName == _T("Oct") ) - mon = Oct; - else if ( monName == _T("Nov") ) - mon = Nov; - else if ( monName == _T("Dec") ) - mon = Dec; - else - { - wxLogDebug(_T("Invalid RFC 822 month name '%s'"), monName.c_str()); - - return (wxChar *)NULL; - } - - p += 3; - - if ( *p++ != _T(' ') ) - { - return (wxChar *)NULL; - } - - // next is the year - if ( !wxIsdigit(*p) ) - { - // no year? - return (wxChar *)NULL; - } - - int year = *p++ - _T('0'); - - if ( !wxIsdigit(*p) ) - { - // should have at least 2 digits in the year - return (wxChar *)NULL; - } - - year *= 10; - year += *p++ - _T('0'); - - // is it a 2 digit year (as per original RFC 822) or a 4 digit one? - if ( wxIsdigit(*p) ) - { - year *= 10; - year += *p++ - _T('0'); - - if ( !wxIsdigit(*p) ) - { - // no 3 digit years please - return (wxChar *)NULL; - } - - year *= 10; - year += *p++ - _T('0'); - } - - if ( *p++ != _T(' ') ) - { - return (wxChar *)NULL; - } - - // time is in the format hh:mm:ss and seconds are optional - if ( !wxIsdigit(*p) ) - { - return (wxChar *)NULL; - } - - wxDateTime_t hour = (wxDateTime_t)(*p++ - _T('0')); - - if ( !wxIsdigit(*p) ) - { - return (wxChar *)NULL; - } - - hour *= 10; - hour = (wxDateTime_t)(hour + (*p++ - _T('0'))); - - if ( *p++ != _T(':') ) - { - return (wxChar *)NULL; - } - - if ( !wxIsdigit(*p) ) - { - return (wxChar *)NULL; - } - - wxDateTime_t min = (wxDateTime_t)(*p++ - _T('0')); - - if ( !wxIsdigit(*p) ) - { - return (wxChar *)NULL; - } - - min *= 10; - min = (wxDateTime_t)(min + *p++ - _T('0')); - - wxDateTime_t sec = 0; - if ( *p == _T(':') ) - { - p++; - if ( !wxIsdigit(*p) ) - { - return (wxChar *)NULL; - } - - sec = (wxDateTime_t)(*p++ - _T('0')); - - if ( !wxIsdigit(*p) ) - { - return (wxChar *)NULL; - } - - sec *= 10; - sec = (wxDateTime_t)(sec + *p++ - _T('0')); - } - - if ( *p++ != _T(' ') ) - { - return (wxChar *)NULL; - } - - // and now the interesting part: the timezone - int offset wxDUMMY_INITIALIZE(0); - if ( *p == _T('-') || *p == _T('+') ) - { - // the explicit offset given: it has the form of hhmm - bool plus = *p++ == _T('+'); - - if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) ) - { - return (wxChar *)NULL; - } - - // hours - offset = MIN_PER_HOUR*(10*(*p - _T('0')) + (*(p + 1) - _T('0'))); - - p += 2; - - if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) ) - { - return (wxChar *)NULL; - } - - // minutes - offset += 10*(*p - _T('0')) + (*(p + 1) - _T('0')); - - if ( !plus ) - { - offset = -offset; - } - - p += 2; - } - else - { - // the symbolic timezone given: may be either military timezone or one - // of standard abbreviations - if ( !*(p + 1) ) - { - // military: Z = UTC, J unused, A = -1, ..., Y = +12 - static const int offsets[26] = - { - //A B C D E F G H I J K L M - -1, -2, -3, -4, -5, -6, -7, -8, -9, 0, -10, -11, -12, - //N O P R Q S T U V W Z Y Z - +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, 0 - }; - - if ( *p < _T('A') || *p > _T('Z') || *p == _T('J') ) - { - wxLogDebug(_T("Invalid militaty timezone '%c'"), *p); - - return (wxChar *)NULL; - } - - offset = offsets[*p++ - _T('A')]; - } - else - { - // abbreviation - wxString tz = p; - if ( tz == _T("UT") || tz == _T("UTC") || tz == _T("GMT") ) - offset = 0; - else if ( tz == _T("AST") ) - offset = AST - GMT0; - else if ( tz == _T("ADT") ) - offset = ADT - GMT0; - else if ( tz == _T("EST") ) - offset = EST - GMT0; - else if ( tz == _T("EDT") ) - offset = EDT - GMT0; - else if ( tz == _T("CST") ) - offset = CST - GMT0; - else if ( tz == _T("CDT") ) - offset = CDT - GMT0; - else if ( tz == _T("MST") ) - offset = MST - GMT0; - else if ( tz == _T("MDT") ) - offset = MDT - GMT0; - else if ( tz == _T("PST") ) - offset = PST - GMT0; - else if ( tz == _T("PDT") ) - offset = PDT - GMT0; - else - { - wxLogDebug(_T("Unknown RFC 822 timezone '%s'"), p); - - return (wxChar *)NULL; - } - - p += tz.length(); - } - - // make it minutes - offset *= MIN_PER_HOUR; - } - - // the spec was correct, construct the date from the values we found - Set(day, mon, year, hour, min, sec); - MakeFromTimezone(TimeZone::Make(offset*SEC_PER_MIN)); - - return p; -} - -#ifdef __WINDOWS__ - -// returns the string containing strftime() format used for short dates in the -// current locale or an empty string -static wxString GetLocaleDateFormat() -{ - wxString fmtWX; - - // there is no setlocale() under Windows CE, so just always query the - // system there -#ifndef __WXWINCE__ - if ( strcmp(setlocale(LC_ALL, NULL), "C") != 0 ) -#endif - { - // The locale was programatically set to non-C. We assume that this was - // done using wxLocale, in which case thread's current locale is also - // set to correct LCID value and we can use GetLocaleInfo to determine - // the correct formatting string: -#ifdef __WXWINCE__ - LCID lcid = LOCALE_USER_DEFAULT; -#else - LCID lcid = GetThreadLocale(); -#endif - // according to MSDN 80 chars is max allowed for short date format - wxChar fmt[81]; - if ( ::GetLocaleInfo(lcid, LOCALE_SSHORTDATE, fmt, WXSIZEOF(fmt)) ) - { - wxChar chLast = _T('\0'); - size_t lastCount = 0; - for ( const wxChar *p = fmt; /* NUL handled inside */; p++ ) - { - if ( *p == chLast ) - { - lastCount++; - continue; - } - - switch ( *p ) - { - // these characters come in groups, start counting them - case _T('d'): - case _T('M'): - case _T('y'): - case _T('g'): - chLast = *p; - lastCount = 1; - break; - - default: - // first deal with any special characters we have had - if ( lastCount ) - { - switch ( chLast ) - { - case _T('d'): - switch ( lastCount ) - { - case 1: // d - case 2: // dd - // these two are the same as we - // don't distinguish between 1 and - // 2 digits for days - fmtWX += _T("%d"); - break; - - case 3: // ddd - fmtWX += _T("%a"); - break; - - case 4: // dddd - fmtWX += _T("%A"); - break; - - default: - wxFAIL_MSG( _T("too many 'd's") ); - } - break; - - case _T('M'): - switch ( lastCount ) - { - case 1: // M - case 2: // MM - // as for 'd' and 'dd' above - fmtWX += _T("%m"); - break; - - case 3: - fmtWX += _T("%b"); - break; - - case 4: - fmtWX += _T("%B"); - break; - - default: - wxFAIL_MSG( _T("too many 'M's") ); - } - break; - - case _T('y'): - switch ( lastCount ) - { - case 1: // y - case 2: // yy - fmtWX += _T("%y"); - break; - - case 4: // yyyy - fmtWX += _T("%Y"); - break; - - default: - wxFAIL_MSG( _T("wrong number of 'y's") ); - } - break; - - case _T('g'): - // strftime() doesn't have era string, - // ignore this format - wxASSERT_MSG( lastCount <= 2, - _T("too many 'g's") ); - break; - - default: - wxFAIL_MSG( _T("unreachable") ); - } - - chLast = _T('\0'); - lastCount = 0; - } - - // not a special character so must be just a separator, - // treat as is - if ( *p != _T('\0') ) - { - if ( *p == _T('%') ) - { - // this one needs to be escaped - fmtWX += _T('%'); - } - - fmtWX += *p; - } - } - - if ( *p == _T('\0') ) - break; - } - } - //else: GetLocaleInfo() failed, leave fmtDate value unchanged and - // try our luck with the default formats - } - //else: default C locale, default formats should work - - return fmtWX; -} - -#endif // __WINDOWS__ - -const wxChar *wxDateTime::ParseFormat(const wxChar *date, - const wxChar *format, - const wxDateTime& dateDef) -{ - wxCHECK_MSG( date && format, (wxChar *)NULL, - _T("NULL pointer in wxDateTime::ParseFormat()") ); - - wxString str; - unsigned long num; - - // what fields have we found? - bool haveWDay = false, - haveYDay = false, - haveDay = false, - haveMon = false, - haveYear = false, - haveHour = false, - haveMin = false, - haveSec = false; - - bool hourIsIn12hFormat = false, // or in 24h one? - isPM = false; // AM by default - - // and the value of the items we have (init them to get rid of warnings) - wxDateTime_t sec = 0, - min = 0, - hour = 0; - WeekDay wday = Inv_WeekDay; - wxDateTime_t yday = 0, - mday = 0; - wxDateTime::Month mon = Inv_Month; - int year = 0; - - const wxChar *input = date; - for ( const wxChar *fmt = format; *fmt; fmt++ ) - { - if ( *fmt != _T('%') ) - { - if ( wxIsspace(*fmt) ) - { - // a white space in the format string matches 0 or more white - // spaces in the input - while ( wxIsspace(*input) ) - { - input++; - } - } - else // !space - { - // any other character (not whitespace, not '%') must be - // matched by itself in the input - if ( *input++ != *fmt ) - { - // no match - return (wxChar *)NULL; - } - } - - // done with this format char - continue; - } - - // start of a format specification - - // parse the optional width - size_t width = 0; - while ( wxIsdigit(*++fmt) ) - { - width *= 10; - width += *fmt - _T('0'); - } - - // the default widths for the various fields - if ( !width ) - { - switch ( *fmt ) - { - case _T('Y'): // year has 4 digits - width = 4; - break; - - case _T('j'): // day of year has 3 digits - case _T('l'): // milliseconds have 3 digits - width = 3; - break; - - case _T('w'): // week day as number has only one - width = 1; - break; - - default: - // default for all other fields - width = 2; - } - } - - // then the format itself - switch ( *fmt ) - { - case _T('a'): // a weekday name - case _T('A'): - { - int flag = *fmt == _T('a') ? Name_Abbr : Name_Full; - wday = GetWeekDayFromName(GetAlphaToken(input), flag); - if ( wday == Inv_WeekDay ) - { - // no match - return (wxChar *)NULL; - } - } - haveWDay = true; - break; - - case _T('b'): // a month name - case _T('B'): - { - int flag = *fmt == _T('b') ? Name_Abbr : Name_Full; - mon = GetMonthFromName(GetAlphaToken(input), flag); - if ( mon == Inv_Month ) - { - // no match - return (wxChar *)NULL; - } - } - haveMon = true; - break; - - case _T('c'): // locale default date and time representation - { - wxDateTime dt; - - // this is the format which corresponds to ctime() output - // and strptime("%c") should parse it, so try it first - static const wxChar *fmtCtime = _T("%a %b %d %H:%M:%S %Y"); - - const wxChar *result = dt.ParseFormat(input, fmtCtime); - if ( !result ) - { - result = dt.ParseFormat(input, _T("%x %X")); - } - - if ( !result ) - { - result = dt.ParseFormat(input, _T("%X %x")); - } - - if ( !result ) - { - // we've tried everything and still no match - return (wxChar *)NULL; - } - - Tm tm = dt.GetTm(); - - haveDay = haveMon = haveYear = - haveHour = haveMin = haveSec = true; - - hour = tm.hour; - min = tm.min; - sec = tm.sec; - - year = tm.year; - mon = tm.mon; - mday = tm.mday; - - input = result; - } - break; - - case _T('d'): // day of a month (01-31) - if ( !GetNumericToken(width, input, &num) || - (num > 31) || (num < 1) ) - { - // no match - return (wxChar *)NULL; - } - - // we can't check whether the day range is correct yet, will - // do it later - assume ok for now - haveDay = true; - mday = (wxDateTime_t)num; - break; - - case _T('H'): // hour in 24h format (00-23) - if ( !GetNumericToken(width, input, &num) || (num > 23) ) - { - // no match - return (wxChar *)NULL; - } - - haveHour = true; - hour = (wxDateTime_t)num; - break; - - case _T('I'): // hour in 12h format (01-12) - if ( !GetNumericToken(width, input, &num) || !num || (num > 12) ) - { - // no match - return (wxChar *)NULL; - } - - haveHour = true; - hourIsIn12hFormat = true; - hour = (wxDateTime_t)(num % 12); // 12 should be 0 - break; - - case _T('j'): // day of the year - if ( !GetNumericToken(width, input, &num) || !num || (num > 366) ) - { - // no match - return (wxChar *)NULL; - } - - haveYDay = true; - yday = (wxDateTime_t)num; - break; - - case _T('m'): // month as a number (01-12) - if ( !GetNumericToken(width, input, &num) || !num || (num > 12) ) - { - // no match - return (wxChar *)NULL; - } - - haveMon = true; - mon = (Month)(num - 1); - break; - - case _T('M'): // minute as a decimal number (00-59) - if ( !GetNumericToken(width, input, &num) || (num > 59) ) - { - // no match - return (wxChar *)NULL; - } - - haveMin = true; - min = (wxDateTime_t)num; - break; - - case _T('p'): // AM or PM string - { - wxString am, pm, token = GetAlphaToken(input); - - GetAmPmStrings(&am, &pm); - if (am.empty() && pm.empty()) - return (wxChar *)NULL; // no am/pm strings defined - if ( token.CmpNoCase(pm) == 0 ) - { - isPM = true; - } - else if ( token.CmpNoCase(am) != 0 ) - { - // no match - return (wxChar *)NULL; - } - } - break; - - case _T('r'): // time as %I:%M:%S %p - { - wxDateTime dt; - input = dt.ParseFormat(input, _T("%I:%M:%S %p")); - if ( !input ) - { - // no match - return (wxChar *)NULL; - } - - haveHour = haveMin = haveSec = true; - - Tm tm = dt.GetTm(); - hour = tm.hour; - min = tm.min; - sec = tm.sec; - } - break; - - case _T('R'): // time as %H:%M - { - wxDateTime dt; - input = dt.ParseFormat(input, _T("%H:%M")); - if ( !input ) - { - // no match - return (wxChar *)NULL; - } - - haveHour = haveMin = true; - - Tm tm = dt.GetTm(); - hour = tm.hour; - min = tm.min; - } - break; - - case _T('S'): // second as a decimal number (00-61) - if ( !GetNumericToken(width, input, &num) || (num > 61) ) - { - // no match - return (wxChar *)NULL; - } - - haveSec = true; - sec = (wxDateTime_t)num; - break; - - case _T('T'): // time as %H:%M:%S - { - wxDateTime dt; - input = dt.ParseFormat(input, _T("%H:%M:%S")); - if ( !input ) - { - // no match - return (wxChar *)NULL; - } - - haveHour = haveMin = haveSec = true; - - Tm tm = dt.GetTm(); - hour = tm.hour; - min = tm.min; - sec = tm.sec; - } - break; - - case _T('w'): // weekday as a number (0-6), Sunday = 0 - if ( !GetNumericToken(width, input, &num) || (wday > 6) ) - { - // no match - return (wxChar *)NULL; - } - - haveWDay = true; - wday = (WeekDay)num; - break; - - case _T('x'): // locale default date representation -#ifdef HAVE_STRPTIME - // try using strptime() -- it may fail even if the input is - // correct but the date is out of range, so we will fall back - // to our generic code anyhow - { - struct tm tm; - - const wxChar *result = CallStrptime(input, "%x", &tm); - if ( result ) - { - input = result; - - haveDay = haveMon = haveYear = true; - - year = 1900 + tm.tm_year; - mon = (Month)tm.tm_mon; - mday = tm.tm_mday; - - break; - } - } -#endif // HAVE_STRPTIME - - { - wxDateTime dt; - wxString fmtDate, - fmtDateAlt; - -#ifdef __WINDOWS__ - // The above doesn't work for all locales, try to query - // Windows for the right way of formatting the date: - fmtDate = GetLocaleDateFormat(); - if ( fmtDate.empty() ) -#endif - { - if ( IsWestEuropeanCountry(GetCountry()) || - GetCountry() == Russia ) - { - fmtDate = _T("%d/%m/%y"); - fmtDateAlt = _T("%m/%d/%y"); - } - else // assume USA - { - fmtDate = _T("%m/%d/%y"); - fmtDateAlt = _T("%d/%m/%y"); - } - } - - const wxChar *result = dt.ParseFormat(input, fmtDate); - - if ( !result && !fmtDateAlt.empty() ) - { - // ok, be nice and try another one - result = dt.ParseFormat(input, fmtDateAlt); - } - - if ( !result ) - { - // bad luck - return (wxChar *)NULL; - } - - Tm tm = dt.GetTm(); - - haveDay = haveMon = haveYear = true; - - year = tm.year; - mon = tm.mon; - mday = tm.mday; - - input = result; - } - - break; - - case _T('X'): // locale default time representation -#ifdef HAVE_STRPTIME - { - // use strptime() to do it for us (FIXME !Unicode friendly) - struct tm tm; - input = CallStrptime(input, "%X", &tm); - if ( !input ) - { - return (wxChar *)NULL; - } - - haveHour = haveMin = haveSec = true; - - hour = tm.tm_hour; - min = tm.tm_min; - sec = tm.tm_sec; - } -#else // !HAVE_STRPTIME - // TODO under Win32 we can query the LOCALE_ITIME system - // setting which says whether the default time format is - // 24 or 12 hour - { - // try to parse what follows as "%H:%M:%S" and, if this - // fails, as "%I:%M:%S %p" - this should catch the most - // common cases - wxDateTime dt; - - const wxChar *result = dt.ParseFormat(input, _T("%T")); - if ( !result ) - { - result = dt.ParseFormat(input, _T("%r")); - } - - if ( !result ) - { - // no match - return (wxChar *)NULL; - } - - haveHour = haveMin = haveSec = true; - - Tm tm = dt.GetTm(); - hour = tm.hour; - min = tm.min; - sec = tm.sec; - - input = result; - } -#endif // HAVE_STRPTIME/!HAVE_STRPTIME - break; - - case _T('y'): // year without century (00-99) - if ( !GetNumericToken(width, input, &num) || (num > 99) ) - { - // no match - return (wxChar *)NULL; - } - - haveYear = true; - - // TODO should have an option for roll over date instead of - // hard coding it here - year = (num > 30 ? 1900 : 2000) + (wxDateTime_t)num; - break; - - case _T('Y'): // year with century - if ( !GetNumericToken(width, input, &num) ) - { - // no match - return (wxChar *)NULL; - } - - haveYear = true; - year = (wxDateTime_t)num; - break; - - case _T('Z'): // timezone name - wxFAIL_MSG(_T("TODO")); - break; - - case _T('%'): // a percent sign - if ( *input++ != _T('%') ) - { - // no match - return (wxChar *)NULL; - } - break; - - case 0: // the end of string - wxFAIL_MSG(_T("unexpected format end")); - - // fall through - - default: // not a known format spec - return (wxChar *)NULL; - } - } - - // format matched, try to construct a date from what we have now - Tm tmDef; - if ( dateDef.IsValid() ) - { - // take this date as default - tmDef = dateDef.GetTm(); - } - else if ( IsValid() ) - { - // if this date is valid, don't change it - tmDef = GetTm(); - } - else - { - // no default and this date is invalid - fall back to Today() - tmDef = Today().GetTm(); - } - - Tm tm = tmDef; - - // set the date - if ( haveYear ) - { - tm.year = year; - } - - // TODO we don't check here that the values are consistent, if both year - // day and month/day were found, we just ignore the year day and we - // also always ignore the week day - if ( haveMon && haveDay ) - { - if ( mday > GetNumOfDaysInMonth(tm.year, mon) ) - { - wxLogDebug(_T("bad month day in wxDateTime::ParseFormat")); - - return (wxChar *)NULL; - } - - tm.mon = mon; - tm.mday = mday; - } - else if ( haveYDay ) - { - if ( yday > GetNumberOfDays(tm.year) ) - { - wxLogDebug(_T("bad year day in wxDateTime::ParseFormat")); - - return (wxChar *)NULL; - } - - Tm tm2 = wxDateTime(1, Jan, tm.year).SetToYearDay(yday).GetTm(); - - tm.mon = tm2.mon; - tm.mday = tm2.mday; - } - - // deal with AM/PM - if ( haveHour && hourIsIn12hFormat && isPM ) - { - // translate to 24hour format - hour += 12; - } - //else: either already in 24h format or no translation needed - - // set the time - if ( haveHour ) - { - tm.hour = hour; - } - - if ( haveMin ) - { - tm.min = min; - } - - if ( haveSec ) - { - tm.sec = sec; - } - - Set(tm); - - // finally check that the week day is consistent -- if we had it - if ( haveWDay && GetWeekDay() != wday ) - { - wxLogDebug(_T("inconsistsnet week day in wxDateTime::ParseFormat()")); - - return NULL; - } - - return input; -} - -const wxChar *wxDateTime::ParseDateTime(const wxChar *date) -{ - wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); - - // Set to current day and hour, so strings like '14:00' becomes today at - // 14, not some other random date - wxDateTime dtDate = wxDateTime::Today(); - wxDateTime dtTime = wxDateTime::Today(); - - const wxChar* pchTime; - - // Try to parse the beginning of the string as a date - const wxChar* pchDate = dtDate.ParseDate(date); - - // We got a date in the beginning, see if there is a time specified after the date - if ( pchDate ) - { - // Skip spaces, as the ParseTime() function fails on spaces - while ( wxIsspace(*pchDate) ) - pchDate++; - - pchTime = dtTime.ParseTime(pchDate); - } - else // no date in the beginning - { - // check and see if we have a time followed by a date - pchTime = dtTime.ParseTime(date); - if ( pchTime ) - { - while ( wxIsspace(*pchTime) ) - pchTime++; - - pchDate = dtDate.ParseDate(pchTime); - } - } - - // If we have a date specified, set our own data to the same date - if ( !pchDate || !pchTime ) - return NULL; - - Set(dtDate.GetDay(), dtDate.GetMonth(), dtDate.GetYear(), - dtTime.GetHour(), dtTime.GetMinute(), dtTime.GetSecond(), - dtTime.GetMillisecond()); - - // Return endpoint of scan - return pchDate > pchTime ? pchDate : pchTime; -} - -const wxChar *wxDateTime::ParseDate(const wxChar *date) -{ - // this is a simplified version of ParseDateTime() which understands only - // "today" (for wxDate compatibility) and digits only otherwise (and not - // all esoteric constructions ParseDateTime() knows about) - - wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); - - const wxChar *p = date; - while ( wxIsspace(*p) ) - p++; - - // some special cases - static struct - { - const wxChar *str; - int dayDiffFromToday; - } literalDates[] = - { - { wxTRANSLATE("today"), 0 }, - { wxTRANSLATE("yesterday"), -1 }, - { wxTRANSLATE("tomorrow"), 1 }, - }; - - for ( size_t n = 0; n < WXSIZEOF(literalDates); n++ ) - { - const wxString dateStr = wxGetTranslation(literalDates[n].str); - size_t len = dateStr.length(); - if ( wxStrlen(p) >= len ) - { - wxString str(p, len); - if ( str.CmpNoCase(dateStr) == 0 ) - { - // nothing can follow this, so stop here - p += len; - - int dayDiffFromToday = literalDates[n].dayDiffFromToday; - *this = Today(); - if ( dayDiffFromToday ) - { - *this += wxDateSpan::Days(dayDiffFromToday); - } - - return p; - } - } - } - - // We try to guess what we have here: for each new (numeric) token, we - // determine if it can be a month, day or a year. Of course, there is an - // ambiguity as some numbers may be days as well as months, so we also - // have the ability to back track. - - // what do we have? - bool haveDay = false, // the months day? - haveWDay = false, // the day of week? - haveMon = false, // the month? - haveYear = false; // the year? - - // and the value of the items we have (init them to get rid of warnings) - WeekDay wday = Inv_WeekDay; - wxDateTime_t day = 0; - wxDateTime::Month mon = Inv_Month; - int year = 0; - - // tokenize the string - size_t nPosCur = 0; - static const wxChar *dateDelimiters = _T(".,/-\t\r\n "); - wxStringTokenizer tok(p, dateDelimiters); - while ( tok.HasMoreTokens() ) - { - wxString token = tok.GetNextToken(); - if ( !token ) - continue; - - // is it a number? - unsigned long val; - if ( token.ToULong(&val) ) - { - // guess what this number is - - bool isDay = false, - isMonth = false, - isYear = false; - - if ( !haveMon && val > 0 && val <= 12 ) - { - // assume it is month - isMonth = true; - } - else // not the month - { - if ( haveDay ) - { - // this can only be the year - isYear = true; - } - else // may be either day or year - { - // use a leap year if we don't have the year yet to allow - // dates like 2/29/1976 which would be rejected otherwise - wxDateTime_t max_days = (wxDateTime_t)( - haveMon - ? GetNumOfDaysInMonth(haveYear ? year : 1976, mon) - : 31 - ); - - // can it be day? - if ( (val == 0) || (val > (unsigned long)max_days) ) - { - // no - isYear = true; - } - else // yes, suppose it's the day - { - isDay = true; - } - } - } - - if ( isYear ) - { - if ( haveYear ) - break; - - haveYear = true; - - year = (wxDateTime_t)val; - } - else if ( isDay ) - { - if ( haveDay ) - break; - - haveDay = true; - - day = (wxDateTime_t)val; - } - else if ( isMonth ) - { - haveMon = true; - - mon = (Month)(val - 1); - } - } - else // not a number - { - // be careful not to overwrite the current mon value - Month mon2 = GetMonthFromName(token, Name_Full | Name_Abbr); - if ( mon2 != Inv_Month ) - { - // it's a month - if ( haveMon ) - { - // but we already have a month - maybe we guessed wrong? - if ( !haveDay ) - { - // no need to check in month range as always < 12, but - // the days are counted from 1 unlike the months - day = (wxDateTime_t)(mon + 1); - haveDay = true; - } - else - { - // could possible be the year (doesn't the year come - // before the month in the japanese format?) (FIXME) - break; - } - } - - mon = mon2; - - haveMon = true; - } - else // not a valid month name - { - WeekDay wday2 = GetWeekDayFromName(token, Name_Full | Name_Abbr); - if ( wday2 != Inv_WeekDay ) - { - // a week day - if ( haveWDay ) - { - break; - } - - wday = wday2; - - haveWDay = true; - } - else // not a valid weekday name - { - // try the ordinals - static const wxChar *ordinals[] = - { - wxTRANSLATE("first"), - wxTRANSLATE("second"), - wxTRANSLATE("third"), - wxTRANSLATE("fourth"), - wxTRANSLATE("fifth"), - wxTRANSLATE("sixth"), - wxTRANSLATE("seventh"), - wxTRANSLATE("eighth"), - wxTRANSLATE("ninth"), - wxTRANSLATE("tenth"), - wxTRANSLATE("eleventh"), - wxTRANSLATE("twelfth"), - wxTRANSLATE("thirteenth"), - wxTRANSLATE("fourteenth"), - wxTRANSLATE("fifteenth"), - wxTRANSLATE("sixteenth"), - wxTRANSLATE("seventeenth"), - wxTRANSLATE("eighteenth"), - wxTRANSLATE("nineteenth"), - wxTRANSLATE("twentieth"), - // that's enough - otherwise we'd have problems with - // composite (or not) ordinals - }; - - size_t n; - for ( n = 0; n < WXSIZEOF(ordinals); n++ ) - { - if ( token.CmpNoCase(ordinals[n]) == 0 ) - { - break; - } - } - - if ( n == WXSIZEOF(ordinals) ) - { - // stop here - something unknown - break; - } - - // it's a day - if ( haveDay ) - { - // don't try anything here (as in case of numeric day - // above) - the symbolic day spec should always - // precede the month/year - break; - } - - haveDay = true; - - day = (wxDateTime_t)(n + 1); - } - } - } - - nPosCur = tok.GetPosition(); - } - - // either no more tokens or the scan was stopped by something we couldn't - // parse - in any case, see if we can construct a date from what we have - if ( !haveDay && !haveWDay ) - { - wxLogDebug(_T("ParseDate: no day, no weekday hence no date.")); - - return NULL; - } - - if ( haveWDay && (haveMon || haveYear || haveDay) && - !(haveDay && haveMon && haveYear) ) - { - // without adjectives (which we don't support here) the week day only - // makes sense completely separately or with the full date - // specification (what would "Wed 1999" mean?) - return NULL; - } - - if ( !haveWDay && haveYear && !(haveDay && haveMon) ) - { - // may be we have month and day instead of day and year? - if ( haveDay && !haveMon ) - { - if ( day <= 12 ) - { - // exchange day and month - mon = (wxDateTime::Month)(day - 1); - - // we're in the current year then - if ( (year > 0) && (year <= (int)GetNumOfDaysInMonth(Inv_Year, mon)) ) - { - day = (wxDateTime_t)year; - - haveMon = true; - haveYear = false; - } - //else: no, can't exchange, leave haveMon == false - } - } - - if ( !haveMon ) - { - // if we give the year, month and day must be given too - wxLogDebug(_T("ParseDate: day and month should be specified if year is.")); - - return NULL; - } - } - - if ( !haveMon ) - { - mon = GetCurrentMonth(); - } - - if ( !haveYear ) - { - year = GetCurrentYear(); - } - - if ( haveDay ) - { - // normally we check the day above but the check is optimistic in case - // we find the day before its month/year so we have to redo it now - if ( day > GetNumOfDaysInMonth(year, mon) ) - return NULL; - - Set(day, mon, year); - - if ( haveWDay ) - { - // check that it is really the same - if ( GetWeekDay() != wday ) - { - // inconsistency detected - wxLogDebug(_T("ParseDate: inconsistent day/weekday.")); - - return (wxChar *)NULL; - } - } - } - else // haveWDay - { - *this = Today(); - - SetToWeekDayInSameWeek(wday); - } - - // return the pointer to the first unparsed char - p += nPosCur; - if ( nPosCur && wxStrchr(dateDelimiters, *(p - 1)) ) - { - // if we couldn't parse the token after the delimiter, put back the - // delimiter as well - p--; - } - - return p; -} - -const wxChar *wxDateTime::ParseTime(const wxChar *time) -{ - wxCHECK_MSG( time, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); - - // first try some extra things - static const struct - { - const wxChar *name; - wxDateTime_t hour; - } stdTimes[] = - { - { wxTRANSLATE("noon"), 12 }, - { wxTRANSLATE("midnight"), 00 }, - // anything else? - }; - - for ( size_t n = 0; n < WXSIZEOF(stdTimes); n++ ) - { - wxString timeString = wxGetTranslation(stdTimes[n].name); - size_t len = timeString.length(); - if ( timeString.CmpNoCase(wxString(time, len)) == 0 ) - { - // casts required by DigitalMars - Set(stdTimes[n].hour, wxDateTime_t(0), wxDateTime_t(0)); - - return time + len; - } - } - - // try all time formats we may think about in the order from longest to - // shortest - - // 12hour with AM/PM? - const wxChar *result = ParseFormat(time, _T("%I:%M:%S %p")); - - if ( !result ) - { - // normally, it's the same, but why not try it? - result = ParseFormat(time, _T("%H:%M:%S")); - } - - if ( !result ) - { - // 12hour with AM/PM but without seconds? - result = ParseFormat(time, _T("%I:%M %p")); - } - - if ( !result ) - { - // without seconds? - result = ParseFormat(time, _T("%H:%M")); - } - - if ( !result ) - { - // just the hour and AM/PM? - result = ParseFormat(time, _T("%I %p")); - } - - if ( !result ) - { - // just the hour? - result = ParseFormat(time, _T("%H")); - } - - if ( !result ) - { - // parse the standard format: normally it is one of the formats above - // but it may be set to something completely different by the user - result = ParseFormat(time, _T("%X")); - } - - // TODO: parse timezones - - return result; -} - -// ---------------------------------------------------------------------------- -// Workdays and holidays support -// ---------------------------------------------------------------------------- - -bool wxDateTime::IsWorkDay(Country WXUNUSED(country)) const -{ - return !wxDateTimeHolidayAuthority::IsHoliday(*this); -} - -// ============================================================================ -// wxDateSpan -// ============================================================================ - -wxDateSpan WXDLLIMPEXP_BASE operator*(int n, const wxDateSpan& ds) -{ - wxDateSpan ds1(ds); - return ds1.Multiply(n); -} - -// ============================================================================ -// wxTimeSpan -// ============================================================================ - -wxTimeSpan WXDLLIMPEXP_BASE operator*(int n, const wxTimeSpan& ts) -{ - return wxTimeSpan(ts).Multiply(n); -} - -// this enum is only used in wxTimeSpan::Format() below but we can't declare -// it locally to the method as it provokes an internal compiler error in egcs -// 2.91.60 when building with -O2 -enum TimeSpanPart -{ - Part_Week, - Part_Day, - Part_Hour, - Part_Min, - Part_Sec, - Part_MSec -}; - -// not all strftime(3) format specifiers make sense here because, for example, -// a time span doesn't have a year nor a timezone -// -// Here are the ones which are supported (all of them are supported by strftime -// as well): -// %H hour in 24 hour format -// %M minute (00 - 59) -// %S second (00 - 59) -// %% percent sign -// -// Also, for MFC CTimeSpan compatibility, we support -// %D number of days -// -// And, to be better than MFC :-), we also have -// %E number of wEeks -// %l milliseconds (000 - 999) -wxString wxTimeSpan::Format(const wxChar *format) const -{ - // we deal with only positive time spans here and just add the sign in - // front for the negative ones - if ( IsNegative() ) - { - wxString str(Negate().Format(format)); - return _T("-") + str; - } - - wxCHECK_MSG( format, wxEmptyString, - _T("NULL format in wxTimeSpan::Format") ); - - wxString str; - str.Alloc(wxStrlen(format)); - - // Suppose we have wxTimeSpan ts(1 /* hour */, 2 /* min */, 3 /* sec */) - // - // Then, of course, ts.Format("%H:%M:%S") must return "01:02:03", but the - // question is what should ts.Format("%S") do? The code here returns "3273" - // in this case (i.e. the total number of seconds, not just seconds % 60) - // because, for me, this call means "give me entire time interval in - // seconds" and not "give me the seconds part of the time interval" - // - // If we agree that it should behave like this, it is clear that the - // interpretation of each format specifier depends on the presence of the - // other format specs in the string: if there was "%H" before "%M", we - // should use GetMinutes() % 60, otherwise just GetMinutes() &c - - // we remember the most important unit found so far - TimeSpanPart partBiggest = Part_MSec; - - for ( const wxChar *pch = format; *pch; pch++ ) - { - wxChar ch = *pch; - - if ( ch == _T('%') ) - { - // the start of the format specification of the printf() below - wxString fmtPrefix(_T('%')); - - // the number - long n; - - // the number of digits for the format string, 0 if unused - unsigned digits = 0; - - ch = *++pch; // get the format spec char - switch ( ch ) - { - default: - wxFAIL_MSG( _T("invalid format character") ); - // fall through - - case _T('%'): - str += ch; - - // skip the part below switch - continue; - - case _T('D'): - n = GetDays(); - if ( partBiggest < Part_Day ) - { - n %= DAYS_PER_WEEK; - } - else - { - partBiggest = Part_Day; - } - break; - - case _T('E'): - partBiggest = Part_Week; - n = GetWeeks(); - break; - - case _T('H'): - n = GetHours(); - if ( partBiggest < Part_Hour ) - { - n %= HOURS_PER_DAY; - } - else - { - partBiggest = Part_Hour; - } - - digits = 2; - break; - - case _T('l'): - n = GetMilliseconds().ToLong(); - if ( partBiggest < Part_MSec ) - { - n %= 1000; - } - //else: no need to reset partBiggest to Part_MSec, it is - // the least significant one anyhow - - digits = 3; - break; - - case _T('M'): - n = GetMinutes(); - if ( partBiggest < Part_Min ) - { - n %= MIN_PER_HOUR; - } - else - { - partBiggest = Part_Min; - } - - digits = 2; - break; - - case _T('S'): - n = GetSeconds().ToLong(); - if ( partBiggest < Part_Sec ) - { - n %= SEC_PER_MIN; - } - else - { - partBiggest = Part_Sec; - } - - digits = 2; - break; - } - - if ( digits ) - { - fmtPrefix << _T("0") << digits; - } - - str += wxString::Format(fmtPrefix + _T("ld"), n); - } - else - { - // normal character, just copy - str += ch; - } - } - - return str; -} - -// ============================================================================ -// wxDateTimeHolidayAuthority and related classes -// ============================================================================ - -#include "wx/arrimpl.cpp" - -WX_DEFINE_OBJARRAY(wxDateTimeArray) - -static int wxCMPFUNC_CONV -wxDateTimeCompareFunc(wxDateTime **first, wxDateTime **second) -{ - wxDateTime dt1 = **first, - dt2 = **second; - - return dt1 == dt2 ? 0 : dt1 < dt2 ? -1 : +1; -} - -// ---------------------------------------------------------------------------- -// wxDateTimeHolidayAuthority -// ---------------------------------------------------------------------------- - -wxHolidayAuthoritiesArray wxDateTimeHolidayAuthority::ms_authorities; - -/* static */ -bool wxDateTimeHolidayAuthority::IsHoliday(const wxDateTime& dt) -{ - size_t count = ms_authorities.size(); - for ( size_t n = 0; n < count; n++ ) - { - if ( ms_authorities[n]->DoIsHoliday(dt) ) - { - return true; - } - } - - return false; -} - -/* static */ -size_t -wxDateTimeHolidayAuthority::GetHolidaysInRange(const wxDateTime& dtStart, - const wxDateTime& dtEnd, - wxDateTimeArray& holidays) -{ - wxDateTimeArray hol; - - holidays.Clear(); - - const size_t countAuth = ms_authorities.size(); - for ( size_t nAuth = 0; nAuth < countAuth; nAuth++ ) - { - ms_authorities[nAuth]->DoGetHolidaysInRange(dtStart, dtEnd, hol); - - WX_APPEND_ARRAY(holidays, hol); - } - - holidays.Sort(wxDateTimeCompareFunc); - - return holidays.size(); -} - -/* static */ -void wxDateTimeHolidayAuthority::ClearAllAuthorities() -{ - WX_CLEAR_ARRAY(ms_authorities); -} - -/* static */ -void wxDateTimeHolidayAuthority::AddAuthority(wxDateTimeHolidayAuthority *auth) -{ - ms_authorities.push_back(auth); -} - -wxDateTimeHolidayAuthority::~wxDateTimeHolidayAuthority() -{ - // required here for Darwin -} - -// ---------------------------------------------------------------------------- -// wxDateTimeWorkDays -// ---------------------------------------------------------------------------- - -bool wxDateTimeWorkDays::DoIsHoliday(const wxDateTime& dt) const -{ - wxDateTime::WeekDay wd = dt.GetWeekDay(); - - return (wd == wxDateTime::Sun) || (wd == wxDateTime::Sat); -} - -size_t wxDateTimeWorkDays::DoGetHolidaysInRange(const wxDateTime& dtStart, - const wxDateTime& dtEnd, - wxDateTimeArray& holidays) const -{ - if ( dtStart > dtEnd ) - { - wxFAIL_MSG( _T("invalid date range in GetHolidaysInRange") ); - - return 0u; - } - - holidays.Empty(); - - // instead of checking all days, start with the first Sat after dtStart and - // end with the last Sun before dtEnd - wxDateTime dtSatFirst = dtStart.GetNextWeekDay(wxDateTime::Sat), - dtSatLast = dtEnd.GetPrevWeekDay(wxDateTime::Sat), - dtSunFirst = dtStart.GetNextWeekDay(wxDateTime::Sun), - dtSunLast = dtEnd.GetPrevWeekDay(wxDateTime::Sun), - dt; - - for ( dt = dtSatFirst; dt <= dtSatLast; dt += wxDateSpan::Week() ) - { - holidays.Add(dt); - } - - for ( dt = dtSunFirst; dt <= dtSunLast; dt += wxDateSpan::Week() ) - { - holidays.Add(dt); - } - - return holidays.GetCount(); -} - -// ============================================================================ -// other helper functions -// ============================================================================ - -// ---------------------------------------------------------------------------- -// iteration helpers: can be used to write a for loop over enum variable like -// this: -// for ( m = wxDateTime::Jan; m < wxDateTime::Inv_Month; wxNextMonth(m) ) -// ---------------------------------------------------------------------------- - -WXDLLIMPEXP_BASE void wxNextMonth(wxDateTime::Month& m) -{ - wxASSERT_MSG( m < wxDateTime::Inv_Month, _T("invalid month") ); - - // no wrapping or the for loop above would never end! - m = (wxDateTime::Month)(m + 1); -} - -WXDLLIMPEXP_BASE void wxPrevMonth(wxDateTime::Month& m) -{ - wxASSERT_MSG( m < wxDateTime::Inv_Month, _T("invalid month") ); - - m = m == wxDateTime::Jan ? wxDateTime::Inv_Month - : (wxDateTime::Month)(m - 1); -} - -WXDLLIMPEXP_BASE void wxNextWDay(wxDateTime::WeekDay& wd) -{ - wxASSERT_MSG( wd < wxDateTime::Inv_WeekDay, _T("invalid week day") ); - - // no wrapping or the for loop above would never end! - wd = (wxDateTime::WeekDay)(wd + 1); -} - -WXDLLIMPEXP_BASE void wxPrevWDay(wxDateTime::WeekDay& wd) -{ - wxASSERT_MSG( wd < wxDateTime::Inv_WeekDay, _T("invalid week day") ); - - wd = wd == wxDateTime::Sun ? wxDateTime::Inv_WeekDay - : (wxDateTime::WeekDay)(wd - 1); -} - -#endif // wxUSE_DATETIME +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/datetime.cpp +// Purpose: implementation of time/date related classes +// Author: Vadim Zeitlin +// Modified by: +// Created: 11.05.99 +// RCS-ID: $Id: datetime.cpp 65730 2010-10-02 16:50:34Z TIK $ +// Copyright: (c) 1999 Vadim Zeitlin +// parts of code taken from sndcal library by Scott E. Lee: +// +// Copyright 1993-1995, Scott E. Lee, all rights reserved. +// Permission granted to use, copy, modify, distribute and sell +// so long as the above copyright and this permission statement +// are retained in all copies. +// +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +/* + * Implementation notes: + * + * 1. the time is stored as a 64bit integer containing the signed number of + * milliseconds since Jan 1. 1970 (the Unix Epoch) - so it is always + * expressed in GMT. + * + * 2. the range is thus something about 580 million years, but due to current + * algorithms limitations, only dates from Nov 24, 4714BC are handled + * + * 3. standard ANSI C functions are used to do time calculations whenever + * possible, i.e. when the date is in the range Jan 1, 1970 to 2038 + * + * 4. otherwise, the calculations are done by converting the date to/from JDN + * first (the range limitation mentioned above comes from here: the + * algorithm used by Scott E. Lee's code only works for positive JDNs, more + * or less) + * + * 5. the object constructed for the given DD-MM-YYYY HH:MM:SS corresponds to + * this moment in local time and may be converted to the object + * corresponding to the same date/time in another time zone by using + * ToTimezone() + * + * 6. the conversions to the current (or any other) timezone are done when the + * internal time representation is converted to the broken-down one in + * wxDateTime::Tm. + */ + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if !defined(wxUSE_DATETIME) || wxUSE_DATETIME + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" + #endif + #include "wx/string.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/stopwatch.h" // for wxGetLocalTimeMillis() + #include "wx/module.h" +#endif // WX_PRECOMP + +#include "wx/thread.h" +#include "wx/tokenzr.h" + +#include + +#ifdef __WINDOWS__ + #include + #ifndef __WXWINCE__ + #include + #endif +#endif + +#include "wx/datetime.h" + +const long wxDateTime::TIME_T_FACTOR = 1000l; + +#if wxUSE_EXTENDED_RTTI + +template<> void wxStringReadValue(const wxString &s , wxDateTime &data ) +{ + data.ParseFormat(s,wxT("%Y-%m-%d %H:%M:%S")) ; +} + +template<> void wxStringWriteValue(wxString &s , const wxDateTime &data ) +{ + s = data.Format(wxT("%Y-%m-%d %H:%M:%S")) ; +} + +wxCUSTOM_TYPE_INFO(wxDateTime, wxToStringConverter , wxFromStringConverter) + +#endif + +// +// ---------------------------------------------------------------------------- +// conditional compilation +// ---------------------------------------------------------------------------- + +#if defined(HAVE_STRPTIME) && defined(__GLIBC__) && \ + ((__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0)) + // glibc 2.0.7 strptime() is broken - the following snippet causes it to + // crash (instead of just failing): + // + // strncpy(buf, "Tue Dec 21 20:25:40 1999", 128); + // strptime(buf, "%x", &tm); + // + // so don't use it + #undef HAVE_STRPTIME +#endif // broken strptime() + +#if defined(HAVE_STRPTIME) && defined(__DARWIN__) && defined(_MSL_USING_MW_C_HEADERS) && _MSL_USING_MW_C_HEADERS + // configure detects strptime as linkable because it's in the OS X + // System library but MSL headers don't declare it. + +// char *strptime(const char *, const char *, struct tm *); + // However, we DON'T want to just provide it here because we would + // crash and/or overwrite data when strptime from OS X tries + // to fill in MW's struct tm which is two fields shorter (no TZ stuff) + // So for now let's just say we don't have strptime + #undef HAVE_STRPTIME +#endif + +#if defined(__MWERKS__) && wxUSE_UNICODE + #include +#endif + +// define a special symbol for VC8 instead of writing tests for 1400 repeatedly +#ifdef __VISUALC__ + #if __VISUALC__ >= 1400 + #define __VISUALC8__ + #endif +#endif + +#if !defined(WX_TIMEZONE) && !defined(WX_GMTOFF_IN_TM) + #if defined(__WXPALMOS__) + #define WX_GMTOFF_IN_TM + #elif defined(__WXMSW__) + static long wxGetTimeZone() + { + TIME_ZONE_INFORMATION info; + GetTimeZoneInformation(&info); + long timeZone = info.Bias * 60; // convert minutes to seconds + return timeZone; + } + #define WX_TIMEZONE wxGetTimeZone() + #elif defined(__VISAGECPP__) + #define WX_TIMEZONE _timezone + #elif defined(__MWERKS__) + long wxmw_timezone = 28800; + #define WX_TIMEZONE wxmw_timezone + #elif defined(__DARWIN__) + #define WX_GMTOFF_IN_TM + #else // unknown platform - try timezone + #define WX_TIMEZONE timezone + #endif +#endif // !WX_TIMEZONE && !WX_GMTOFF_IN_TM + +// everyone has strftime except Win CE unless VC8 is used +#if !defined(__WXWINCE__) || defined(__VISUALC8__) + #define HAVE_STRFTIME +#endif + +// NB: VC8 safe time functions could/should be used for wxMSW as well probably +#if defined(__WXWINCE__) && defined(__VISUALC8__) + +struct tm *wxLocaltime_r(const time_t *t, struct tm* tm) +{ + __time64_t t64 = *t; + return _localtime64_s(tm, &t64) == 0 ? tm : NULL; +} + +struct tm *wxGmtime_r(const time_t* t, struct tm* tm) +{ + __time64_t t64 = *t; + return _gmtime64_s(tm, &t64) == 0 ? tm : NULL; +} + +#else // !wxWinCE with VC8 + +#if (!defined(HAVE_LOCALTIME_R) || !defined(HAVE_GMTIME_R)) && wxUSE_THREADS && !defined(__WINDOWS__) +static wxMutex timeLock; +#endif + +#ifndef HAVE_LOCALTIME_R +struct tm *wxLocaltime_r(const time_t* ticks, struct tm* temp) +{ +#if wxUSE_THREADS && !defined(__WINDOWS__) + // No need to waste time with a mutex on windows since it's using + // thread local storage for localtime anyway. + wxMutexLocker locker(timeLock); +#endif + + // Borland CRT crashes when passed 0 ticks for some reason, see SF bug 1704438 +#ifdef __BORLANDC__ + if ( !*ticks ) + return NULL; +#endif + + const tm * const t = localtime(ticks); + if ( !t ) + return NULL; + + memcpy(temp, t, sizeof(struct tm)); + return temp; +} +#endif // !HAVE_LOCALTIME_R + +#ifndef HAVE_GMTIME_R +struct tm *wxGmtime_r(const time_t* ticks, struct tm* temp) +{ +#if wxUSE_THREADS && !defined(__WINDOWS__) + // No need to waste time with a mutex on windows since it's + // using thread local storage for gmtime anyway. + wxMutexLocker locker(timeLock); +#endif + +#ifdef __BORLANDC__ + if ( !*ticks ) + return NULL; +#endif + + const tm * const t = gmtime(ticks); + if ( !t ) + return NULL; + + memcpy(temp, gmtime(ticks), sizeof(struct tm)); + return temp; +} +#endif // !HAVE_GMTIME_R + +#endif // wxWinCE with VC8/other platforms + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +// debugging helper: just a convenient replacement of wxCHECK() +#define wxDATETIME_CHECK(expr, msg) \ + wxCHECK2_MSG(expr, *this = wxInvalidDateTime; return *this, msg) + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +class wxDateTimeHolidaysModule : public wxModule +{ +public: + virtual bool OnInit() + { + wxDateTimeHolidayAuthority::AddAuthority(new wxDateTimeWorkDays); + + return true; + } + + virtual void OnExit() + { + wxDateTimeHolidayAuthority::ClearAllAuthorities(); + wxDateTimeHolidayAuthority::ms_authorities.clear(); + } + +private: + DECLARE_DYNAMIC_CLASS(wxDateTimeHolidaysModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxDateTimeHolidaysModule, wxModule) + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// some trivial ones +static const int MONTHS_IN_YEAR = 12; + +static const int SEC_PER_MIN = 60; + +static const int MIN_PER_HOUR = 60; + +static const int HOURS_PER_DAY = 24; + +static const long SECONDS_PER_DAY = 86400l; + +static const int DAYS_PER_WEEK = 7; + +static const long MILLISECONDS_PER_DAY = 86400000l; + +// this is the integral part of JDN of the midnight of Jan 1, 1970 +// (i.e. JDN(Jan 1, 1970) = 2440587.5) +static const long EPOCH_JDN = 2440587l; + +// used only in asserts +#ifdef __WXDEBUG__ +// the date of JDN -0.5 (as we don't work with fractional parts, this is the +// reference date for us) is Nov 24, 4714BC +static const int JDN_0_YEAR = -4713; +static const int JDN_0_MONTH = wxDateTime::Nov; +static const int JDN_0_DAY = 24; +#endif // __WXDEBUG__ + +// the constants used for JDN calculations +static const long JDN_OFFSET = 32046l; +static const long DAYS_PER_5_MONTHS = 153l; +static const long DAYS_PER_4_YEARS = 1461l; +static const long DAYS_PER_400_YEARS = 146097l; + +// this array contains the cumulated number of days in all previous months for +// normal and leap years +static const wxDateTime::wxDateTime_t gs_cumulatedDays[2][MONTHS_IN_YEAR] = +{ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }, + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 } +}; + +// ---------------------------------------------------------------------------- +// global data +// ---------------------------------------------------------------------------- + +const wxChar * wxDefaultDateTimeFormat = wxT("%c"); +const wxChar * wxDefaultTimeSpanFormat = wxT("%H:%M:%S"); + +// in the fine tradition of ANSI C we use our equivalent of (time_t)-1 to +// indicate an invalid wxDateTime object +const wxDateTime wxDefaultDateTime; + +wxDateTime::Country wxDateTime::ms_country = wxDateTime::Country_Unknown; + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +// debugger helper: shows what the date really is +#ifdef __WXDEBUG__ +extern const wxChar *wxDumpDate(const wxDateTime* dt) +{ + static wxChar buf[128]; + + wxStrcpy(buf, dt->Format(_T("%Y-%m-%d (%a) %H:%M:%S"))); + + return buf; +} +#endif // Debug + +// get the number of days in the given month of the given year +static inline +wxDateTime::wxDateTime_t GetNumOfDaysInMonth(int year, wxDateTime::Month month) +{ + // the number of days in month in Julian/Gregorian calendar: the first line + // is for normal years, the second one is for the leap ones + static wxDateTime::wxDateTime_t daysInMonth[2][MONTHS_IN_YEAR] = + { + { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } + }; + + return daysInMonth[wxDateTime::IsLeapYear(year)][month]; +} + +// returns the time zone in the C sense, i.e. the difference UTC - local +// (in seconds) +static int GetTimeZone() +{ +#ifdef WX_GMTOFF_IN_TM + // set to true when the timezone is set + static bool s_timezoneSet = false; + static long gmtoffset = LONG_MAX; // invalid timezone + + // ensure that the timezone variable is set by calling wxLocaltime_r + if ( !s_timezoneSet ) + { + // just call wxLocaltime_r() instead of figuring out whether this + // system supports tzset(), _tzset() or something else + time_t t = 0; + struct tm tm; + + wxLocaltime_r(&t, &tm); + s_timezoneSet = true; + + // note that GMT offset is the opposite of time zone and so to return + // consistent results in both WX_GMTOFF_IN_TM and !WX_GMTOFF_IN_TM + // cases we have to negate it + gmtoffset = -tm.tm_gmtoff; + } + return (int)gmtoffset; +#else // !WX_GMTOFF_IN_TM + return WX_TIMEZONE; +#endif // WX_GMTOFF_IN_TM/!WX_GMTOFF_IN_TM +} + +// return the integral part of the JDN for the midnight of the given date (to +// get the real JDN you need to add 0.5, this is, in fact, JDN of the +// noon of the previous day) +static long GetTruncatedJDN(wxDateTime::wxDateTime_t day, + wxDateTime::Month mon, + int year) +{ + // CREDIT: code below is by Scott E. Lee (but bugs are mine) + + // check the date validity + wxASSERT_MSG( + (year > JDN_0_YEAR) || + ((year == JDN_0_YEAR) && (mon > JDN_0_MONTH)) || + ((year == JDN_0_YEAR) && (mon == JDN_0_MONTH) && (day >= JDN_0_DAY)), + _T("date out of range - can't convert to JDN") + ); + + // make the year positive to avoid problems with negative numbers division + year += 4800; + + // months are counted from March here + int month; + if ( mon >= wxDateTime::Mar ) + { + month = mon - 2; + } + else + { + month = mon + 10; + year--; + } + + // now we can simply add all the contributions together + return ((year / 100) * DAYS_PER_400_YEARS) / 4 + + ((year % 100) * DAYS_PER_4_YEARS) / 4 + + (month * DAYS_PER_5_MONTHS + 2) / 5 + + day + - JDN_OFFSET; +} + +#ifdef HAVE_STRFTIME + +// this function is a wrapper around strftime(3) adding error checking +static wxString CallStrftime(const wxChar *format, const tm* tm) +{ + wxChar buf[4096]; + // Create temp wxString here to work around mingw/cygwin bug 1046059 + // http://sourceforge.net/tracker/?func=detail&atid=102435&aid=1046059&group_id=2435 + wxString s; + + if ( !wxStrftime(buf, WXSIZEOF(buf), format, tm) ) + { + // buffer is too small? + wxFAIL_MSG(_T("strftime() failed")); + } + + s = buf; + return s; +} + +#endif // HAVE_STRFTIME + +#ifdef HAVE_STRPTIME + +#if wxUSE_UNIX && !defined(HAVE_STRPTIME_DECL) + // configure detected that we had strptime() but not its declaration, + // provide it ourselves + extern "C" char *strptime(const char *, const char *, struct tm *); +#endif + +// Unicode-friendly strptime() wrapper +static const wxChar * +CallStrptime(const wxChar *input, const char *fmt, tm *tm) +{ + // the problem here is that strptime() returns pointer into the string we + // passed to it while we're really interested in the pointer into the + // original, Unicode, string so we try to transform the pointer back +#if wxUSE_UNICODE + wxCharBuffer inputMB(wxConvertWX2MB(input)); +#else // ASCII + const char * const inputMB = input; +#endif // Unicode/Ascii + + const char *result = strptime(inputMB, fmt, tm); + if ( !result ) + return NULL; + +#if wxUSE_UNICODE + // FIXME: this is wrong in presence of surrogates &c + return input + (result - inputMB.data()); +#else // ASCII + return result; +#endif // Unicode/Ascii +} + +#endif // HAVE_STRPTIME + +// if year and/or month have invalid values, replace them with the current ones +static void ReplaceDefaultYearMonthWithCurrent(int *year, + wxDateTime::Month *month) +{ + struct tm *tmNow = NULL; + struct tm tmstruct; + + if ( *year == wxDateTime::Inv_Year ) + { + tmNow = wxDateTime::GetTmNow(&tmstruct); + + *year = 1900 + tmNow->tm_year; + } + + if ( *month == wxDateTime::Inv_Month ) + { + if ( !tmNow ) + tmNow = wxDateTime::GetTmNow(&tmstruct); + + *month = (wxDateTime::Month)tmNow->tm_mon; + } +} + +// fll the struct tm with default values +static void InitTm(struct tm& tm) +{ + // struct tm may have etxra fields (undocumented and with unportable + // names) which, nevertheless, must be set to 0 + memset(&tm, 0, sizeof(struct tm)); + + tm.tm_mday = 1; // mday 0 is invalid + tm.tm_year = 76; // any valid year + tm.tm_isdst = -1; // auto determine +} + +// parsing helpers +// --------------- + +// return the month if the string is a month name or Inv_Month otherwise +static wxDateTime::Month GetMonthFromName(const wxString& name, int flags) +{ + wxDateTime::Month mon; + for ( mon = wxDateTime::Jan; mon < wxDateTime::Inv_Month; wxNextMonth(mon) ) + { + // case-insensitive comparison either one of or with both abbreviated + // and not versions + if ( flags & wxDateTime::Name_Full ) + { + if ( name.CmpNoCase(wxDateTime:: + GetMonthName(mon, wxDateTime::Name_Full)) == 0 ) + { + break; + } + } + + if ( flags & wxDateTime::Name_Abbr ) + { + if ( name.CmpNoCase(wxDateTime:: + GetMonthName(mon, wxDateTime::Name_Abbr)) == 0 ) + { + break; + } + } + } + + return mon; +} + +// return the weekday if the string is a weekday name or Inv_WeekDay otherwise +static wxDateTime::WeekDay GetWeekDayFromName(const wxString& name, int flags) +{ + wxDateTime::WeekDay wd; + for ( wd = wxDateTime::Sun; wd < wxDateTime::Inv_WeekDay; wxNextWDay(wd) ) + { + // case-insensitive comparison either one of or with both abbreviated + // and not versions + if ( flags & wxDateTime::Name_Full ) + { + if ( name.CmpNoCase(wxDateTime:: + GetWeekDayName(wd, wxDateTime::Name_Full)) == 0 ) + { + break; + } + } + + if ( flags & wxDateTime::Name_Abbr ) + { + if ( name.CmpNoCase(wxDateTime:: + GetWeekDayName(wd, wxDateTime::Name_Abbr)) == 0 ) + { + break; + } + } + } + + return wd; +} + +/* static */ +struct tm *wxDateTime::GetTmNow(struct tm *tmstruct) +{ + time_t t = GetTimeNow(); + return wxLocaltime_r(&t, tmstruct); +} + +// scans all digits (but no more than len) and returns the resulting number +static bool GetNumericToken(size_t len, const wxChar*& p, unsigned long *number) +{ + size_t n = 1; + wxString s; + while ( wxIsdigit(*p) ) + { + s += *p++; + + if ( len && ++n > len ) + break; + } + + return !s.empty() && s.ToULong(number); +} + +// scans all alphabetic characters and returns the resulting string +static wxString GetAlphaToken(const wxChar*& p) +{ + wxString s; + while ( wxIsalpha(*p) ) + { + s += *p++; + } + + return s; +} + +// ============================================================================ +// implementation of wxDateTime +// ============================================================================ + +// ---------------------------------------------------------------------------- +// struct Tm +// ---------------------------------------------------------------------------- + +wxDateTime::Tm::Tm() +{ + year = (wxDateTime_t)wxDateTime::Inv_Year; + mon = wxDateTime::Inv_Month; + mday = 0; + hour = min = sec = msec = 0; + wday = wxDateTime::Inv_WeekDay; +} + +wxDateTime::Tm::Tm(const struct tm& tm, const TimeZone& tz) + : m_tz(tz) +{ + msec = 0; + sec = (wxDateTime::wxDateTime_t)tm.tm_sec; + min = (wxDateTime::wxDateTime_t)tm.tm_min; + hour = (wxDateTime::wxDateTime_t)tm.tm_hour; + mday = (wxDateTime::wxDateTime_t)tm.tm_mday; + mon = (wxDateTime::Month)tm.tm_mon; + year = 1900 + tm.tm_year; + wday = (wxDateTime::wxDateTime_t)tm.tm_wday; + yday = (wxDateTime::wxDateTime_t)tm.tm_yday; +} + +bool wxDateTime::Tm::IsValid() const +{ + // we allow for the leap seconds, although we don't use them (yet) + return (year != wxDateTime::Inv_Year) && (mon != wxDateTime::Inv_Month) && + (mday <= GetNumOfDaysInMonth(year, mon)) && + (hour < 24) && (min < 60) && (sec < 62) && (msec < 1000); +} + +void wxDateTime::Tm::ComputeWeekDay() +{ + // compute the week day from day/month/year: we use the dumbest algorithm + // possible: just compute our JDN and then use the (simple to derive) + // formula: weekday = (JDN + 1.5) % 7 + wday = (wxDateTime::wxDateTime_t)((GetTruncatedJDN(mday, mon, year) + 2) % 7); +} + +void wxDateTime::Tm::AddMonths(int monDiff) +{ + // normalize the months field + while ( monDiff < -mon ) + { + year--; + + monDiff += MONTHS_IN_YEAR; + } + + while ( monDiff + mon >= MONTHS_IN_YEAR ) + { + year++; + + monDiff -= MONTHS_IN_YEAR; + } + + mon = (wxDateTime::Month)(mon + monDiff); + + wxASSERT_MSG( mon >= 0 && mon < MONTHS_IN_YEAR, _T("logic error") ); + + // NB: we don't check here that the resulting date is valid, this function + // is private and the caller must check it if needed +} + +void wxDateTime::Tm::AddDays(int dayDiff) +{ + // normalize the days field + while ( dayDiff + mday < 1 ) + { + AddMonths(-1); + + dayDiff += GetNumOfDaysInMonth(year, mon); + } + + mday = (wxDateTime::wxDateTime_t)( mday + dayDiff ); + while ( mday > GetNumOfDaysInMonth(year, mon) ) + { + mday -= GetNumOfDaysInMonth(year, mon); + + AddMonths(1); + } + + wxASSERT_MSG( mday > 0 && mday <= GetNumOfDaysInMonth(year, mon), + _T("logic error") ); +} + +// ---------------------------------------------------------------------------- +// class TimeZone +// ---------------------------------------------------------------------------- + +wxDateTime::TimeZone::TimeZone(wxDateTime::TZ tz) +{ + switch ( tz ) + { + case wxDateTime::Local: + // get the offset from C RTL: it returns the difference GMT-local + // while we want to have the offset _from_ GMT, hence the '-' + m_offset = -GetTimeZone(); + break; + + case wxDateTime::GMT_12: + case wxDateTime::GMT_11: + case wxDateTime::GMT_10: + case wxDateTime::GMT_9: + case wxDateTime::GMT_8: + case wxDateTime::GMT_7: + case wxDateTime::GMT_6: + case wxDateTime::GMT_5: + case wxDateTime::GMT_4: + case wxDateTime::GMT_3: + case wxDateTime::GMT_2: + case wxDateTime::GMT_1: + m_offset = -3600*(wxDateTime::GMT0 - tz); + break; + + case wxDateTime::GMT0: + case wxDateTime::GMT1: + case wxDateTime::GMT2: + case wxDateTime::GMT3: + case wxDateTime::GMT4: + case wxDateTime::GMT5: + case wxDateTime::GMT6: + case wxDateTime::GMT7: + case wxDateTime::GMT8: + case wxDateTime::GMT9: + case wxDateTime::GMT10: + case wxDateTime::GMT11: + case wxDateTime::GMT12: + case wxDateTime::GMT13: + m_offset = 3600*(tz - wxDateTime::GMT0); + break; + + case wxDateTime::A_CST: + // Central Standard Time in use in Australia = UTC + 9.5 + m_offset = 60l*(9*MIN_PER_HOUR + MIN_PER_HOUR/2); + break; + + default: + wxFAIL_MSG( _T("unknown time zone") ); + } +} + +// ---------------------------------------------------------------------------- +// static functions +// ---------------------------------------------------------------------------- + +/* static */ +bool wxDateTime::IsLeapYear(int year, wxDateTime::Calendar cal) +{ + if ( year == Inv_Year ) + year = GetCurrentYear(); + + if ( cal == Gregorian ) + { + // in Gregorian calendar leap years are those divisible by 4 except + // those divisible by 100 unless they're also divisible by 400 + // (in some countries, like Russia and Greece, additional corrections + // exist, but they won't manifest themselves until 2700) + return (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0)); + } + else if ( cal == Julian ) + { + // in Julian calendar the rule is simpler + return year % 4 == 0; + } + else + { + wxFAIL_MSG(_T("unknown calendar")); + + return false; + } +} + +/* static */ +int wxDateTime::GetCentury(int year) +{ + return year > 0 ? year / 100 : year / 100 - 1; +} + +/* static */ +int wxDateTime::ConvertYearToBC(int year) +{ + // year 0 is BC 1 + return year > 0 ? year : year - 1; +} + +/* static */ +int wxDateTime::GetCurrentYear(wxDateTime::Calendar cal) +{ + switch ( cal ) + { + case Gregorian: + return Now().GetYear(); + + case Julian: + wxFAIL_MSG(_T("TODO")); + break; + + default: + wxFAIL_MSG(_T("unsupported calendar")); + break; + } + + return Inv_Year; +} + +/* static */ +wxDateTime::Month wxDateTime::GetCurrentMonth(wxDateTime::Calendar cal) +{ + switch ( cal ) + { + case Gregorian: + return Now().GetMonth(); + + case Julian: + wxFAIL_MSG(_T("TODO")); + break; + + default: + wxFAIL_MSG(_T("unsupported calendar")); + break; + } + + return Inv_Month; +} + +/* static */ +wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(int year, Calendar cal) +{ + if ( year == Inv_Year ) + { + // take the current year if none given + year = GetCurrentYear(); + } + + switch ( cal ) + { + case Gregorian: + case Julian: + return IsLeapYear(year) ? 366 : 365; + + default: + wxFAIL_MSG(_T("unsupported calendar")); + break; + } + + return 0; +} + +/* static */ +wxDateTime::wxDateTime_t wxDateTime::GetNumberOfDays(wxDateTime::Month month, + int year, + wxDateTime::Calendar cal) +{ + wxCHECK_MSG( month < MONTHS_IN_YEAR, 0, _T("invalid month") ); + + if ( cal == Gregorian || cal == Julian ) + { + if ( year == Inv_Year ) + { + // take the current year if none given + year = GetCurrentYear(); + } + + return GetNumOfDaysInMonth(year, month); + } + else + { + wxFAIL_MSG(_T("unsupported calendar")); + + return 0; + } +} + +/* static */ +wxString wxDateTime::GetMonthName(wxDateTime::Month month, + wxDateTime::NameFlags flags) +{ + wxCHECK_MSG( month != Inv_Month, wxEmptyString, _T("invalid month") ); +#ifdef HAVE_STRFTIME + // notice that we must set all the fields to avoid confusing libc (GNU one + // gets confused to a crash if we don't do this) + tm tm; + InitTm(tm); + tm.tm_mon = month; + + return CallStrftime(flags == Name_Abbr ? _T("%b") : _T("%B"), &tm); +#else // !HAVE_STRFTIME + wxString ret; + switch(month) + { + case Jan: + ret = (flags == Name_Abbr ? wxT("Jan"): wxT("January")); + break; + case Feb: + ret = (flags == Name_Abbr ? wxT("Feb"): wxT("Febuary")); + break; + case Mar: + ret = (flags == Name_Abbr ? wxT("Mar"): wxT("March")); + break; + case Apr: + ret = (flags == Name_Abbr ? wxT("Apr"): wxT("April")); + break; + case May: + ret = (flags == Name_Abbr ? wxT("May"): wxT("May")); + break; + case Jun: + ret = (flags == Name_Abbr ? wxT("Jun"): wxT("June")); + break; + case Jul: + ret = (flags == Name_Abbr ? wxT("Jul"): wxT("July")); + break; + case Aug: + ret = (flags == Name_Abbr ? wxT("Aug"): wxT("August")); + break; + case Sep: + ret = (flags == Name_Abbr ? wxT("Sep"): wxT("September")); + break; + case Oct: + ret = (flags == Name_Abbr ? wxT("Oct"): wxT("October")); + break; + case Nov: + ret = (flags == Name_Abbr ? wxT("Nov"): wxT("November")); + break; + case Dec: + ret = (flags == Name_Abbr ? wxT("Dec"): wxT("December")); + break; + } + return ret; +#endif // HAVE_STRFTIME/!HAVE_STRFTIME +} + +/* static */ +wxString wxDateTime::GetWeekDayName(wxDateTime::WeekDay wday, + wxDateTime::NameFlags flags) +{ + wxCHECK_MSG( wday != Inv_WeekDay, wxEmptyString, _T("invalid weekday") ); +#ifdef HAVE_STRFTIME + // take some arbitrary Sunday (but notice that the day should be such that + // after adding wday to it below we still have a valid date, e.g. don't + // take 28 here!) + tm tm; + InitTm(tm); + tm.tm_mday = 21; + tm.tm_mon = Nov; + tm.tm_year = 99; + + // and offset it by the number of days needed to get the correct wday + tm.tm_mday += wday; + + // call mktime() to normalize it... + (void)mktime(&tm); + + // ... and call strftime() + return CallStrftime(flags == Name_Abbr ? _T("%a") : _T("%A"), &tm); +#else // !HAVE_STRFTIME + wxString ret; + switch(wday) + { + case Sun: + ret = (flags == Name_Abbr ? wxT("Sun") : wxT("Sunday")); + break; + case Mon: + ret = (flags == Name_Abbr ? wxT("Mon") : wxT("Monday")); + break; + case Tue: + ret = (flags == Name_Abbr ? wxT("Tue") : wxT("Tuesday")); + break; + case Wed: + ret = (flags == Name_Abbr ? wxT("Wed") : wxT("Wednesday")); + break; + case Thu: + ret = (flags == Name_Abbr ? wxT("Thu") : wxT("Thursday")); + break; + case Fri: + ret = (flags == Name_Abbr ? wxT("Fri") : wxT("Friday")); + break; + case Sat: + ret = (flags == Name_Abbr ? wxT("Sat") : wxT("Saturday")); + break; + } + return ret; +#endif // HAVE_STRFTIME/!HAVE_STRFTIME +} + +/* static */ +void wxDateTime::GetAmPmStrings(wxString *am, wxString *pm) +{ + tm tm; + InitTm(tm); + wxChar buffer[64]; + // @Note: Do not call 'CallStrftime' here! CallStrftime checks the return code + // and causes an assertion failed if the buffer is to small (which is good) - OR - + // if strftime does not return anything because the format string is invalid - OR - + // if there are no 'am' / 'pm' tokens defined for the current locale (which is not good). + // wxDateTime::ParseTime will try several different formats to parse the time. + // As a result, GetAmPmStrings might get called, even if the current locale + // does not define any 'am' / 'pm' tokens. In this case, wxStrftime would + // assert, even though it is a perfectly legal use. + if ( am ) + { + if (wxStrftime(buffer, sizeof(buffer)/sizeof(wxChar), _T("%p"), &tm) > 0) + *am = wxString(buffer); + else + *am = wxString(); + } + if ( pm ) + { + tm.tm_hour = 13; + if (wxStrftime(buffer, sizeof(buffer)/sizeof(wxChar), _T("%p"), &tm) > 0) + *pm = wxString(buffer); + else + *pm = wxString(); + } +} + +// ---------------------------------------------------------------------------- +// Country stuff: date calculations depend on the country (DST, work days, +// ...), so we need to know which rules to follow. +// ---------------------------------------------------------------------------- + +/* static */ +wxDateTime::Country wxDateTime::GetCountry() +{ + // TODO use LOCALE_ICOUNTRY setting under Win32 +#ifndef __WXWINCE__ + if ( ms_country == Country_Unknown ) + { + // try to guess from the time zone name + time_t t = time(NULL); + struct tm tmstruct; + struct tm *tm = wxLocaltime_r(&t, &tmstruct); + + wxString tz = CallStrftime(_T("%Z"), tm); + if ( tz == _T("WET") || tz == _T("WEST") ) + { + ms_country = UK; + } + else if ( tz == _T("CET") || tz == _T("CEST") ) + { + ms_country = Country_EEC; + } + else if ( tz == _T("MSK") || tz == _T("MSD") ) + { + ms_country = Russia; + } + else if ( tz == _T("AST") || tz == _T("ADT") || + tz == _T("EST") || tz == _T("EDT") || + tz == _T("CST") || tz == _T("CDT") || + tz == _T("MST") || tz == _T("MDT") || + tz == _T("PST") || tz == _T("PDT") ) + { + ms_country = USA; + } + else + { + // well, choose a default one + ms_country = USA; + } + } +#else // __WXWINCE__ + ms_country = USA; +#endif // !__WXWINCE__/__WXWINCE__ + + return ms_country; +} + +/* static */ +void wxDateTime::SetCountry(wxDateTime::Country country) +{ + ms_country = country; +} + +/* static */ +bool wxDateTime::IsWestEuropeanCountry(Country country) +{ + if ( country == Country_Default ) + { + country = GetCountry(); + } + + return (Country_WesternEurope_Start <= country) && + (country <= Country_WesternEurope_End); +} + +// ---------------------------------------------------------------------------- +// DST calculations: we use 3 different rules for the West European countries, +// USA and for the rest of the world. This is undoubtedly false for many +// countries, but I lack the necessary info (and the time to gather it), +// please add the other rules here! +// ---------------------------------------------------------------------------- + +/* static */ +bool wxDateTime::IsDSTApplicable(int year, Country country) +{ + if ( year == Inv_Year ) + { + // take the current year if none given + year = GetCurrentYear(); + } + + if ( country == Country_Default ) + { + country = GetCountry(); + } + + switch ( country ) + { + case USA: + case UK: + // DST was first observed in the US and UK during WWI, reused + // during WWII and used again since 1966 + return year >= 1966 || + (year >= 1942 && year <= 1945) || + (year == 1918 || year == 1919); + + default: + // assume that it started after WWII + return year > 1950; + } +} + +/* static */ +wxDateTime wxDateTime::GetBeginDST(int year, Country country) +{ + if ( year == Inv_Year ) + { + // take the current year if none given + year = GetCurrentYear(); + } + + if ( country == Country_Default ) + { + country = GetCountry(); + } + + if ( !IsDSTApplicable(year, country) ) + { + return wxInvalidDateTime; + } + + wxDateTime dt; + + if ( IsWestEuropeanCountry(country) || (country == Russia) ) + { + // DST begins at 1 a.m. GMT on the last Sunday of March + if ( !dt.SetToLastWeekDay(Sun, Mar, year) ) + { + // weird... + wxFAIL_MSG( _T("no last Sunday in March?") ); + } + + dt += wxTimeSpan::Hours(1); + + // disable DST tests because it could result in an infinite recursion! + dt.MakeGMT(true); + } + else switch ( country ) + { + case USA: + switch ( year ) + { + case 1918: + case 1919: + // don't know for sure - assume it was in effect all year + + case 1943: + case 1944: + case 1945: + dt.Set(1, Jan, year); + break; + + case 1942: + // DST was installed Feb 2, 1942 by the Congress + dt.Set(2, Feb, year); + break; + + // Oil embargo changed the DST period in the US + case 1974: + dt.Set(6, Jan, 1974); + break; + + case 1975: + dt.Set(23, Feb, 1975); + break; + + default: + // before 1986, DST begun on the last Sunday of April, but + // in 1986 Reagan changed it to begin at 2 a.m. of the + // first Sunday in April + if ( year < 1986 ) + { + if ( !dt.SetToLastWeekDay(Sun, Apr, year) ) + { + // weird... + wxFAIL_MSG( _T("no first Sunday in April?") ); + } + } + else if ( year > 2006 ) + // Energy Policy Act of 2005, Pub. L. no. 109-58, 119 Stat 594 (2005). + // Starting in 2007, daylight time begins in the United States on the + // second Sunday in March and ends on the first Sunday in November + { + if ( !dt.SetToWeekDay(Sun, 2, Mar, year) ) + { + // weird... + wxFAIL_MSG( _T("no second Sunday in March?") ); + } + } + else + { + if ( !dt.SetToWeekDay(Sun, 1, Apr, year) ) + { + // weird... + wxFAIL_MSG( _T("no first Sunday in April?") ); + } + } + + dt += wxTimeSpan::Hours(2); + + // TODO what about timezone?? + } + + break; + + default: + // assume Mar 30 as the start of the DST for the rest of the world + // - totally bogus, of course + dt.Set(30, Mar, year); + } + + return dt; +} + +/* static */ +wxDateTime wxDateTime::GetEndDST(int year, Country country) +{ + if ( year == Inv_Year ) + { + // take the current year if none given + year = GetCurrentYear(); + } + + if ( country == Country_Default ) + { + country = GetCountry(); + } + + if ( !IsDSTApplicable(year, country) ) + { + return wxInvalidDateTime; + } + + wxDateTime dt; + + if ( IsWestEuropeanCountry(country) || (country == Russia) ) + { + // DST ends at 1 a.m. GMT on the last Sunday of October + if ( !dt.SetToLastWeekDay(Sun, Oct, year) ) + { + // weirder and weirder... + wxFAIL_MSG( _T("no last Sunday in October?") ); + } + + dt += wxTimeSpan::Hours(1); + + // disable DST tests because it could result in an infinite recursion! + dt.MakeGMT(true); + } + else switch ( country ) + { + case USA: + switch ( year ) + { + case 1918: + case 1919: + // don't know for sure - assume it was in effect all year + + case 1943: + case 1944: + dt.Set(31, Dec, year); + break; + + case 1945: + // the time was reset after the end of the WWII + dt.Set(30, Sep, year); + break; + + default: // default for switch (year) + if ( year > 2006 ) + // Energy Policy Act of 2005, Pub. L. no. 109-58, 119 Stat 594 (2005). + // Starting in 2007, daylight time begins in the United States on the + // second Sunday in March and ends on the first Sunday in November + { + if ( !dt.SetToWeekDay(Sun, 1, Nov, year) ) + { + // weird... + wxFAIL_MSG( _T("no first Sunday in November?") ); + } + } + else + // pre-2007 + // DST ends at 2 a.m. on the last Sunday of October + { + if ( !dt.SetToLastWeekDay(Sun, Oct, year) ) + { + // weirder and weirder... + wxFAIL_MSG( _T("no last Sunday in October?") ); + } + } + + dt += wxTimeSpan::Hours(2); + + // TODO: what about timezone?? + } + break; + + default: // default for switch (country) + // assume October 26th as the end of the DST - totally bogus too + dt.Set(26, Oct, year); + } + + return dt; +} + +// ---------------------------------------------------------------------------- +// constructors and assignment operators +// ---------------------------------------------------------------------------- + +// return the current time with ms precision +/* static */ wxDateTime wxDateTime::UNow() +{ + return wxDateTime(wxGetLocalTimeMillis()); +} + +// the values in the tm structure contain the local time +wxDateTime& wxDateTime::Set(const struct tm& tm) +{ + struct tm tm2(tm); + time_t timet = mktime(&tm2); + + if ( timet == (time_t)-1 ) + { + // mktime() rather unintuitively fails for Jan 1, 1970 if the hour is + // less than timezone - try to make it work for this case + if ( tm2.tm_year == 70 && tm2.tm_mon == 0 && tm2.tm_mday == 1 ) + { + return Set((time_t)( + GetTimeZone() + + tm2.tm_hour * MIN_PER_HOUR * SEC_PER_MIN + + tm2.tm_min * SEC_PER_MIN + + tm2.tm_sec)); + } + + wxFAIL_MSG( _T("mktime() failed") ); + + *this = wxInvalidDateTime; + + return *this; + } + else + { + return Set(timet); + } +} + +wxDateTime& wxDateTime::Set(wxDateTime_t hour, + wxDateTime_t minute, + wxDateTime_t second, + wxDateTime_t millisec) +{ + // we allow seconds to be 61 to account for the leap seconds, even if we + // don't use them really + wxDATETIME_CHECK( hour < 24 && + second < 62 && + minute < 60 && + millisec < 1000, + _T("Invalid time in wxDateTime::Set()") ); + + // get the current date from system + struct tm tmstruct; + struct tm *tm = GetTmNow(&tmstruct); + + wxDATETIME_CHECK( tm, _T("wxLocaltime_r() failed") ); + + // make a copy so it isn't clobbered by the call to mktime() below + struct tm tm1(*tm); + + // adjust the time + tm1.tm_hour = hour; + tm1.tm_min = minute; + tm1.tm_sec = second; + + // and the DST in case it changes on this date + struct tm tm2(tm1); + mktime(&tm2); + if ( tm2.tm_isdst != tm1.tm_isdst ) + tm1.tm_isdst = tm2.tm_isdst; + + (void)Set(tm1); + + // and finally adjust milliseconds + return SetMillisecond(millisec); +} + +wxDateTime& wxDateTime::Set(wxDateTime_t day, + Month month, + int year, + wxDateTime_t hour, + wxDateTime_t minute, + wxDateTime_t second, + wxDateTime_t millisec) +{ + wxDATETIME_CHECK( hour < 24 && + second < 62 && + minute < 60 && + millisec < 1000, + _T("Invalid time in wxDateTime::Set()") ); + + ReplaceDefaultYearMonthWithCurrent(&year, &month); + + wxDATETIME_CHECK( (0 < day) && (day <= GetNumberOfDays(month, year)), + _T("Invalid date in wxDateTime::Set()") ); + + // the range of time_t type (inclusive) + static const int yearMinInRange = 1970; + static const int yearMaxInRange = 2037; + + // test only the year instead of testing for the exact end of the Unix + // time_t range - it doesn't bring anything to do more precise checks + if ( year >= yearMinInRange && year <= yearMaxInRange ) + { + // use the standard library version if the date is in range - this is + // probably more efficient than our code + struct tm tm; + tm.tm_year = year - 1900; + tm.tm_mon = month; + tm.tm_mday = day; + tm.tm_hour = hour; + tm.tm_min = minute; + tm.tm_sec = second; + tm.tm_isdst = -1; // mktime() will guess it + + (void)Set(tm); + + // and finally adjust milliseconds + if (IsValid()) + SetMillisecond(millisec); + + return *this; + } + else + { + // do time calculations ourselves: we want to calculate the number of + // milliseconds between the given date and the epoch + + // get the JDN for the midnight of this day + m_time = GetTruncatedJDN(day, month, year); + m_time -= EPOCH_JDN; + m_time *= SECONDS_PER_DAY * TIME_T_FACTOR; + + // JDN corresponds to GMT, we take localtime + Add(wxTimeSpan(hour, minute, second + GetTimeZone(), millisec)); + } + + return *this; +} + +wxDateTime& wxDateTime::Set(double jdn) +{ + // so that m_time will be 0 for the midnight of Jan 1, 1970 which is jdn + // EPOCH_JDN + 0.5 + jdn -= EPOCH_JDN + 0.5; + + m_time.Assign(jdn*MILLISECONDS_PER_DAY); + + // JDNs always are in UTC, so we don't need any adjustments for time zone + + return *this; +} + +wxDateTime& wxDateTime::ResetTime() +{ + Tm tm = GetTm(); + + if ( tm.hour || tm.min || tm.sec || tm.msec ) + { + tm.msec = + tm.sec = + tm.min = + tm.hour = 0; + + Set(tm); + } + + return *this; +} + +wxDateTime wxDateTime::GetDateOnly() const +{ + Tm tm = GetTm(); + tm.msec = + tm.sec = + tm.min = + tm.hour = 0; + return wxDateTime(tm); +} + +// ---------------------------------------------------------------------------- +// DOS Date and Time Format functions +// ---------------------------------------------------------------------------- +// the dos date and time value is an unsigned 32 bit value in the format: +// YYYYYYYMMMMDDDDDhhhhhmmmmmmsssss +// +// Y = year offset from 1980 (0-127) +// M = month (1-12) +// D = day of month (1-31) +// h = hour (0-23) +// m = minute (0-59) +// s = bisecond (0-29) each bisecond indicates two seconds +// ---------------------------------------------------------------------------- + +wxDateTime& wxDateTime::SetFromDOS(unsigned long ddt) +{ + struct tm tm; + InitTm(tm); + + long year = ddt & 0xFE000000; + year >>= 25; + year += 80; + tm.tm_year = year; + + long month = ddt & 0x1E00000; + month >>= 21; + month -= 1; + tm.tm_mon = month; + + long day = ddt & 0x1F0000; + day >>= 16; + tm.tm_mday = day; + + long hour = ddt & 0xF800; + hour >>= 11; + tm.tm_hour = hour; + + long minute = ddt & 0x7E0; + minute >>= 5; + tm.tm_min = minute; + + long second = ddt & 0x1F; + tm.tm_sec = second * 2; + + return Set(mktime(&tm)); +} + +unsigned long wxDateTime::GetAsDOS() const +{ + unsigned long ddt; + time_t ticks = GetTicks(); + struct tm tmstruct; + struct tm *tm = wxLocaltime_r(&ticks, &tmstruct); + wxCHECK_MSG( tm, ULONG_MAX, _T("time can't be represented in DOS format") ); + + long year = tm->tm_year; + year -= 80; + year <<= 25; + + long month = tm->tm_mon; + month += 1; + month <<= 21; + + long day = tm->tm_mday; + day <<= 16; + + long hour = tm->tm_hour; + hour <<= 11; + + long minute = tm->tm_min; + minute <<= 5; + + long second = tm->tm_sec; + second /= 2; + + ddt = year | month | day | hour | minute | second; + return ddt; +} + +// ---------------------------------------------------------------------------- +// time_t <-> broken down time conversions +// ---------------------------------------------------------------------------- + +wxDateTime::Tm wxDateTime::GetTm(const TimeZone& tz) const +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + time_t time = GetTicks(); + if ( time != (time_t)-1 ) + { + // use C RTL functions + struct tm tmstruct; + tm *tm; + if ( tz.GetOffset() == -GetTimeZone() ) + { + // we are working with local time + tm = wxLocaltime_r(&time, &tmstruct); + + // should never happen + wxCHECK_MSG( tm, Tm(), _T("wxLocaltime_r() failed") ); + } + else + { + time += (time_t)tz.GetOffset(); +#if defined(__VMS__) || defined(__WATCOMC__) // time is unsigned so avoid warning + int time2 = (int) time; + if ( time2 >= 0 ) +#else + if ( time >= 0 ) +#endif + { + tm = wxGmtime_r(&time, &tmstruct); + + // should never happen + wxCHECK_MSG( tm, Tm(), _T("wxGmtime_r() failed") ); + } + else + { + tm = (struct tm *)NULL; + } + } + + if ( tm ) + { + // adjust the milliseconds + Tm tm2(*tm, tz); + long timeOnly = (m_time % MILLISECONDS_PER_DAY).ToLong(); + tm2.msec = (wxDateTime_t)(timeOnly % 1000); + return tm2; + } + //else: use generic code below + } + + // remember the time and do the calculations with the date only - this + // eliminates rounding errors of the floating point arithmetics + + wxLongLong timeMidnight = m_time + tz.GetOffset() * 1000; + + long timeOnly = (timeMidnight % MILLISECONDS_PER_DAY).ToLong(); + + // we want to always have positive time and timeMidnight to be really + // the midnight before it + if ( timeOnly < 0 ) + { + timeOnly = MILLISECONDS_PER_DAY + timeOnly; + } + + timeMidnight -= timeOnly; + + // calculate the Gregorian date from JDN for the midnight of our date: + // this will yield day, month (in 1..12 range) and year + + // actually, this is the JDN for the noon of the previous day + long jdn = (timeMidnight / MILLISECONDS_PER_DAY).ToLong() + EPOCH_JDN; + + // CREDIT: code below is by Scott E. Lee (but bugs are mine) + + wxASSERT_MSG( jdn > -2, _T("JDN out of range") ); + + // calculate the century + long temp = (jdn + JDN_OFFSET) * 4 - 1; + long century = temp / DAYS_PER_400_YEARS; + + // then the year and day of year (1 <= dayOfYear <= 366) + temp = ((temp % DAYS_PER_400_YEARS) / 4) * 4 + 3; + long year = (century * 100) + (temp / DAYS_PER_4_YEARS); + long dayOfYear = (temp % DAYS_PER_4_YEARS) / 4 + 1; + + // and finally the month and day of the month + temp = dayOfYear * 5 - 3; + long month = temp / DAYS_PER_5_MONTHS; + long day = (temp % DAYS_PER_5_MONTHS) / 5 + 1; + + // month is counted from March - convert to normal + if ( month < 10 ) + { + month += 3; + } + else + { + year += 1; + month -= 9; + } + + // year is offset by 4800 + year -= 4800; + + // check that the algorithm gave us something reasonable + wxASSERT_MSG( (0 < month) && (month <= 12), _T("invalid month") ); + wxASSERT_MSG( (1 <= day) && (day < 32), _T("invalid day") ); + + // construct Tm from these values + Tm tm; + tm.year = (int)year; + tm.mon = (Month)(month - 1); // algorithm yields 1 for January, not 0 + tm.mday = (wxDateTime_t)day; + tm.msec = (wxDateTime_t)(timeOnly % 1000); + timeOnly -= tm.msec; + timeOnly /= 1000; // now we have time in seconds + + tm.sec = (wxDateTime_t)(timeOnly % SEC_PER_MIN); + timeOnly -= tm.sec; + timeOnly /= SEC_PER_MIN; // now we have time in minutes + + tm.min = (wxDateTime_t)(timeOnly % MIN_PER_HOUR); + timeOnly -= tm.min; + + tm.hour = (wxDateTime_t)(timeOnly / MIN_PER_HOUR); + + return tm; +} + +wxDateTime& wxDateTime::SetYear(int year) +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + Tm tm(GetTm()); + tm.year = year; + Set(tm); + + return *this; +} + +wxDateTime& wxDateTime::SetMonth(Month month) +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + Tm tm(GetTm()); + tm.mon = month; + Set(tm); + + return *this; +} + +wxDateTime& wxDateTime::SetDay(wxDateTime_t mday) +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + Tm tm(GetTm()); + tm.mday = mday; + Set(tm); + + return *this; +} + +wxDateTime& wxDateTime::SetHour(wxDateTime_t hour) +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + Tm tm(GetTm()); + tm.hour = hour; + Set(tm); + + return *this; +} + +wxDateTime& wxDateTime::SetMinute(wxDateTime_t min) +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + Tm tm(GetTm()); + tm.min = min; + Set(tm); + + return *this; +} + +wxDateTime& wxDateTime::SetSecond(wxDateTime_t sec) +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + Tm tm(GetTm()); + tm.sec = sec; + Set(tm); + + return *this; +} + +wxDateTime& wxDateTime::SetMillisecond(wxDateTime_t millisecond) +{ + wxASSERT_MSG( IsValid(), _T("invalid wxDateTime") ); + + // we don't need to use GetTm() for this one + m_time -= m_time % 1000l; + m_time += millisecond; + + return *this; +} + +// ---------------------------------------------------------------------------- +// wxDateTime arithmetics +// ---------------------------------------------------------------------------- + +wxDateTime& wxDateTime::Add(const wxDateSpan& diff) +{ + Tm tm(GetTm()); + + tm.year += diff.GetYears(); + tm.AddMonths(diff.GetMonths()); + + // check that the resulting date is valid + if ( tm.mday > GetNumOfDaysInMonth(tm.year, tm.mon) ) + { + // We suppose that when adding one month to Jan 31 we want to get Feb + // 28 (or 29), i.e. adding a month to the last day of the month should + // give the last day of the next month which is quite logical. + // + // Unfortunately, there is no logic way to understand what should + // Jan 30 + 1 month be - Feb 28 too or Feb 27 (assuming non leap year)? + // We make it Feb 28 (last day too), but it is highly questionable. + tm.mday = GetNumOfDaysInMonth(tm.year, tm.mon); + } + + tm.AddDays(diff.GetTotalDays()); + + Set(tm); + + wxASSERT_MSG( IsSameTime(tm), + _T("Add(wxDateSpan) shouldn't modify time") ); + + return *this; +} + +// ---------------------------------------------------------------------------- +// Weekday and monthday stuff +// ---------------------------------------------------------------------------- + +// convert Sun, Mon, ..., Sat into 6, 0, ..., 5 +static inline int ConvertWeekDayToMondayBase(int wd) +{ + return wd == wxDateTime::Sun ? 6 : wd - 1; +} + +/* static */ +wxDateTime +wxDateTime::SetToWeekOfYear(int year, wxDateTime_t numWeek, WeekDay wd) +{ + wxASSERT_MSG( numWeek > 0, + _T("invalid week number: weeks are counted from 1") ); + + // Jan 4 always lies in the 1st week of the year + wxDateTime dt(4, Jan, year); + dt.SetToWeekDayInSameWeek(wd); + dt += wxDateSpan::Weeks(numWeek - 1); + + return dt; +} + +#if WXWIN_COMPATIBILITY_2_6 +// use a separate function to avoid warnings about using deprecated +// SetToTheWeek in GetWeek below +static wxDateTime +SetToTheWeek(int year, + wxDateTime::wxDateTime_t numWeek, + wxDateTime::WeekDay weekday, + wxDateTime::WeekFlags flags) +{ + // Jan 4 always lies in the 1st week of the year + wxDateTime dt(4, wxDateTime::Jan, year); + dt.SetToWeekDayInSameWeek(weekday, flags); + dt += wxDateSpan::Weeks(numWeek - 1); + + return dt; +} + +bool wxDateTime::SetToTheWeek(wxDateTime_t numWeek, + WeekDay weekday, + WeekFlags flags) +{ + int year = GetYear(); + *this = ::SetToTheWeek(year, numWeek, weekday, flags); + if ( GetYear() != year ) + { + // oops... numWeek was too big + return false; + } + + return true; +} + +wxDateTime wxDateTime::GetWeek(wxDateTime_t numWeek, + WeekDay weekday, + WeekFlags flags) const +{ + return ::SetToTheWeek(GetYear(), numWeek, weekday, flags); +} +#endif // WXWIN_COMPATIBILITY_2_6 + +wxDateTime& wxDateTime::SetToLastMonthDay(Month month, + int year) +{ + // take the current month/year if none specified + if ( year == Inv_Year ) + year = GetYear(); + if ( month == Inv_Month ) + month = GetMonth(); + + return Set(GetNumOfDaysInMonth(year, month), month, year); +} + +wxDateTime& wxDateTime::SetToWeekDayInSameWeek(WeekDay weekday, WeekFlags flags) +{ + wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") ); + + int wdayDst = weekday, + wdayThis = GetWeekDay(); + if ( wdayDst == wdayThis ) + { + // nothing to do + return *this; + } + + if ( flags == Default_First ) + { + flags = GetCountry() == USA ? Sunday_First : Monday_First; + } + + // the logic below based on comparing weekday and wdayThis works if Sun (0) + // is the first day in the week, but breaks down for Monday_First case so + // we adjust the week days in this case + if ( flags == Monday_First ) + { + if ( wdayThis == Sun ) + wdayThis += 7; + if ( wdayDst == Sun ) + wdayDst += 7; + } + //else: Sunday_First, nothing to do + + // go forward or back in time to the day we want + if ( wdayDst < wdayThis ) + { + return Subtract(wxDateSpan::Days(wdayThis - wdayDst)); + } + else // weekday > wdayThis + { + return Add(wxDateSpan::Days(wdayDst - wdayThis)); + } +} + +wxDateTime& wxDateTime::SetToNextWeekDay(WeekDay weekday) +{ + wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") ); + + int diff; + WeekDay wdayThis = GetWeekDay(); + if ( weekday == wdayThis ) + { + // nothing to do + return *this; + } + else if ( weekday < wdayThis ) + { + // need to advance a week + diff = 7 - (wdayThis - weekday); + } + else // weekday > wdayThis + { + diff = weekday - wdayThis; + } + + return Add(wxDateSpan::Days(diff)); +} + +wxDateTime& wxDateTime::SetToPrevWeekDay(WeekDay weekday) +{ + wxDATETIME_CHECK( weekday != Inv_WeekDay, _T("invalid weekday") ); + + int diff; + WeekDay wdayThis = GetWeekDay(); + if ( weekday == wdayThis ) + { + // nothing to do + return *this; + } + else if ( weekday > wdayThis ) + { + // need to go to previous week + diff = 7 - (weekday - wdayThis); + } + else // weekday < wdayThis + { + diff = wdayThis - weekday; + } + + return Subtract(wxDateSpan::Days(diff)); +} + +bool wxDateTime::SetToWeekDay(WeekDay weekday, + int n, + Month month, + int year) +{ + wxCHECK_MSG( weekday != Inv_WeekDay, false, _T("invalid weekday") ); + + // we don't check explicitly that -5 <= n <= 5 because we will return false + // anyhow in such case - but may be should still give an assert for it? + + // take the current month/year if none specified + ReplaceDefaultYearMonthWithCurrent(&year, &month); + + wxDateTime dt; + + // TODO this probably could be optimised somehow... + + if ( n > 0 ) + { + // get the first day of the month + dt.Set(1, month, year); + + // get its wday + WeekDay wdayFirst = dt.GetWeekDay(); + + // go to the first weekday of the month + int diff = weekday - wdayFirst; + if ( diff < 0 ) + diff += 7; + + // add advance n-1 weeks more + diff += 7*(n - 1); + + dt += wxDateSpan::Days(diff); + } + else // count from the end of the month + { + // get the last day of the month + dt.SetToLastMonthDay(month, year); + + // get its wday + WeekDay wdayLast = dt.GetWeekDay(); + + // go to the last weekday of the month + int diff = wdayLast - weekday; + if ( diff < 0 ) + diff += 7; + + // and rewind n-1 weeks from there + diff += 7*(-n - 1); + + dt -= wxDateSpan::Days(diff); + } + + // check that it is still in the same month + if ( dt.GetMonth() == month ) + { + *this = dt; + + return true; + } + else + { + // no such day in this month + return false; + } +} + +static inline +wxDateTime::wxDateTime_t GetDayOfYearFromTm(const wxDateTime::Tm& tm) +{ + return (wxDateTime::wxDateTime_t)(gs_cumulatedDays[wxDateTime::IsLeapYear(tm.year)][tm.mon] + tm.mday); +} + +wxDateTime::wxDateTime_t wxDateTime::GetDayOfYear(const TimeZone& tz) const +{ + return GetDayOfYearFromTm(GetTm(tz)); +} + +wxDateTime::wxDateTime_t +wxDateTime::GetWeekOfYear(wxDateTime::WeekFlags flags, const TimeZone& tz) const +{ + if ( flags == Default_First ) + { + flags = GetCountry() == USA ? Sunday_First : Monday_First; + } + + Tm tm(GetTm(tz)); + wxDateTime_t nDayInYear = GetDayOfYearFromTm(tm); + + int wdTarget = GetWeekDay(tz); + int wdYearStart = wxDateTime(1, Jan, GetYear()).GetWeekDay(); + int week; + if ( flags == Sunday_First ) + { + // FIXME: First week is not calculated correctly. + week = (nDayInYear - wdTarget + 7) / 7; + if ( wdYearStart == Wed || wdYearStart == Thu ) + week++; + } + else // week starts with monday + { + // adjust the weekdays to non-US style. + wdYearStart = ConvertWeekDayToMondayBase(wdYearStart); + wdTarget = ConvertWeekDayToMondayBase(wdTarget); + + // quoting from http://www.cl.cam.ac.uk/~mgk25/iso-time.html: + // + // Week 01 of a year is per definition the first week that has the + // Thursday in this year, which is equivalent to the week that + // contains the fourth day of January. In other words, the first + // week of a new year is the week that has the majority of its + // days in the new year. Week 01 might also contain days from the + // previous year and the week before week 01 of a year is the last + // week (52 or 53) of the previous year even if it contains days + // from the new year. A week starts with Monday (day 1) and ends + // with Sunday (day 7). + // + + // if Jan 1 is Thursday or less, it is in the first week of this year + if ( wdYearStart < 4 ) + { + // count the number of entire weeks between Jan 1 and this date + week = (nDayInYear + wdYearStart + 6 - wdTarget)/7; + + // be careful to check for overflow in the next year + if ( week == 53 && tm.mday - wdTarget > 28 ) + week = 1; + } + else // Jan 1 is in the last week of the previous year + { + // check if we happen to be at the last week of previous year: + if ( tm.mon == Jan && tm.mday < 8 - wdYearStart ) + week = wxDateTime(31, Dec, GetYear()-1).GetWeekOfYear(); + else + week = (nDayInYear + wdYearStart - 1 - wdTarget)/7; + } + } + + return (wxDateTime::wxDateTime_t)week; +} + +wxDateTime::wxDateTime_t wxDateTime::GetWeekOfMonth(wxDateTime::WeekFlags flags, + const TimeZone& tz) const +{ + Tm tm = GetTm(tz); + const wxDateTime dateFirst = wxDateTime(1, tm.mon, tm.year); + const wxDateTime::WeekDay wdFirst = dateFirst.GetWeekDay(); + + if ( flags == Default_First ) + { + flags = GetCountry() == USA ? Sunday_First : Monday_First; + } + + // compute offset of dateFirst from the beginning of the week + int firstOffset; + if ( flags == Sunday_First ) + firstOffset = wdFirst - Sun; + else + firstOffset = wdFirst == Sun ? DAYS_PER_WEEK - 1 : wdFirst - Mon; + + return (wxDateTime::wxDateTime_t)((tm.mday - 1 + firstOffset)/7 + 1); +} + +wxDateTime& wxDateTime::SetToYearDay(wxDateTime::wxDateTime_t yday) +{ + int year = GetYear(); + wxDATETIME_CHECK( (0 < yday) && (yday <= GetNumberOfDays(year)), + _T("invalid year day") ); + + bool isLeap = IsLeapYear(year); + for ( Month mon = Jan; mon < Inv_Month; wxNextMonth(mon) ) + { + // for Dec, we can't compare with gs_cumulatedDays[mon + 1], but we + // don't need it neither - because of the CHECK above we know that + // yday lies in December then + if ( (mon == Dec) || (yday <= gs_cumulatedDays[isLeap][mon + 1]) ) + { + Set((wxDateTime::wxDateTime_t)(yday - gs_cumulatedDays[isLeap][mon]), mon, year); + + break; + } + } + + return *this; +} + +// ---------------------------------------------------------------------------- +// Julian day number conversion and related stuff +// ---------------------------------------------------------------------------- + +double wxDateTime::GetJulianDayNumber() const +{ + return m_time.ToDouble() / MILLISECONDS_PER_DAY + EPOCH_JDN + 0.5; +} + +double wxDateTime::GetRataDie() const +{ + // March 1 of the year 0 is Rata Die day -306 and JDN 1721119.5 + return GetJulianDayNumber() - 1721119.5 - 306; +} + +// ---------------------------------------------------------------------------- +// timezone and DST stuff +// ---------------------------------------------------------------------------- + +int wxDateTime::IsDST(wxDateTime::Country country) const +{ + wxCHECK_MSG( country == Country_Default, -1, + _T("country support not implemented") ); + + // use the C RTL for the dates in the standard range + time_t timet = GetTicks(); + if ( timet != (time_t)-1 ) + { + struct tm tmstruct; + tm *tm = wxLocaltime_r(&timet, &tmstruct); + + wxCHECK_MSG( tm, -1, _T("wxLocaltime_r() failed") ); + + return tm->tm_isdst; + } + else + { + int year = GetYear(); + + if ( !IsDSTApplicable(year, country) ) + { + // no DST time in this year in this country + return -1; + } + + return IsBetween(GetBeginDST(year, country), GetEndDST(year, country)); + } +} + +wxDateTime& wxDateTime::MakeTimezone(const TimeZone& tz, bool noDST) +{ + long secDiff = GetTimeZone() + tz.GetOffset(); + + // we need to know whether DST is or not in effect for this date unless + // the test disabled by the caller + if ( !noDST && (IsDST() == 1) ) + { + // FIXME we assume that the DST is always shifted by 1 hour + secDiff -= 3600; + } + + return Add(wxTimeSpan::Seconds(secDiff)); +} + +wxDateTime& wxDateTime::MakeFromTimezone(const TimeZone& tz, bool noDST) +{ + long secDiff = GetTimeZone() + tz.GetOffset(); + + // we need to know whether DST is or not in effect for this date unless + // the test disabled by the caller + if ( !noDST && (IsDST() == 1) ) + { + // FIXME we assume that the DST is always shifted by 1 hour + secDiff -= 3600; + } + + return Subtract(wxTimeSpan::Seconds(secDiff)); +} + +// ---------------------------------------------------------------------------- +// wxDateTime to/from text representations +// ---------------------------------------------------------------------------- + +wxString wxDateTime::Format(const wxChar *format, const TimeZone& tz) const +{ + wxCHECK_MSG( format, wxEmptyString, _T("NULL format in wxDateTime::Format") ); + + time_t time = GetTicks(); + + // we have to use our own implementation if the date is out of range of + // strftime() or if we use non standard specificators +#ifdef HAVE_STRFTIME + if ( (time != (time_t)-1) && !wxStrstr(format, _T("%l")) ) + { + // use strftime() + struct tm tmstruct; + struct tm *tm; + if ( tz.GetOffset() == -GetTimeZone() ) + { + // we are working with local time + tm = wxLocaltime_r(&time, &tmstruct); + + // should never happen + wxCHECK_MSG( tm, wxEmptyString, _T("wxLocaltime_r() failed") ); + } + else + { + time += (int)tz.GetOffset(); + +#if defined(__VMS__) || defined(__WATCOMC__) // time is unsigned so avoid warning + int time2 = (int) time; + if ( time2 >= 0 ) +#else + if ( time >= 0 ) +#endif + { + tm = wxGmtime_r(&time, &tmstruct); + + // should never happen + wxCHECK_MSG( tm, wxEmptyString, _T("wxGmtime_r() failed") ); + } + else + { + tm = (struct tm *)NULL; + } + } + + if ( tm ) + { + return CallStrftime(format, tm); + } + } + //else: use generic code below +#endif // HAVE_STRFTIME + + // we only parse ANSI C format specifications here, no POSIX 2 + // complications, no GNU extensions but we do add support for a "%l" format + // specifier allowing to get the number of milliseconds + Tm tm = GetTm(tz); + + // used for calls to strftime() when we only deal with time + struct tm tmTimeOnly; + memset(&tmTimeOnly, 0, sizeof(tmTimeOnly)); + tmTimeOnly.tm_hour = tm.hour; + tmTimeOnly.tm_min = tm.min; + tmTimeOnly.tm_sec = tm.sec; + tmTimeOnly.tm_wday = 0; + tmTimeOnly.tm_yday = 0; + tmTimeOnly.tm_mday = 1; // any date will do, use 1976-01-01 + tmTimeOnly.tm_mon = 0; + tmTimeOnly.tm_year = 76; + tmTimeOnly.tm_isdst = 0; // no DST, we adjust for tz ourselves + + wxString tmp, res, fmt; + for ( const wxChar *p = format; *p; p++ ) + { + if ( *p != _T('%') ) + { + // copy as is + res += *p; + + continue; + } + + // set the default format + switch ( *++p ) + { + case _T('Y'): // year has 4 digits + fmt = _T("%04d"); + break; + + case _T('j'): // day of year has 3 digits + case _T('l'): // milliseconds have 3 digits + fmt = _T("%03d"); + break; + + case _T('w'): // week day as number has only one + fmt = _T("%d"); + break; + + default: + // it's either another valid format specifier in which case + // the format is "%02d" (for all the rest) or we have the + // field width preceding the format in which case it will + // override the default format anyhow + fmt = _T("%02d"); + } + + bool restart = true; + while ( restart ) + { + restart = false; + + // start of the format specification + switch ( *p ) + { + case _T('a'): // a weekday name + case _T('A'): + // second parameter should be true for abbreviated names + res += GetWeekDayName(tm.GetWeekDay(), + *p == _T('a') ? Name_Abbr : Name_Full); + break; + + case _T('b'): // a month name + case _T('B'): + res += GetMonthName(tm.mon, + *p == _T('b') ? Name_Abbr : Name_Full); + break; + + case _T('c'): // locale default date and time representation + case _T('x'): // locale default date representation +#ifdef HAVE_STRFTIME + // + // the problem: there is no way to know what do these format + // specifications correspond to for the current locale. + // + // the solution: use a hack and still use strftime(): first + // find the YEAR which is a year in the strftime() range (1970 + // - 2038) whose Jan 1 falls on the same week day as the Jan 1 + // of the real year. Then make a copy of the format and + // replace all occurrences of YEAR in it with some unique + // string not appearing anywhere else in it, then use + // strftime() to format the date in year YEAR and then replace + // YEAR back by the real year and the unique replacement + // string back with YEAR. Notice that "all occurrences of YEAR" + // means all occurrences of 4 digit as well as 2 digit form! + // + // the bugs: we assume that neither of %c nor %x contains any + // fields which may change between the YEAR and real year. For + // example, the week number (%U, %W) and the day number (%j) + // will change if one of these years is leap and the other one + // is not! + { + // find the YEAR: normally, for any year X, Jan 1 or the + // year X + 28 is the same weekday as Jan 1 of X (because + // the weekday advances by 1 for each normal X and by 2 + // for each leap X, hence by 5 every 4 years or by 35 + // which is 0 mod 7 every 28 years) but this rule breaks + // down if there are years between X and Y which are + // divisible by 4 but not leap (i.e. divisible by 100 but + // not 400), hence the correction. + + int yearReal = GetYear(tz); + int mod28 = yearReal % 28; + + // be careful to not go too far - we risk to leave the + // supported range + int year; + if ( mod28 < 10 ) + { + year = 1988 + mod28; // 1988 == 0 (mod 28) + } + else + { + year = 1970 + mod28 - 10; // 1970 == 10 (mod 28) + } + + int nCentury = year / 100, + nCenturyReal = yearReal / 100; + + // need to adjust for the years divisble by 400 which are + // not leap but are counted like leap ones if we just take + // the number of centuries in between for nLostWeekDays + int nLostWeekDays = (nCentury - nCenturyReal) - + (nCentury / 4 - nCenturyReal / 4); + + // we have to gain back the "lost" weekdays: note that the + // effect of this loop is to not do anything to + // nLostWeekDays (which we won't use any more), but to + // (indirectly) set the year correctly + while ( (nLostWeekDays % 7) != 0 ) + { + nLostWeekDays += year++ % 4 ? 1 : 2; + } + + // Keep year below 2000 so the 2digit year number + // can never match the month or day of the month + if (year>=2000) year-=28; + // at any rate, we couldn't go further than 1988 + 9 + 28! + wxASSERT_MSG( year < 2030, + _T("logic error in wxDateTime::Format") ); + + wxString strYear, strYear2; + strYear.Printf(_T("%d"), year); + strYear2.Printf(_T("%d"), year % 100); + + // find four strings not occurring in format (this is surely + // not the optimal way of doing it... improvements welcome!) + wxString fmt2 = format; + wxString replacement,replacement2,replacement3,replacement4; + for (int rnr=1; rnr<5 ; rnr++) + { + wxString r = (wxChar)-rnr; + while ( fmt2.Find(r) != wxNOT_FOUND ) + { + r << (wxChar)-rnr; + } + + switch (rnr) + { + case 1: replacement=r; break; + case 2: replacement2=r; break; + case 3: replacement3=r; break; + case 4: replacement4=r; break; + } + } + // replace all occurrences of year with it + bool wasReplaced = fmt2.Replace(strYear, replacement) > 0; + // evaluation order ensures we always attempt the replacement. + wasReplaced = (fmt2.Replace(strYear2, replacement2) > 0) || wasReplaced; + + // use strftime() to format the same date but in supported + // year + // + // NB: we assume that strftime() doesn't check for the + // date validity and will happily format the date + // corresponding to Feb 29 of a non leap year (which + // may happen if yearReal was leap and year is not) + struct tm tmAdjusted; + InitTm(tmAdjusted); + tmAdjusted.tm_hour = tm.hour; + tmAdjusted.tm_min = tm.min; + tmAdjusted.tm_sec = tm.sec; + tmAdjusted.tm_wday = tm.GetWeekDay(); + tmAdjusted.tm_yday = GetDayOfYear(); + tmAdjusted.tm_mday = tm.mday; + tmAdjusted.tm_mon = tm.mon; + tmAdjusted.tm_year = year - 1900; + tmAdjusted.tm_isdst = 0; // no DST, already adjusted + wxString str = CallStrftime(*p == _T('c') ? _T("%c") + : _T("%x"), + &tmAdjusted); + + // now replace the occurrence of 1999 with the real year + // we do this in two stages to stop the 2 digit year + // matching any substring of the 4 digit year. + // Any day,month hours and minutes components should be safe due + // to ensuring the range of the years. + wxString strYearReal, strYearReal2; + strYearReal.Printf(_T("%04d"), yearReal); + strYearReal2.Printf(_T("%02d"), yearReal % 100); + str.Replace(strYear, replacement3); + str.Replace(strYear2,replacement4); + str.Replace(replacement3, strYearReal); + str.Replace(replacement4, strYearReal2); + + // and replace back all occurrences of replacement string + if ( wasReplaced ) + { + str.Replace(replacement2, strYear2); + str.Replace(replacement, strYear); + } + + res += str; + } +#else // !HAVE_STRFTIME + // Use "%m/%d/%y %H:%M:%S" format instead + res += wxString::Format(wxT("%02d/%02d/%04d %02d:%02d:%02d"), + tm.mon+1,tm.mday, tm.year, tm.hour, tm.min, tm.sec); +#endif // HAVE_STRFTIME/!HAVE_STRFTIME + break; + + case _T('d'): // day of a month (01-31) + res += wxString::Format(fmt, tm.mday); + break; + + case _T('H'): // hour in 24h format (00-23) + res += wxString::Format(fmt, tm.hour); + break; + + case _T('I'): // hour in 12h format (01-12) + { + // 24h -> 12h, 0h -> 12h too + int hour12 = tm.hour > 12 ? tm.hour - 12 + : tm.hour ? tm.hour : 12; + res += wxString::Format(fmt, hour12); + } + break; + + case _T('j'): // day of the year + res += wxString::Format(fmt, GetDayOfYear(tz)); + break; + + case _T('l'): // milliseconds (NOT STANDARD) + res += wxString::Format(fmt, GetMillisecond(tz)); + break; + + case _T('m'): // month as a number (01-12) + res += wxString::Format(fmt, tm.mon + 1); + break; + + case _T('M'): // minute as a decimal number (00-59) + res += wxString::Format(fmt, tm.min); + break; + + case _T('p'): // AM or PM string +#ifdef HAVE_STRFTIME + res += CallStrftime(_T("%p"), &tmTimeOnly); +#else // !HAVE_STRFTIME + res += (tmTimeOnly.tm_hour > 12) ? wxT("pm") : wxT("am"); +#endif // HAVE_STRFTIME/!HAVE_STRFTIME + break; + + case _T('S'): // second as a decimal number (00-61) + res += wxString::Format(fmt, tm.sec); + break; + + case _T('U'): // week number in the year (Sunday 1st week day) + res += wxString::Format(fmt, GetWeekOfYear(Sunday_First, tz)); + break; + + case _T('W'): // week number in the year (Monday 1st week day) + res += wxString::Format(fmt, GetWeekOfYear(Monday_First, tz)); + break; + + case _T('w'): // weekday as a number (0-6), Sunday = 0 + res += wxString::Format(fmt, tm.GetWeekDay()); + break; + + // case _T('x'): -- handled with "%c" + + case _T('X'): // locale default time representation + // just use strftime() to format the time for us +#ifdef HAVE_STRFTIME + res += CallStrftime(_T("%X"), &tmTimeOnly); +#else // !HAVE_STRFTIME + res += wxString::Format(wxT("%02d:%02d:%02d"),tm.hour, tm.min, tm.sec); +#endif // HAVE_STRFTIME/!HAVE_STRFTIME + break; + + case _T('y'): // year without century (00-99) + res += wxString::Format(fmt, tm.year % 100); + break; + + case _T('Y'): // year with century + res += wxString::Format(fmt, tm.year); + break; + + case _T('Z'): // timezone name +#ifdef HAVE_STRFTIME + res += CallStrftime(_T("%Z"), &tmTimeOnly); +#endif + break; + + default: + // is it the format width? + for( fmt.clear(); + *p == _T('-') || *p == _T('+') || + *p == _T(' ') || wxIsdigit(*p); + ++p ) + { + fmt += *p; + } + + if ( !fmt.empty() ) + { + // we've only got the flags and width so far in fmt + fmt.Prepend(_T('%')); + fmt.Append(_T('d')); + + restart = true; + + break; + } + + // no, it wasn't the width + wxFAIL_MSG(_T("unknown format specificator")); + + // fall through and just copy it nevertheless + + case _T('%'): // a percent sign + res += *p; + break; + + case 0: // the end of string + wxFAIL_MSG(_T("missing format at the end of string")); + + // just put the '%' which was the last char in format + res += _T('%'); + break; + } + } + } + + return res; +} + +// this function parses a string in (strict) RFC 822 format: see the section 5 +// of the RFC for the detailed description, but briefly it's something of the +// form "Sat, 18 Dec 1999 00:48:30 +0100" +// +// this function is "strict" by design - it must reject anything except true +// RFC822 time specs. +// +// TODO a great candidate for using reg exps +const wxChar *wxDateTime::ParseRfc822Date(const wxChar* date) +{ + wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); + + const wxChar *p = date; + const wxChar *comma = wxStrchr(p, _T(',')); + if ( comma ) + { + // the part before comma is the weekday + + // skip it for now - we don't use but might check that it really + // corresponds to the specfied date + p = comma + 1; + + if ( *p != _T(' ') ) + { + wxLogDebug(_T("no space after weekday in RFC822 time spec")); + + return (wxChar *)NULL; + } + + p++; // skip space + } + + // the following 1 or 2 digits are the day number + if ( !wxIsdigit(*p) ) + { + wxLogDebug(_T("day number expected in RFC822 time spec, none found")); + + return (wxChar *)NULL; + } + + wxDateTime_t day = (wxDateTime_t)(*p++ - _T('0')); + if ( wxIsdigit(*p) ) + { + day *= 10; + day = (wxDateTime_t)(day + (*p++ - _T('0'))); + } + + if ( *p++ != _T(' ') ) + { + return (wxChar *)NULL; + } + + // the following 3 letters specify the month + wxString monName(p, 3); + Month mon; + if ( monName == _T("Jan") ) + mon = Jan; + else if ( monName == _T("Feb") ) + mon = Feb; + else if ( monName == _T("Mar") ) + mon = Mar; + else if ( monName == _T("Apr") ) + mon = Apr; + else if ( monName == _T("May") ) + mon = May; + else if ( monName == _T("Jun") ) + mon = Jun; + else if ( monName == _T("Jul") ) + mon = Jul; + else if ( monName == _T("Aug") ) + mon = Aug; + else if ( monName == _T("Sep") ) + mon = Sep; + else if ( monName == _T("Oct") ) + mon = Oct; + else if ( monName == _T("Nov") ) + mon = Nov; + else if ( monName == _T("Dec") ) + mon = Dec; + else + { + wxLogDebug(_T("Invalid RFC 822 month name '%s'"), monName.c_str()); + + return (wxChar *)NULL; + } + + p += 3; + + if ( *p++ != _T(' ') ) + { + return (wxChar *)NULL; + } + + // next is the year + if ( !wxIsdigit(*p) ) + { + // no year? + return (wxChar *)NULL; + } + + int year = *p++ - _T('0'); + + if ( !wxIsdigit(*p) ) + { + // should have at least 2 digits in the year + return (wxChar *)NULL; + } + + year *= 10; + year += *p++ - _T('0'); + + // is it a 2 digit year (as per original RFC 822) or a 4 digit one? + if ( wxIsdigit(*p) ) + { + year *= 10; + year += *p++ - _T('0'); + + if ( !wxIsdigit(*p) ) + { + // no 3 digit years please + return (wxChar *)NULL; + } + + year *= 10; + year += *p++ - _T('0'); + } + + if ( *p++ != _T(' ') ) + { + return (wxChar *)NULL; + } + + // time is in the format hh:mm:ss and seconds are optional + if ( !wxIsdigit(*p) ) + { + return (wxChar *)NULL; + } + + wxDateTime_t hour = (wxDateTime_t)(*p++ - _T('0')); + + if ( !wxIsdigit(*p) ) + { + return (wxChar *)NULL; + } + + hour *= 10; + hour = (wxDateTime_t)(hour + (*p++ - _T('0'))); + + if ( *p++ != _T(':') ) + { + return (wxChar *)NULL; + } + + if ( !wxIsdigit(*p) ) + { + return (wxChar *)NULL; + } + + wxDateTime_t min = (wxDateTime_t)(*p++ - _T('0')); + + if ( !wxIsdigit(*p) ) + { + return (wxChar *)NULL; + } + + min *= 10; + min = (wxDateTime_t)(min + *p++ - _T('0')); + + wxDateTime_t sec = 0; + if ( *p == _T(':') ) + { + p++; + if ( !wxIsdigit(*p) ) + { + return (wxChar *)NULL; + } + + sec = (wxDateTime_t)(*p++ - _T('0')); + + if ( !wxIsdigit(*p) ) + { + return (wxChar *)NULL; + } + + sec *= 10; + sec = (wxDateTime_t)(sec + *p++ - _T('0')); + } + + if ( *p++ != _T(' ') ) + { + return (wxChar *)NULL; + } + + // and now the interesting part: the timezone + int offset wxDUMMY_INITIALIZE(0); + if ( *p == _T('-') || *p == _T('+') ) + { + // the explicit offset given: it has the form of hhmm + bool plus = *p++ == _T('+'); + + if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) ) + { + return (wxChar *)NULL; + } + + // hours + offset = MIN_PER_HOUR*(10*(*p - _T('0')) + (*(p + 1) - _T('0'))); + + p += 2; + + if ( !wxIsdigit(*p) || !wxIsdigit(*(p + 1)) ) + { + return (wxChar *)NULL; + } + + // minutes + offset += 10*(*p - _T('0')) + (*(p + 1) - _T('0')); + + if ( !plus ) + { + offset = -offset; + } + + p += 2; + } + else + { + // the symbolic timezone given: may be either military timezone or one + // of standard abbreviations + if ( !*(p + 1) ) + { + // military: Z = UTC, J unused, A = -1, ..., Y = +12 + static const int offsets[26] = + { + //A B C D E F G H I J K L M + -1, -2, -3, -4, -5, -6, -7, -8, -9, 0, -10, -11, -12, + //N O P R Q S T U V W Z Y Z + +1, +2, +3, +4, +5, +6, +7, +8, +9, +10, +11, +12, 0 + }; + + if ( *p < _T('A') || *p > _T('Z') || *p == _T('J') ) + { + wxLogDebug(_T("Invalid militaty timezone '%c'"), *p); + + return (wxChar *)NULL; + } + + offset = offsets[*p++ - _T('A')]; + } + else + { + // abbreviation + wxString tz = p; + if ( tz == _T("UT") || tz == _T("UTC") || tz == _T("GMT") ) + offset = 0; + else if ( tz == _T("AST") ) + offset = AST - GMT0; + else if ( tz == _T("ADT") ) + offset = ADT - GMT0; + else if ( tz == _T("EST") ) + offset = EST - GMT0; + else if ( tz == _T("EDT") ) + offset = EDT - GMT0; + else if ( tz == _T("CST") ) + offset = CST - GMT0; + else if ( tz == _T("CDT") ) + offset = CDT - GMT0; + else if ( tz == _T("MST") ) + offset = MST - GMT0; + else if ( tz == _T("MDT") ) + offset = MDT - GMT0; + else if ( tz == _T("PST") ) + offset = PST - GMT0; + else if ( tz == _T("PDT") ) + offset = PDT - GMT0; + else + { + wxLogDebug(_T("Unknown RFC 822 timezone '%s'"), p); + + return (wxChar *)NULL; + } + + p += tz.length(); + } + + // make it minutes + offset *= MIN_PER_HOUR; + } + + // the spec was correct, construct the date from the values we found + Set(day, mon, year, hour, min, sec); + MakeFromTimezone(TimeZone::Make(offset*SEC_PER_MIN)); + + return p; +} + +#ifdef __WINDOWS__ + +// returns the string containing strftime() format used for short dates in the +// current locale or an empty string +static wxString GetLocaleDateFormat() +{ + wxString fmtWX; + + // there is no setlocale() under Windows CE, so just always query the + // system there +#ifndef __WXWINCE__ + if ( strcmp(setlocale(LC_ALL, NULL), "C") != 0 ) +#endif + { + // The locale was programatically set to non-C. We assume that this was + // done using wxLocale, in which case thread's current locale is also + // set to correct LCID value and we can use GetLocaleInfo to determine + // the correct formatting string: +#ifdef __WXWINCE__ + LCID lcid = LOCALE_USER_DEFAULT; +#else + LCID lcid = GetThreadLocale(); +#endif + // according to MSDN 80 chars is max allowed for short date format + wxChar fmt[81]; + if ( ::GetLocaleInfo(lcid, LOCALE_SSHORTDATE, fmt, WXSIZEOF(fmt)) ) + { + wxChar chLast = _T('\0'); + size_t lastCount = 0; + for ( const wxChar *p = fmt; /* NUL handled inside */; p++ ) + { + if ( *p == chLast ) + { + lastCount++; + continue; + } + + switch ( *p ) + { + // these characters come in groups, start counting them + case _T('d'): + case _T('M'): + case _T('y'): + case _T('g'): + chLast = *p; + lastCount = 1; + break; + + default: + // first deal with any special characters we have had + if ( lastCount ) + { + switch ( chLast ) + { + case _T('d'): + switch ( lastCount ) + { + case 1: // d + case 2: // dd + // these two are the same as we + // don't distinguish between 1 and + // 2 digits for days + fmtWX += _T("%d"); + break; + + case 3: // ddd + fmtWX += _T("%a"); + break; + + case 4: // dddd + fmtWX += _T("%A"); + break; + + default: + wxFAIL_MSG( _T("too many 'd's") ); + } + break; + + case _T('M'): + switch ( lastCount ) + { + case 1: // M + case 2: // MM + // as for 'd' and 'dd' above + fmtWX += _T("%m"); + break; + + case 3: + fmtWX += _T("%b"); + break; + + case 4: + fmtWX += _T("%B"); + break; + + default: + wxFAIL_MSG( _T("too many 'M's") ); + } + break; + + case _T('y'): + switch ( lastCount ) + { + case 1: // y + case 2: // yy + fmtWX += _T("%y"); + break; + + case 4: // yyyy + fmtWX += _T("%Y"); + break; + + default: + wxFAIL_MSG( _T("wrong number of 'y's") ); + } + break; + + case _T('g'): + // strftime() doesn't have era string, + // ignore this format + wxASSERT_MSG( lastCount <= 2, + _T("too many 'g's") ); + break; + + default: + wxFAIL_MSG( _T("unreachable") ); + } + + chLast = _T('\0'); + lastCount = 0; + } + + // not a special character so must be just a separator, + // treat as is + if ( *p != _T('\0') ) + { + if ( *p == _T('%') ) + { + // this one needs to be escaped + fmtWX += _T('%'); + } + + fmtWX += *p; + } + } + + if ( *p == _T('\0') ) + break; + } + } + //else: GetLocaleInfo() failed, leave fmtDate value unchanged and + // try our luck with the default formats + } + //else: default C locale, default formats should work + + return fmtWX; +} + +#endif // __WINDOWS__ + +const wxChar *wxDateTime::ParseFormat(const wxChar *date, + const wxChar *format, + const wxDateTime& dateDef) +{ + wxCHECK_MSG( date && format, (wxChar *)NULL, + _T("NULL pointer in wxDateTime::ParseFormat()") ); + + wxString str; + unsigned long num; + + // what fields have we found? + bool haveWDay = false, + haveYDay = false, + haveDay = false, + haveMon = false, + haveYear = false, + haveHour = false, + haveMin = false, + haveSec = false; + + bool hourIsIn12hFormat = false, // or in 24h one? + isPM = false; // AM by default + + // and the value of the items we have (init them to get rid of warnings) + wxDateTime_t sec = 0, + min = 0, + hour = 0; + WeekDay wday = Inv_WeekDay; + wxDateTime_t yday = 0, + mday = 0; + wxDateTime::Month mon = Inv_Month; + int year = 0; + + const wxChar *input = date; + for ( const wxChar *fmt = format; *fmt; fmt++ ) + { + if ( *fmt != _T('%') ) + { + if ( wxIsspace(*fmt) ) + { + // a white space in the format string matches 0 or more white + // spaces in the input + while ( wxIsspace(*input) ) + { + input++; + } + } + else // !space + { + // any other character (not whitespace, not '%') must be + // matched by itself in the input + if ( *input++ != *fmt ) + { + // no match + return (wxChar *)NULL; + } + } + + // done with this format char + continue; + } + + // start of a format specification + + // parse the optional width + size_t width = 0; + while ( wxIsdigit(*++fmt) ) + { + width *= 10; + width += *fmt - _T('0'); + } + + // the default widths for the various fields + if ( !width ) + { + switch ( *fmt ) + { + case _T('Y'): // year has 4 digits + width = 4; + break; + + case _T('j'): // day of year has 3 digits + case _T('l'): // milliseconds have 3 digits + width = 3; + break; + + case _T('w'): // week day as number has only one + width = 1; + break; + + default: + // default for all other fields + width = 2; + } + } + + // then the format itself + switch ( *fmt ) + { + case _T('a'): // a weekday name + case _T('A'): + { + int flag = *fmt == _T('a') ? Name_Abbr : Name_Full; + wday = GetWeekDayFromName(GetAlphaToken(input), flag); + if ( wday == Inv_WeekDay ) + { + // no match + return (wxChar *)NULL; + } + } + haveWDay = true; + break; + + case _T('b'): // a month name + case _T('B'): + { + int flag = *fmt == _T('b') ? Name_Abbr : Name_Full; + mon = GetMonthFromName(GetAlphaToken(input), flag); + if ( mon == Inv_Month ) + { + // no match + return (wxChar *)NULL; + } + } + haveMon = true; + break; + + case _T('c'): // locale default date and time representation + { + wxDateTime dt; + + // this is the format which corresponds to ctime() output + // and strptime("%c") should parse it, so try it first + static const wxChar *fmtCtime = _T("%a %b %d %H:%M:%S %Y"); + + const wxChar *result = dt.ParseFormat(input, fmtCtime); + if ( !result ) + { + result = dt.ParseFormat(input, _T("%x %X")); + } + + if ( !result ) + { + result = dt.ParseFormat(input, _T("%X %x")); + } + + if ( !result ) + { + // we've tried everything and still no match + return (wxChar *)NULL; + } + + Tm tm = dt.GetTm(); + + haveDay = haveMon = haveYear = + haveHour = haveMin = haveSec = true; + + hour = tm.hour; + min = tm.min; + sec = tm.sec; + + year = tm.year; + mon = tm.mon; + mday = tm.mday; + + input = result; + } + break; + + case _T('d'): // day of a month (01-31) + if ( !GetNumericToken(width, input, &num) || + (num > 31) || (num < 1) ) + { + // no match + return (wxChar *)NULL; + } + + // we can't check whether the day range is correct yet, will + // do it later - assume ok for now + haveDay = true; + mday = (wxDateTime_t)num; + break; + + case _T('H'): // hour in 24h format (00-23) + if ( !GetNumericToken(width, input, &num) || (num > 23) ) + { + // no match + return (wxChar *)NULL; + } + + haveHour = true; + hour = (wxDateTime_t)num; + break; + + case _T('I'): // hour in 12h format (01-12) + if ( !GetNumericToken(width, input, &num) || !num || (num > 12) ) + { + // no match + return (wxChar *)NULL; + } + + haveHour = true; + hourIsIn12hFormat = true; + hour = (wxDateTime_t)(num % 12); // 12 should be 0 + break; + + case _T('j'): // day of the year + if ( !GetNumericToken(width, input, &num) || !num || (num > 366) ) + { + // no match + return (wxChar *)NULL; + } + + haveYDay = true; + yday = (wxDateTime_t)num; + break; + + case _T('m'): // month as a number (01-12) + if ( !GetNumericToken(width, input, &num) || !num || (num > 12) ) + { + // no match + return (wxChar *)NULL; + } + + haveMon = true; + mon = (Month)(num - 1); + break; + + case _T('M'): // minute as a decimal number (00-59) + if ( !GetNumericToken(width, input, &num) || (num > 59) ) + { + // no match + return (wxChar *)NULL; + } + + haveMin = true; + min = (wxDateTime_t)num; + break; + + case _T('p'): // AM or PM string + { + wxString am, pm, token = GetAlphaToken(input); + + GetAmPmStrings(&am, &pm); + if (am.empty() && pm.empty()) + return (wxChar *)NULL; // no am/pm strings defined + if ( token.CmpNoCase(pm) == 0 ) + { + isPM = true; + } + else if ( token.CmpNoCase(am) != 0 ) + { + // no match + return (wxChar *)NULL; + } + } + break; + + case _T('r'): // time as %I:%M:%S %p + { + wxDateTime dt; + input = dt.ParseFormat(input, _T("%I:%M:%S %p")); + if ( !input ) + { + // no match + return (wxChar *)NULL; + } + + haveHour = haveMin = haveSec = true; + + Tm tm = dt.GetTm(); + hour = tm.hour; + min = tm.min; + sec = tm.sec; + } + break; + + case _T('R'): // time as %H:%M + { + wxDateTime dt; + input = dt.ParseFormat(input, _T("%H:%M")); + if ( !input ) + { + // no match + return (wxChar *)NULL; + } + + haveHour = haveMin = true; + + Tm tm = dt.GetTm(); + hour = tm.hour; + min = tm.min; + } + break; + + case _T('S'): // second as a decimal number (00-61) + if ( !GetNumericToken(width, input, &num) || (num > 61) ) + { + // no match + return (wxChar *)NULL; + } + + haveSec = true; + sec = (wxDateTime_t)num; + break; + + case _T('T'): // time as %H:%M:%S + { + wxDateTime dt; + input = dt.ParseFormat(input, _T("%H:%M:%S")); + if ( !input ) + { + // no match + return (wxChar *)NULL; + } + + haveHour = haveMin = haveSec = true; + + Tm tm = dt.GetTm(); + hour = tm.hour; + min = tm.min; + sec = tm.sec; + } + break; + + case _T('w'): // weekday as a number (0-6), Sunday = 0 + if ( !GetNumericToken(width, input, &num) || (wday > 6) ) + { + // no match + return (wxChar *)NULL; + } + + haveWDay = true; + wday = (WeekDay)num; + break; + + case _T('x'): // locale default date representation +#ifdef HAVE_STRPTIME + // try using strptime() -- it may fail even if the input is + // correct but the date is out of range, so we will fall back + // to our generic code anyhow + { + struct tm tm; + + const wxChar *result = CallStrptime(input, "%x", &tm); + if ( result ) + { + input = result; + + haveDay = haveMon = haveYear = true; + + year = 1900 + tm.tm_year; + mon = (Month)tm.tm_mon; + mday = tm.tm_mday; + + break; + } + } +#endif // HAVE_STRPTIME + + { + wxDateTime dt; + wxString fmtDate, + fmtDateAlt; + +#ifdef __WINDOWS__ + // The above doesn't work for all locales, try to query + // Windows for the right way of formatting the date: + fmtDate = GetLocaleDateFormat(); + if ( fmtDate.empty() ) +#endif + { + if ( IsWestEuropeanCountry(GetCountry()) || + GetCountry() == Russia ) + { + fmtDate = _T("%d/%m/%y"); + fmtDateAlt = _T("%m/%d/%y"); + } + else // assume USA + { + fmtDate = _T("%m/%d/%y"); + fmtDateAlt = _T("%d/%m/%y"); + } + } + + const wxChar *result = dt.ParseFormat(input, fmtDate); + + if ( !result && !fmtDateAlt.empty() ) + { + // ok, be nice and try another one + result = dt.ParseFormat(input, fmtDateAlt); + } + + if ( !result ) + { + // bad luck + return (wxChar *)NULL; + } + + Tm tm = dt.GetTm(); + + haveDay = haveMon = haveYear = true; + + year = tm.year; + mon = tm.mon; + mday = tm.mday; + + input = result; + } + + break; + + case _T('X'): // locale default time representation +#ifdef HAVE_STRPTIME + { + // use strptime() to do it for us (FIXME !Unicode friendly) + struct tm tm; + input = CallStrptime(input, "%X", &tm); + if ( !input ) + { + return (wxChar *)NULL; + } + + haveHour = haveMin = haveSec = true; + + hour = tm.tm_hour; + min = tm.tm_min; + sec = tm.tm_sec; + } +#else // !HAVE_STRPTIME + // TODO under Win32 we can query the LOCALE_ITIME system + // setting which says whether the default time format is + // 24 or 12 hour + { + // try to parse what follows as "%H:%M:%S" and, if this + // fails, as "%I:%M:%S %p" - this should catch the most + // common cases + wxDateTime dt; + + const wxChar *result = dt.ParseFormat(input, _T("%T")); + if ( !result ) + { + result = dt.ParseFormat(input, _T("%r")); + } + + if ( !result ) + { + // no match + return (wxChar *)NULL; + } + + haveHour = haveMin = haveSec = true; + + Tm tm = dt.GetTm(); + hour = tm.hour; + min = tm.min; + sec = tm.sec; + + input = result; + } +#endif // HAVE_STRPTIME/!HAVE_STRPTIME + break; + + case _T('y'): // year without century (00-99) + if ( !GetNumericToken(width, input, &num) || (num > 99) ) + { + // no match + return (wxChar *)NULL; + } + + haveYear = true; + + // TODO should have an option for roll over date instead of + // hard coding it here + year = (num > 30 ? 1900 : 2000) + (wxDateTime_t)num; + break; + + case _T('Y'): // year with century + if ( !GetNumericToken(width, input, &num) ) + { + // no match + return (wxChar *)NULL; + } + + haveYear = true; + year = (wxDateTime_t)num; + break; + + case _T('Z'): // timezone name + wxFAIL_MSG(_T("TODO")); + break; + + case _T('%'): // a percent sign + if ( *input++ != _T('%') ) + { + // no match + return (wxChar *)NULL; + } + break; + + case 0: // the end of string + wxFAIL_MSG(_T("unexpected format end")); + + // fall through + + default: // not a known format spec + return (wxChar *)NULL; + } + } + + // format matched, try to construct a date from what we have now + Tm tmDef; + if ( dateDef.IsValid() ) + { + // take this date as default + tmDef = dateDef.GetTm(); + } + else if ( IsValid() ) + { + // if this date is valid, don't change it + tmDef = GetTm(); + } + else + { + // no default and this date is invalid - fall back to Today() + tmDef = Today().GetTm(); + } + + Tm tm = tmDef; + + // set the date + if ( haveYear ) + { + tm.year = year; + } + + // TODO we don't check here that the values are consistent, if both year + // day and month/day were found, we just ignore the year day and we + // also always ignore the week day + if ( haveMon && haveDay ) + { + if ( mday > GetNumOfDaysInMonth(tm.year, mon) ) + { + wxLogDebug(_T("bad month day in wxDateTime::ParseFormat")); + + return (wxChar *)NULL; + } + + tm.mon = mon; + tm.mday = mday; + } + else if ( haveYDay ) + { + if ( yday > GetNumberOfDays(tm.year) ) + { + wxLogDebug(_T("bad year day in wxDateTime::ParseFormat")); + + return (wxChar *)NULL; + } + + Tm tm2 = wxDateTime(1, Jan, tm.year).SetToYearDay(yday).GetTm(); + + tm.mon = tm2.mon; + tm.mday = tm2.mday; + } + + // deal with AM/PM + if ( haveHour && hourIsIn12hFormat && isPM ) + { + // translate to 24hour format + hour += 12; + } + //else: either already in 24h format or no translation needed + + // set the time + if ( haveHour ) + { + tm.hour = hour; + } + + if ( haveMin ) + { + tm.min = min; + } + + if ( haveSec ) + { + tm.sec = sec; + } + + Set(tm); + + // finally check that the week day is consistent -- if we had it + if ( haveWDay && GetWeekDay() != wday ) + { + wxLogDebug(_T("inconsistsnet week day in wxDateTime::ParseFormat()")); + + return NULL; + } + + return input; +} + +const wxChar *wxDateTime::ParseDateTime(const wxChar *date) +{ + wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); + + // Set to current day and hour, so strings like '14:00' becomes today at + // 14, not some other random date + wxDateTime dtDate = wxDateTime::Today(); + wxDateTime dtTime = wxDateTime::Today(); + + const wxChar* pchTime; + + // Try to parse the beginning of the string as a date + const wxChar* pchDate = dtDate.ParseDate(date); + + // We got a date in the beginning, see if there is a time specified after the date + if ( pchDate ) + { + // Skip spaces, as the ParseTime() function fails on spaces + while ( wxIsspace(*pchDate) ) + pchDate++; + + pchTime = dtTime.ParseTime(pchDate); + } + else // no date in the beginning + { + // check and see if we have a time followed by a date + pchTime = dtTime.ParseTime(date); + if ( pchTime ) + { + while ( wxIsspace(*pchTime) ) + pchTime++; + + pchDate = dtDate.ParseDate(pchTime); + } + } + + // If we have a date specified, set our own data to the same date + if ( !pchDate || !pchTime ) + return NULL; + + Set(dtDate.GetDay(), dtDate.GetMonth(), dtDate.GetYear(), + dtTime.GetHour(), dtTime.GetMinute(), dtTime.GetSecond(), + dtTime.GetMillisecond()); + + // Return endpoint of scan + return pchDate > pchTime ? pchDate : pchTime; +} + +const wxChar *wxDateTime::ParseDate(const wxChar *date) +{ + // this is a simplified version of ParseDateTime() which understands only + // "today" (for wxDate compatibility) and digits only otherwise (and not + // all esoteric constructions ParseDateTime() knows about) + + wxCHECK_MSG( date, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); + + const wxChar *p = date; + while ( wxIsspace(*p) ) + p++; + + // some special cases + static struct + { + const wxChar *str; + int dayDiffFromToday; + } literalDates[] = + { + { wxTRANSLATE("today"), 0 }, + { wxTRANSLATE("yesterday"), -1 }, + { wxTRANSLATE("tomorrow"), 1 }, + }; + + for ( size_t n = 0; n < WXSIZEOF(literalDates); n++ ) + { + const wxString dateStr = wxGetTranslation(literalDates[n].str); + size_t len = dateStr.length(); + if ( wxStrlen(p) >= len ) + { + wxString str(p, len); + if ( str.CmpNoCase(dateStr) == 0 ) + { + // nothing can follow this, so stop here + p += len; + + int dayDiffFromToday = literalDates[n].dayDiffFromToday; + *this = Today(); + if ( dayDiffFromToday ) + { + *this += wxDateSpan::Days(dayDiffFromToday); + } + + return p; + } + } + } + + // We try to guess what we have here: for each new (numeric) token, we + // determine if it can be a month, day or a year. Of course, there is an + // ambiguity as some numbers may be days as well as months, so we also + // have the ability to back track. + + // what do we have? + bool haveDay = false, // the months day? + haveWDay = false, // the day of week? + haveMon = false, // the month? + haveYear = false; // the year? + + // and the value of the items we have (init them to get rid of warnings) + WeekDay wday = Inv_WeekDay; + wxDateTime_t day = 0; + wxDateTime::Month mon = Inv_Month; + int year = 0; + + // tokenize the string + size_t nPosCur = 0; + static const wxChar *dateDelimiters = _T(".,/-\t\r\n "); + wxStringTokenizer tok(p, dateDelimiters); + while ( tok.HasMoreTokens() ) + { + wxString token = tok.GetNextToken(); + if ( !token ) + continue; + + // is it a number? + unsigned long val; + if ( token.ToULong(&val) ) + { + // guess what this number is + + bool isDay = false, + isMonth = false, + isYear = false; + + if ( !haveMon && val > 0 && val <= 12 ) + { + // assume it is month + isMonth = true; + } + else // not the month + { + if ( haveDay ) + { + // this can only be the year + isYear = true; + } + else // may be either day or year + { + // use a leap year if we don't have the year yet to allow + // dates like 2/29/1976 which would be rejected otherwise + wxDateTime_t max_days = (wxDateTime_t)( + haveMon + ? GetNumOfDaysInMonth(haveYear ? year : 1976, mon) + : 31 + ); + + // can it be day? + if ( (val == 0) || (val > (unsigned long)max_days) ) + { + // no + isYear = true; + } + else // yes, suppose it's the day + { + isDay = true; + } + } + } + + if ( isYear ) + { + if ( haveYear ) + break; + + haveYear = true; + + year = (wxDateTime_t)val; + } + else if ( isDay ) + { + if ( haveDay ) + break; + + haveDay = true; + + day = (wxDateTime_t)val; + } + else if ( isMonth ) + { + haveMon = true; + + mon = (Month)(val - 1); + } + } + else // not a number + { + // be careful not to overwrite the current mon value + Month mon2 = GetMonthFromName(token, Name_Full | Name_Abbr); + if ( mon2 != Inv_Month ) + { + // it's a month + if ( haveMon ) + { + // but we already have a month - maybe we guessed wrong? + if ( !haveDay ) + { + // no need to check in month range as always < 12, but + // the days are counted from 1 unlike the months + day = (wxDateTime_t)(mon + 1); + haveDay = true; + } + else + { + // could possible be the year (doesn't the year come + // before the month in the japanese format?) (FIXME) + break; + } + } + + mon = mon2; + + haveMon = true; + } + else // not a valid month name + { + WeekDay wday2 = GetWeekDayFromName(token, Name_Full | Name_Abbr); + if ( wday2 != Inv_WeekDay ) + { + // a week day + if ( haveWDay ) + { + break; + } + + wday = wday2; + + haveWDay = true; + } + else // not a valid weekday name + { + // try the ordinals + static const wxChar *ordinals[] = + { + wxTRANSLATE("first"), + wxTRANSLATE("second"), + wxTRANSLATE("third"), + wxTRANSLATE("fourth"), + wxTRANSLATE("fifth"), + wxTRANSLATE("sixth"), + wxTRANSLATE("seventh"), + wxTRANSLATE("eighth"), + wxTRANSLATE("ninth"), + wxTRANSLATE("tenth"), + wxTRANSLATE("eleventh"), + wxTRANSLATE("twelfth"), + wxTRANSLATE("thirteenth"), + wxTRANSLATE("fourteenth"), + wxTRANSLATE("fifteenth"), + wxTRANSLATE("sixteenth"), + wxTRANSLATE("seventeenth"), + wxTRANSLATE("eighteenth"), + wxTRANSLATE("nineteenth"), + wxTRANSLATE("twentieth"), + // that's enough - otherwise we'd have problems with + // composite (or not) ordinals + }; + + size_t n; + for ( n = 0; n < WXSIZEOF(ordinals); n++ ) + { + if ( token.CmpNoCase(ordinals[n]) == 0 ) + { + break; + } + } + + if ( n == WXSIZEOF(ordinals) ) + { + // stop here - something unknown + break; + } + + // it's a day + if ( haveDay ) + { + // don't try anything here (as in case of numeric day + // above) - the symbolic day spec should always + // precede the month/year + break; + } + + haveDay = true; + + day = (wxDateTime_t)(n + 1); + } + } + } + + nPosCur = tok.GetPosition(); + } + + // either no more tokens or the scan was stopped by something we couldn't + // parse - in any case, see if we can construct a date from what we have + if ( !haveDay && !haveWDay ) + { + wxLogDebug(_T("ParseDate: no day, no weekday hence no date.")); + + return NULL; + } + + if ( haveWDay && (haveMon || haveYear || haveDay) && + !(haveDay && haveMon && haveYear) ) + { + // without adjectives (which we don't support here) the week day only + // makes sense completely separately or with the full date + // specification (what would "Wed 1999" mean?) + return NULL; + } + + if ( !haveWDay && haveYear && !(haveDay && haveMon) ) + { + // may be we have month and day instead of day and year? + if ( haveDay && !haveMon ) + { + if ( day <= 12 ) + { + // exchange day and month + mon = (wxDateTime::Month)(day - 1); + + // we're in the current year then + if ( (year > 0) && (year <= (int)GetNumOfDaysInMonth(Inv_Year, mon)) ) + { + day = (wxDateTime_t)year; + + haveMon = true; + haveYear = false; + } + //else: no, can't exchange, leave haveMon == false + } + } + + if ( !haveMon ) + { + // if we give the year, month and day must be given too + wxLogDebug(_T("ParseDate: day and month should be specified if year is.")); + + return NULL; + } + } + + if ( !haveMon ) + { + mon = GetCurrentMonth(); + } + + if ( !haveYear ) + { + year = GetCurrentYear(); + } + + if ( haveDay ) + { + // normally we check the day above but the check is optimistic in case + // we find the day before its month/year so we have to redo it now + if ( day > GetNumOfDaysInMonth(year, mon) ) + return NULL; + + Set(day, mon, year); + + if ( haveWDay ) + { + // check that it is really the same + if ( GetWeekDay() != wday ) + { + // inconsistency detected + wxLogDebug(_T("ParseDate: inconsistent day/weekday.")); + + return (wxChar *)NULL; + } + } + } + else // haveWDay + { + *this = Today(); + + SetToWeekDayInSameWeek(wday); + } + + // return the pointer to the first unparsed char + p += nPosCur; + if ( nPosCur && wxStrchr(dateDelimiters, *(p - 1)) ) + { + // if we couldn't parse the token after the delimiter, put back the + // delimiter as well + p--; + } + + return p; +} + +const wxChar *wxDateTime::ParseTime(const wxChar *time) +{ + wxCHECK_MSG( time, (wxChar *)NULL, _T("NULL pointer in wxDateTime::Parse") ); + + // first try some extra things + static const struct + { + const wxChar *name; + wxDateTime_t hour; + } stdTimes[] = + { + { wxTRANSLATE("noon"), 12 }, + { wxTRANSLATE("midnight"), 00 }, + // anything else? + }; + + for ( size_t n = 0; n < WXSIZEOF(stdTimes); n++ ) + { + wxString timeString = wxGetTranslation(stdTimes[n].name); + size_t len = timeString.length(); + if ( timeString.CmpNoCase(wxString(time, len)) == 0 ) + { + // casts required by DigitalMars + Set(stdTimes[n].hour, wxDateTime_t(0), wxDateTime_t(0)); + + return time + len; + } + } + + // try all time formats we may think about in the order from longest to + // shortest + + // 12hour with AM/PM? + const wxChar *result = ParseFormat(time, _T("%I:%M:%S %p")); + + if ( !result ) + { + // normally, it's the same, but why not try it? + result = ParseFormat(time, _T("%H:%M:%S")); + } + + if ( !result ) + { + // 12hour with AM/PM but without seconds? + result = ParseFormat(time, _T("%I:%M %p")); + } + + if ( !result ) + { + // without seconds? + result = ParseFormat(time, _T("%H:%M")); + } + + if ( !result ) + { + // just the hour and AM/PM? + result = ParseFormat(time, _T("%I %p")); + } + + if ( !result ) + { + // just the hour? + result = ParseFormat(time, _T("%H")); + } + + if ( !result ) + { + // parse the standard format: normally it is one of the formats above + // but it may be set to something completely different by the user + result = ParseFormat(time, _T("%X")); + } + + // TODO: parse timezones + + return result; +} + +// ---------------------------------------------------------------------------- +// Workdays and holidays support +// ---------------------------------------------------------------------------- + +bool wxDateTime::IsWorkDay(Country WXUNUSED(country)) const +{ + return !wxDateTimeHolidayAuthority::IsHoliday(*this); +} + +// ============================================================================ +// wxDateSpan +// ============================================================================ + +wxDateSpan WXDLLIMPEXP_BASE operator*(int n, const wxDateSpan& ds) +{ + wxDateSpan ds1(ds); + return ds1.Multiply(n); +} + +// ============================================================================ +// wxTimeSpan +// ============================================================================ + +wxTimeSpan WXDLLIMPEXP_BASE operator*(int n, const wxTimeSpan& ts) +{ + return wxTimeSpan(ts).Multiply(n); +} + +// this enum is only used in wxTimeSpan::Format() below but we can't declare +// it locally to the method as it provokes an internal compiler error in egcs +// 2.91.60 when building with -O2 +enum TimeSpanPart +{ + Part_Week, + Part_Day, + Part_Hour, + Part_Min, + Part_Sec, + Part_MSec +}; + +// not all strftime(3) format specifiers make sense here because, for example, +// a time span doesn't have a year nor a timezone +// +// Here are the ones which are supported (all of them are supported by strftime +// as well): +// %H hour in 24 hour format +// %M minute (00 - 59) +// %S second (00 - 59) +// %% percent sign +// +// Also, for MFC CTimeSpan compatibility, we support +// %D number of days +// +// And, to be better than MFC :-), we also have +// %E number of wEeks +// %l milliseconds (000 - 999) +wxString wxTimeSpan::Format(const wxChar *format) const +{ + // we deal with only positive time spans here and just add the sign in + // front for the negative ones + if ( IsNegative() ) + { + wxString str(Negate().Format(format)); + return _T("-") + str; + } + + wxCHECK_MSG( format, wxEmptyString, + _T("NULL format in wxTimeSpan::Format") ); + + wxString str; + str.Alloc(wxStrlen(format)); + + // Suppose we have wxTimeSpan ts(1 /* hour */, 2 /* min */, 3 /* sec */) + // + // Then, of course, ts.Format("%H:%M:%S") must return "01:02:03", but the + // question is what should ts.Format("%S") do? The code here returns "3273" + // in this case (i.e. the total number of seconds, not just seconds % 60) + // because, for me, this call means "give me entire time interval in + // seconds" and not "give me the seconds part of the time interval" + // + // If we agree that it should behave like this, it is clear that the + // interpretation of each format specifier depends on the presence of the + // other format specs in the string: if there was "%H" before "%M", we + // should use GetMinutes() % 60, otherwise just GetMinutes() &c + + // we remember the most important unit found so far + TimeSpanPart partBiggest = Part_MSec; + + for ( const wxChar *pch = format; *pch; pch++ ) + { + wxChar ch = *pch; + + if ( ch == _T('%') ) + { + // the start of the format specification of the printf() below + wxString fmtPrefix(_T('%')); + + // the number + long n; + + // the number of digits for the format string, 0 if unused + unsigned digits = 0; + + ch = *++pch; // get the format spec char + switch ( ch ) + { + default: + wxFAIL_MSG( _T("invalid format character") ); + // fall through + + case _T('%'): + str += ch; + + // skip the part below switch + continue; + + case _T('D'): + n = GetDays(); + if ( partBiggest < Part_Day ) + { + n %= DAYS_PER_WEEK; + } + else + { + partBiggest = Part_Day; + } + break; + + case _T('E'): + partBiggest = Part_Week; + n = GetWeeks(); + break; + + case _T('H'): + n = GetHours(); + if ( partBiggest < Part_Hour ) + { + n %= HOURS_PER_DAY; + } + else + { + partBiggest = Part_Hour; + } + + digits = 2; + break; + + case _T('l'): + n = GetMilliseconds().ToLong(); + if ( partBiggest < Part_MSec ) + { + n %= 1000; + } + //else: no need to reset partBiggest to Part_MSec, it is + // the least significant one anyhow + + digits = 3; + break; + + case _T('M'): + n = GetMinutes(); + if ( partBiggest < Part_Min ) + { + n %= MIN_PER_HOUR; + } + else + { + partBiggest = Part_Min; + } + + digits = 2; + break; + + case _T('S'): + n = GetSeconds().ToLong(); + if ( partBiggest < Part_Sec ) + { + n %= SEC_PER_MIN; + } + else + { + partBiggest = Part_Sec; + } + + digits = 2; + break; + } + + if ( digits ) + { + fmtPrefix << _T("0") << digits; + } + + str += wxString::Format(fmtPrefix + _T("ld"), n); + } + else + { + // normal character, just copy + str += ch; + } + } + + return str; +} + +// ============================================================================ +// wxDateTimeHolidayAuthority and related classes +// ============================================================================ + +#include "wx/arrimpl.cpp" + +WX_DEFINE_OBJARRAY(wxDateTimeArray) + +static int wxCMPFUNC_CONV +wxDateTimeCompareFunc(wxDateTime **first, wxDateTime **second) +{ + wxDateTime dt1 = **first, + dt2 = **second; + + return dt1 == dt2 ? 0 : dt1 < dt2 ? -1 : +1; +} + +// ---------------------------------------------------------------------------- +// wxDateTimeHolidayAuthority +// ---------------------------------------------------------------------------- + +wxHolidayAuthoritiesArray wxDateTimeHolidayAuthority::ms_authorities; + +/* static */ +bool wxDateTimeHolidayAuthority::IsHoliday(const wxDateTime& dt) +{ + size_t count = ms_authorities.size(); + for ( size_t n = 0; n < count; n++ ) + { + if ( ms_authorities[n]->DoIsHoliday(dt) ) + { + return true; + } + } + + return false; +} + +/* static */ +size_t +wxDateTimeHolidayAuthority::GetHolidaysInRange(const wxDateTime& dtStart, + const wxDateTime& dtEnd, + wxDateTimeArray& holidays) +{ + wxDateTimeArray hol; + + holidays.Clear(); + + const size_t countAuth = ms_authorities.size(); + for ( size_t nAuth = 0; nAuth < countAuth; nAuth++ ) + { + ms_authorities[nAuth]->DoGetHolidaysInRange(dtStart, dtEnd, hol); + + WX_APPEND_ARRAY(holidays, hol); + } + + holidays.Sort(wxDateTimeCompareFunc); + + return holidays.size(); +} + +/* static */ +void wxDateTimeHolidayAuthority::ClearAllAuthorities() +{ + WX_CLEAR_ARRAY(ms_authorities); +} + +/* static */ +void wxDateTimeHolidayAuthority::AddAuthority(wxDateTimeHolidayAuthority *auth) +{ + ms_authorities.push_back(auth); +} + +wxDateTimeHolidayAuthority::~wxDateTimeHolidayAuthority() +{ + // required here for Darwin +} + +// ---------------------------------------------------------------------------- +// wxDateTimeWorkDays +// ---------------------------------------------------------------------------- + +bool wxDateTimeWorkDays::DoIsHoliday(const wxDateTime& dt) const +{ + wxDateTime::WeekDay wd = dt.GetWeekDay(); + + return (wd == wxDateTime::Sun) || (wd == wxDateTime::Sat); +} + +size_t wxDateTimeWorkDays::DoGetHolidaysInRange(const wxDateTime& dtStart, + const wxDateTime& dtEnd, + wxDateTimeArray& holidays) const +{ + if ( dtStart > dtEnd ) + { + wxFAIL_MSG( _T("invalid date range in GetHolidaysInRange") ); + + return 0u; + } + + holidays.Empty(); + + // instead of checking all days, start with the first Sat after dtStart and + // end with the last Sun before dtEnd + wxDateTime dtSatFirst = dtStart.GetNextWeekDay(wxDateTime::Sat), + dtSatLast = dtEnd.GetPrevWeekDay(wxDateTime::Sat), + dtSunFirst = dtStart.GetNextWeekDay(wxDateTime::Sun), + dtSunLast = dtEnd.GetPrevWeekDay(wxDateTime::Sun), + dt; + + for ( dt = dtSatFirst; dt <= dtSatLast; dt += wxDateSpan::Week() ) + { + holidays.Add(dt); + } + + for ( dt = dtSunFirst; dt <= dtSunLast; dt += wxDateSpan::Week() ) + { + holidays.Add(dt); + } + + return holidays.GetCount(); +} + +// ============================================================================ +// other helper functions +// ============================================================================ + +// ---------------------------------------------------------------------------- +// iteration helpers: can be used to write a for loop over enum variable like +// this: +// for ( m = wxDateTime::Jan; m < wxDateTime::Inv_Month; wxNextMonth(m) ) +// ---------------------------------------------------------------------------- + +WXDLLIMPEXP_BASE void wxNextMonth(wxDateTime::Month& m) +{ + wxASSERT_MSG( m < wxDateTime::Inv_Month, _T("invalid month") ); + + // no wrapping or the for loop above would never end! + m = (wxDateTime::Month)(m + 1); +} + +WXDLLIMPEXP_BASE void wxPrevMonth(wxDateTime::Month& m) +{ + wxASSERT_MSG( m < wxDateTime::Inv_Month, _T("invalid month") ); + + m = m == wxDateTime::Jan ? wxDateTime::Inv_Month + : (wxDateTime::Month)(m - 1); +} + +WXDLLIMPEXP_BASE void wxNextWDay(wxDateTime::WeekDay& wd) +{ + wxASSERT_MSG( wd < wxDateTime::Inv_WeekDay, _T("invalid week day") ); + + // no wrapping or the for loop above would never end! + wd = (wxDateTime::WeekDay)(wd + 1); +} + +WXDLLIMPEXP_BASE void wxPrevWDay(wxDateTime::WeekDay& wd) +{ + wxASSERT_MSG( wd < wxDateTime::Inv_WeekDay, _T("invalid week day") ); + + wd = wd == wxDateTime::Sun ? wxDateTime::Inv_WeekDay + : (wxDateTime::WeekDay)(wd - 1); +} + +#endif // wxUSE_DATETIME diff --git a/Source/3rd Party/wx/src/common/datstrm.cpp b/Source/3rd Party/wx/src/common/datstrm.cpp index 28f496562..fd16e9223 100644 --- a/Source/3rd Party/wx/src/common/datstrm.cpp +++ b/Source/3rd Party/wx/src/common/datstrm.cpp @@ -1,745 +1,745 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/datstrm.cpp -// Purpose: Data stream classes -// Author: Guilhem Lavaux -// Modified by: Mickael Gilabert -// Created: 28/06/98 -// RCS-ID: $Id: datstrm.cpp 53028 2008-04-05 17:28:32Z VZ $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#include "wx/datstrm.h" - -#ifndef WX_PRECOMP - #include "wx/math.h" -#endif //WX_PRECOMP - -// --------------------------------------------------------------------------- -// wxDataInputStream -// --------------------------------------------------------------------------- - -#if wxUSE_UNICODE -wxDataInputStream::wxDataInputStream(wxInputStream& s, const wxMBConv& conv) - : m_input(&s), m_be_order(false), m_conv(conv.Clone()) -#else -wxDataInputStream::wxDataInputStream(wxInputStream& s) - : m_input(&s), m_be_order(false) -#endif -{ -} - -wxDataInputStream::~wxDataInputStream() -{ -#if wxUSE_UNICODE - delete m_conv; -#endif // wxUSE_UNICODE -} - -#if wxHAS_INT64 -wxUint64 wxDataInputStream::Read64() -{ - wxUint64 tmp; - Read64(&tmp, 1); - return tmp; -} -#endif // wxHAS_INT64 - -wxUint32 wxDataInputStream::Read32() -{ - wxUint32 i32; - - m_input->Read(&i32, 4); - - if (m_be_order) - return wxUINT32_SWAP_ON_LE(i32); - else - return wxUINT32_SWAP_ON_BE(i32); -} - -wxUint16 wxDataInputStream::Read16() -{ - wxUint16 i16; - - m_input->Read(&i16, 2); - - if (m_be_order) - return wxUINT16_SWAP_ON_LE(i16); - else - return wxUINT16_SWAP_ON_BE(i16); -} - -wxUint8 wxDataInputStream::Read8() -{ - wxUint8 buf; - - m_input->Read(&buf, 1); - return (wxUint8)buf; -} - -double wxDataInputStream::ReadDouble() -{ -#if wxUSE_APPLE_IEEE - char buf[10]; - - m_input->Read(buf, 10); - return ConvertFromIeeeExtended((const wxInt8 *)buf); -#else - return 0.0; -#endif -} - -wxString wxDataInputStream::ReadString() -{ - wxString ret; - - const size_t len = Read32(); - if ( len > 0 ) - { -#if wxUSE_UNICODE - wxCharBuffer tmp(len + 1); - if ( tmp ) - { - m_input->Read(tmp.data(), len); - tmp.data()[len] = '\0'; - ret = m_conv->cMB2WX(tmp.data()); - } -#else - wxStringBuffer buf(ret, len); - if ( buf ) - m_input->Read(buf, len); -#endif - } - - return ret; -} - -#if wxUSE_LONGLONG - -template -static -void DoReadLL(T *buffer, size_t size, wxInputStream *input, bool be_order) -{ - typedef T DataType; - unsigned char *pchBuffer = new unsigned char[size * 8]; - // TODO: Check for overflow when size is of type uint and is > than 512m - input->Read(pchBuffer, size * 8); - size_t idx_base = 0; - if ( be_order ) - { - for ( size_t uiIndex = 0; uiIndex != size; ++uiIndex ) - { - buffer[uiIndex] = 0l; - for ( unsigned ui = 0; ui != 8; ++ui ) - { - buffer[uiIndex] = buffer[uiIndex] * 256l + - DataType((unsigned long) pchBuffer[idx_base + ui]); - } - - idx_base += 8; - } - } - else // little endian - { - for ( size_t uiIndex=0; uiIndex!=size; ++uiIndex ) - { - buffer[uiIndex] = 0l; - for ( unsigned ui=0; ui!=8; ++ui ) - buffer[uiIndex] = buffer[uiIndex] * 256l + - DataType((unsigned long) pchBuffer[idx_base + 7 - ui]); - idx_base += 8; - } - } - delete[] pchBuffer; -} - -template -static void DoWriteLL(const T *buffer, size_t size, wxOutputStream *output, bool be_order) -{ - typedef T DataType; - unsigned char *pchBuffer = new unsigned char[size * 8]; - size_t idx_base = 0; - if ( be_order ) - { - for ( size_t uiIndex = 0; uiIndex != size; ++uiIndex ) - { - DataType i64 = buffer[uiIndex]; - for ( unsigned ui = 0; ui != 8; ++ui ) - { - pchBuffer[idx_base + 7 - ui] = - (unsigned char) (i64.GetLo() & 255l); - i64 >>= 8l; - } - - idx_base += 8; - } - } - else // little endian - { - for ( size_t uiIndex=0; uiIndex != size; ++uiIndex ) - { - DataType i64 = buffer[uiIndex]; - for (unsigned ui=0; ui!=8; ++ui) - { - pchBuffer[idx_base + ui] = - (unsigned char) (i64.GetLo() & 255l); - i64 >>= 8l; - } - - idx_base += 8; - } - } - - // TODO: Check for overflow when size is of type uint and is > than 512m - output->Write(pchBuffer, size * 8); - delete[] pchBuffer; -} - -#endif // wxUSE_LONGLONG - -#ifdef wxLongLong_t - -template -static -void DoReadI64(T *buffer, size_t size, wxInputStream *input, bool be_order) -{ - typedef T DataType; - unsigned char *pchBuffer = (unsigned char*) buffer; - // TODO: Check for overflow when size is of type uint and is > than 512m - input->Read(pchBuffer, size * 8); - if ( be_order ) - { - for ( wxUint32 i = 0; i < size; i++ ) - { - DataType v = wxUINT64_SWAP_ON_LE(*buffer); - *(buffer++) = v; - } - } - else // little endian - { - for ( wxUint32 i=0; i -static -void DoWriteI64(const T *buffer, size_t size, wxOutputStream *output, bool be_order) -{ - typedef T DataType; - if ( be_order ) - { - for ( size_t i = 0; i < size; i++ ) - { - DataType i64 = wxUINT64_SWAP_ON_LE(*buffer); - buffer++; - output->Write(&i64, 8); - } - } - else // little endian - { - for ( size_t i=0; i < size; i++ ) - { - DataType i64 = wxUINT64_SWAP_ON_BE(*buffer); - buffer++; - output->Write(&i64, 8); - } - } -} - -#endif // wxLongLong_t - - -#if wxHAS_INT64 -void wxDataInputStream::Read64(wxUint64 *buffer, size_t size) -{ -#ifndef wxLongLong_t - DoReadLL(buffer, size, m_input, m_be_order); -#else - DoReadI64(buffer, size, m_input, m_be_order); -#endif -} - -void wxDataInputStream::Read64(wxInt64 *buffer, size_t size) -{ -#ifndef wxLongLong_t - DoReadLL(buffer, size, m_input, m_be_order); -#else - DoReadI64(buffer, size, m_input, m_be_order); -#endif -} -#endif // wxHAS_INT64 - -#if defined(wxLongLong_t) && wxUSE_LONGLONG -void wxDataInputStream::Read64(wxULongLong *buffer, size_t size) -{ - DoReadLL(buffer, size, m_input, m_be_order); -} - -void wxDataInputStream::Read64(wxLongLong *buffer, size_t size) -{ - DoReadLL(buffer, size, m_input, m_be_order); -} -#endif // wxLongLong_t - -#if wxUSE_LONGLONG -void wxDataInputStream::ReadLL(wxULongLong *buffer, size_t size) -{ - DoReadLL(buffer, size, m_input, m_be_order); -} - -void wxDataInputStream::ReadLL(wxLongLong *buffer, size_t size) -{ - DoReadLL(buffer, size, m_input, m_be_order); -} - -wxLongLong wxDataInputStream::ReadLL(void) -{ - wxLongLong ll; - DoReadLL(&ll, (size_t)1, m_input, m_be_order); - return ll; -} -#endif // wxUSE_LONGLONG - -void wxDataInputStream::Read32(wxUint32 *buffer, size_t size) -{ - m_input->Read(buffer, size * 4); - - if (m_be_order) - { - for (wxUint32 i=0; iRead(buffer, size * 2); - - if (m_be_order) - { - for (wxUint32 i=0; iRead(buffer, size); -} - -void wxDataInputStream::ReadDouble(double *buffer, size_t size) -{ - for (wxUint32 i=0; i>(wxString& s) -{ - s = ReadString(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxInt8& c) -{ - c = (wxInt8)Read8(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxInt16& i) -{ - i = (wxInt16)Read16(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxInt32& i) -{ - i = (wxInt32)Read32(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxUint8& c) -{ - c = Read8(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxUint16& i) -{ - i = Read16(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxUint32& i) -{ - i = Read32(); - return *this; -} - -#if wxHAS_INT64 -wxDataInputStream& wxDataInputStream::operator>>(wxUint64& i) -{ - i = Read64(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxInt64& i) -{ - i = Read64(); - return *this; -} -#endif // wxHAS_INT64 - -#if defined(wxLongLong_t) && wxUSE_LONGLONG -wxDataInputStream& wxDataInputStream::operator>>(wxULongLong& i) -{ - i = ReadLL(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(wxLongLong& i) -{ - i = ReadLL(); - return *this; -} -#endif // wxLongLong_t - -wxDataInputStream& wxDataInputStream::operator>>(double& i) -{ - i = ReadDouble(); - return *this; -} - -wxDataInputStream& wxDataInputStream::operator>>(float& f) -{ - f = (float)ReadDouble(); - return *this; -} - -// --------------------------------------------------------------------------- -// wxDataOutputStream -// --------------------------------------------------------------------------- - -#if wxUSE_UNICODE -wxDataOutputStream::wxDataOutputStream(wxOutputStream& s, const wxMBConv& conv) - : m_output(&s), m_be_order(false), m_conv(conv.Clone()) -#else -wxDataOutputStream::wxDataOutputStream(wxOutputStream& s) - : m_output(&s), m_be_order(false) -#endif -{ -} - -wxDataOutputStream::~wxDataOutputStream() -{ -#if wxUSE_UNICODE - delete m_conv; -#endif // wxUSE_UNICODE -} - -#if wxHAS_INT64 -void wxDataOutputStream::Write64(wxUint64 i) -{ - Write64(&i, 1); -} - -void wxDataOutputStream::Write64(wxInt64 i) -{ - Write64(&i, 1); -} -#endif // wxHAS_INT64 - -void wxDataOutputStream::Write32(wxUint32 i) -{ - wxUint32 i32; - - if (m_be_order) - i32 = wxUINT32_SWAP_ON_LE(i); - else - i32 = wxUINT32_SWAP_ON_BE(i); - m_output->Write(&i32, 4); -} - -void wxDataOutputStream::Write16(wxUint16 i) -{ - wxUint16 i16; - - if (m_be_order) - i16 = wxUINT16_SWAP_ON_LE(i); - else - i16 = wxUINT16_SWAP_ON_BE(i); - - m_output->Write(&i16, 2); -} - -void wxDataOutputStream::Write8(wxUint8 i) -{ - m_output->Write(&i, 1); -} - -void wxDataOutputStream::WriteString(const wxString& string) -{ -#if wxUSE_UNICODE - const wxWX2MBbuf buf = string.mb_str(*m_conv); -#else - const wxWX2MBbuf buf = string.mb_str(); -#endif - size_t len = strlen(buf); - Write32(len); - if (len > 0) - m_output->Write(buf, len); -} - -void wxDataOutputStream::WriteDouble(double d) -{ - char buf[10]; - -#if wxUSE_APPLE_IEEE - ConvertToIeeeExtended(d, (wxInt8 *)buf); -#else -#if !defined(__VMS__) && !defined(__GNUG__) -# pragma warning "wxDataOutputStream::WriteDouble() not using IeeeExtended - will not work!" -#endif - buf[0] = '\0'; -#endif - m_output->Write(buf, 10); -} - -#if wxHAS_INT64 -void wxDataOutputStream::Write64(const wxUint64 *buffer, size_t size) -{ -#ifndef wxLongLong_t - DoWriteLL(buffer, size, m_output, m_be_order); -#else - DoWriteI64(buffer, size, m_output, m_be_order); -#endif -} - -void wxDataOutputStream::Write64(const wxInt64 *buffer, size_t size) -{ -#ifndef wxLongLong_t - DoWriteLL(buffer, size, m_output, m_be_order); -#else - DoWriteI64(buffer, size, m_output, m_be_order); -#endif -} -#endif // wxHAS_INT64 - -#if defined(wxLongLong_t) && wxUSE_LONGLONG -void wxDataOutputStream::Write64(const wxULongLong *buffer, size_t size) -{ - DoWriteLL(buffer, size, m_output, m_be_order); -} - -void wxDataOutputStream::Write64(const wxLongLong *buffer, size_t size) -{ - DoWriteLL(buffer, size, m_output, m_be_order); -} -#endif // wxLongLong_t - -#if wxUSE_LONGLONG -void wxDataOutputStream::WriteLL(const wxULongLong *buffer, size_t size) -{ - DoWriteLL(buffer, size, m_output, m_be_order); -} - -void wxDataOutputStream::WriteLL(const wxLongLong *buffer, size_t size) -{ - DoWriteLL(buffer, size, m_output, m_be_order); -} - -void wxDataOutputStream::WriteLL(const wxLongLong &ll) -{ - WriteLL(&ll, 1); -} - -void wxDataOutputStream::WriteLL(const wxULongLong &ll) -{ - WriteLL(&ll, 1); -} -#endif // wxUSE_LONGLONG - -void wxDataOutputStream::Write32(const wxUint32 *buffer, size_t size) -{ - if (m_be_order) - { - for (wxUint32 i=0; iWrite(&i32, 4); - } - } - else - { - for (wxUint32 i=0; iWrite(&i32, 4); - } - } -} - -void wxDataOutputStream::Write16(const wxUint16 *buffer, size_t size) -{ - if (m_be_order) - { - for (wxUint32 i=0; iWrite(&i16, 2); - } - } - else - { - for (wxUint32 i=0; iWrite(&i16, 2); - } - } -} - -void wxDataOutputStream::Write8(const wxUint8 *buffer, size_t size) -{ - m_output->Write(buffer, size); -} - -void wxDataOutputStream::WriteDouble(const double *buffer, size_t size) -{ - for (wxUint32 i=0; iWrite((const char *)string, wxStrlen(string)*sizeof(wxChar)); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(const wxString& string) -{ - WriteString(string); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(wxInt8 c) -{ - Write8((wxUint8)c); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(wxInt16 i) -{ - Write16((wxUint16)i); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(wxInt32 i) -{ - Write32((wxUint32)i); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(wxUint8 c) -{ - Write8(c); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(wxUint16 i) -{ - Write16(i); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(wxUint32 i) -{ - Write32(i); - return *this; -} - -#if wxHAS_INT64 -wxDataOutputStream& wxDataOutputStream::operator<<(wxUint64 i) -{ - Write64(i); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(wxInt64 i) -{ - Write64(i); - return *this; -} -#endif // wxHAS_INT64 - -#if defined(wxLongLong_t) && wxUSE_LONGLONG -wxDataOutputStream& wxDataOutputStream::operator<<(const wxULongLong &i) -{ - WriteLL(i); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(const wxLongLong &i) -{ - WriteLL(i); - return *this; -} -#endif // wxLongLong_t - -wxDataOutputStream& wxDataOutputStream::operator<<(double f) -{ - WriteDouble(f); - return *this; -} - -wxDataOutputStream& wxDataOutputStream::operator<<(float f) -{ - WriteDouble((double)f); - return *this; -} - -#endif - // wxUSE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/datstrm.cpp +// Purpose: Data stream classes +// Author: Guilhem Lavaux +// Modified by: Mickael Gilabert +// Created: 28/06/98 +// RCS-ID: $Id: datstrm.cpp 53028 2008-04-05 17:28:32Z VZ $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#include "wx/datstrm.h" + +#ifndef WX_PRECOMP + #include "wx/math.h" +#endif //WX_PRECOMP + +// --------------------------------------------------------------------------- +// wxDataInputStream +// --------------------------------------------------------------------------- + +#if wxUSE_UNICODE +wxDataInputStream::wxDataInputStream(wxInputStream& s, const wxMBConv& conv) + : m_input(&s), m_be_order(false), m_conv(conv.Clone()) +#else +wxDataInputStream::wxDataInputStream(wxInputStream& s) + : m_input(&s), m_be_order(false) +#endif +{ +} + +wxDataInputStream::~wxDataInputStream() +{ +#if wxUSE_UNICODE + delete m_conv; +#endif // wxUSE_UNICODE +} + +#if wxHAS_INT64 +wxUint64 wxDataInputStream::Read64() +{ + wxUint64 tmp; + Read64(&tmp, 1); + return tmp; +} +#endif // wxHAS_INT64 + +wxUint32 wxDataInputStream::Read32() +{ + wxUint32 i32; + + m_input->Read(&i32, 4); + + if (m_be_order) + return wxUINT32_SWAP_ON_LE(i32); + else + return wxUINT32_SWAP_ON_BE(i32); +} + +wxUint16 wxDataInputStream::Read16() +{ + wxUint16 i16; + + m_input->Read(&i16, 2); + + if (m_be_order) + return wxUINT16_SWAP_ON_LE(i16); + else + return wxUINT16_SWAP_ON_BE(i16); +} + +wxUint8 wxDataInputStream::Read8() +{ + wxUint8 buf; + + m_input->Read(&buf, 1); + return (wxUint8)buf; +} + +double wxDataInputStream::ReadDouble() +{ +#if wxUSE_APPLE_IEEE + char buf[10]; + + m_input->Read(buf, 10); + return ConvertFromIeeeExtended((const wxInt8 *)buf); +#else + return 0.0; +#endif +} + +wxString wxDataInputStream::ReadString() +{ + wxString ret; + + const size_t len = Read32(); + if ( len > 0 ) + { +#if wxUSE_UNICODE + wxCharBuffer tmp(len + 1); + if ( tmp ) + { + m_input->Read(tmp.data(), len); + tmp.data()[len] = '\0'; + ret = m_conv->cMB2WX(tmp.data()); + } +#else + wxStringBuffer buf(ret, len); + if ( buf ) + m_input->Read(buf, len); +#endif + } + + return ret; +} + +#if wxUSE_LONGLONG + +template +static +void DoReadLL(T *buffer, size_t size, wxInputStream *input, bool be_order) +{ + typedef T DataType; + unsigned char *pchBuffer = new unsigned char[size * 8]; + // TODO: Check for overflow when size is of type uint and is > than 512m + input->Read(pchBuffer, size * 8); + size_t idx_base = 0; + if ( be_order ) + { + for ( size_t uiIndex = 0; uiIndex != size; ++uiIndex ) + { + buffer[uiIndex] = 0l; + for ( unsigned ui = 0; ui != 8; ++ui ) + { + buffer[uiIndex] = buffer[uiIndex] * 256l + + DataType((unsigned long) pchBuffer[idx_base + ui]); + } + + idx_base += 8; + } + } + else // little endian + { + for ( size_t uiIndex=0; uiIndex!=size; ++uiIndex ) + { + buffer[uiIndex] = 0l; + for ( unsigned ui=0; ui!=8; ++ui ) + buffer[uiIndex] = buffer[uiIndex] * 256l + + DataType((unsigned long) pchBuffer[idx_base + 7 - ui]); + idx_base += 8; + } + } + delete[] pchBuffer; +} + +template +static void DoWriteLL(const T *buffer, size_t size, wxOutputStream *output, bool be_order) +{ + typedef T DataType; + unsigned char *pchBuffer = new unsigned char[size * 8]; + size_t idx_base = 0; + if ( be_order ) + { + for ( size_t uiIndex = 0; uiIndex != size; ++uiIndex ) + { + DataType i64 = buffer[uiIndex]; + for ( unsigned ui = 0; ui != 8; ++ui ) + { + pchBuffer[idx_base + 7 - ui] = + (unsigned char) (i64.GetLo() & 255l); + i64 >>= 8l; + } + + idx_base += 8; + } + } + else // little endian + { + for ( size_t uiIndex=0; uiIndex != size; ++uiIndex ) + { + DataType i64 = buffer[uiIndex]; + for (unsigned ui=0; ui!=8; ++ui) + { + pchBuffer[idx_base + ui] = + (unsigned char) (i64.GetLo() & 255l); + i64 >>= 8l; + } + + idx_base += 8; + } + } + + // TODO: Check for overflow when size is of type uint and is > than 512m + output->Write(pchBuffer, size * 8); + delete[] pchBuffer; +} + +#endif // wxUSE_LONGLONG + +#ifdef wxLongLong_t + +template +static +void DoReadI64(T *buffer, size_t size, wxInputStream *input, bool be_order) +{ + typedef T DataType; + unsigned char *pchBuffer = (unsigned char*) buffer; + // TODO: Check for overflow when size is of type uint and is > than 512m + input->Read(pchBuffer, size * 8); + if ( be_order ) + { + for ( wxUint32 i = 0; i < size; i++ ) + { + DataType v = wxUINT64_SWAP_ON_LE(*buffer); + *(buffer++) = v; + } + } + else // little endian + { + for ( wxUint32 i=0; i +static +void DoWriteI64(const T *buffer, size_t size, wxOutputStream *output, bool be_order) +{ + typedef T DataType; + if ( be_order ) + { + for ( size_t i = 0; i < size; i++ ) + { + DataType i64 = wxUINT64_SWAP_ON_LE(*buffer); + buffer++; + output->Write(&i64, 8); + } + } + else // little endian + { + for ( size_t i=0; i < size; i++ ) + { + DataType i64 = wxUINT64_SWAP_ON_BE(*buffer); + buffer++; + output->Write(&i64, 8); + } + } +} + +#endif // wxLongLong_t + + +#if wxHAS_INT64 +void wxDataInputStream::Read64(wxUint64 *buffer, size_t size) +{ +#ifndef wxLongLong_t + DoReadLL(buffer, size, m_input, m_be_order); +#else + DoReadI64(buffer, size, m_input, m_be_order); +#endif +} + +void wxDataInputStream::Read64(wxInt64 *buffer, size_t size) +{ +#ifndef wxLongLong_t + DoReadLL(buffer, size, m_input, m_be_order); +#else + DoReadI64(buffer, size, m_input, m_be_order); +#endif +} +#endif // wxHAS_INT64 + +#if defined(wxLongLong_t) && wxUSE_LONGLONG +void wxDataInputStream::Read64(wxULongLong *buffer, size_t size) +{ + DoReadLL(buffer, size, m_input, m_be_order); +} + +void wxDataInputStream::Read64(wxLongLong *buffer, size_t size) +{ + DoReadLL(buffer, size, m_input, m_be_order); +} +#endif // wxLongLong_t + +#if wxUSE_LONGLONG +void wxDataInputStream::ReadLL(wxULongLong *buffer, size_t size) +{ + DoReadLL(buffer, size, m_input, m_be_order); +} + +void wxDataInputStream::ReadLL(wxLongLong *buffer, size_t size) +{ + DoReadLL(buffer, size, m_input, m_be_order); +} + +wxLongLong wxDataInputStream::ReadLL(void) +{ + wxLongLong ll; + DoReadLL(&ll, (size_t)1, m_input, m_be_order); + return ll; +} +#endif // wxUSE_LONGLONG + +void wxDataInputStream::Read32(wxUint32 *buffer, size_t size) +{ + m_input->Read(buffer, size * 4); + + if (m_be_order) + { + for (wxUint32 i=0; iRead(buffer, size * 2); + + if (m_be_order) + { + for (wxUint32 i=0; iRead(buffer, size); +} + +void wxDataInputStream::ReadDouble(double *buffer, size_t size) +{ + for (wxUint32 i=0; i>(wxString& s) +{ + s = ReadString(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxInt8& c) +{ + c = (wxInt8)Read8(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxInt16& i) +{ + i = (wxInt16)Read16(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxInt32& i) +{ + i = (wxInt32)Read32(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxUint8& c) +{ + c = Read8(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxUint16& i) +{ + i = Read16(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxUint32& i) +{ + i = Read32(); + return *this; +} + +#if wxHAS_INT64 +wxDataInputStream& wxDataInputStream::operator>>(wxUint64& i) +{ + i = Read64(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxInt64& i) +{ + i = Read64(); + return *this; +} +#endif // wxHAS_INT64 + +#if defined(wxLongLong_t) && wxUSE_LONGLONG +wxDataInputStream& wxDataInputStream::operator>>(wxULongLong& i) +{ + i = ReadLL(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(wxLongLong& i) +{ + i = ReadLL(); + return *this; +} +#endif // wxLongLong_t + +wxDataInputStream& wxDataInputStream::operator>>(double& i) +{ + i = ReadDouble(); + return *this; +} + +wxDataInputStream& wxDataInputStream::operator>>(float& f) +{ + f = (float)ReadDouble(); + return *this; +} + +// --------------------------------------------------------------------------- +// wxDataOutputStream +// --------------------------------------------------------------------------- + +#if wxUSE_UNICODE +wxDataOutputStream::wxDataOutputStream(wxOutputStream& s, const wxMBConv& conv) + : m_output(&s), m_be_order(false), m_conv(conv.Clone()) +#else +wxDataOutputStream::wxDataOutputStream(wxOutputStream& s) + : m_output(&s), m_be_order(false) +#endif +{ +} + +wxDataOutputStream::~wxDataOutputStream() +{ +#if wxUSE_UNICODE + delete m_conv; +#endif // wxUSE_UNICODE +} + +#if wxHAS_INT64 +void wxDataOutputStream::Write64(wxUint64 i) +{ + Write64(&i, 1); +} + +void wxDataOutputStream::Write64(wxInt64 i) +{ + Write64(&i, 1); +} +#endif // wxHAS_INT64 + +void wxDataOutputStream::Write32(wxUint32 i) +{ + wxUint32 i32; + + if (m_be_order) + i32 = wxUINT32_SWAP_ON_LE(i); + else + i32 = wxUINT32_SWAP_ON_BE(i); + m_output->Write(&i32, 4); +} + +void wxDataOutputStream::Write16(wxUint16 i) +{ + wxUint16 i16; + + if (m_be_order) + i16 = wxUINT16_SWAP_ON_LE(i); + else + i16 = wxUINT16_SWAP_ON_BE(i); + + m_output->Write(&i16, 2); +} + +void wxDataOutputStream::Write8(wxUint8 i) +{ + m_output->Write(&i, 1); +} + +void wxDataOutputStream::WriteString(const wxString& string) +{ +#if wxUSE_UNICODE + const wxWX2MBbuf buf = string.mb_str(*m_conv); +#else + const wxWX2MBbuf buf = string.mb_str(); +#endif + size_t len = strlen(buf); + Write32(len); + if (len > 0) + m_output->Write(buf, len); +} + +void wxDataOutputStream::WriteDouble(double d) +{ + char buf[10]; + +#if wxUSE_APPLE_IEEE + ConvertToIeeeExtended(d, (wxInt8 *)buf); +#else +#if !defined(__VMS__) && !defined(__GNUG__) +# pragma warning "wxDataOutputStream::WriteDouble() not using IeeeExtended - will not work!" +#endif + buf[0] = '\0'; +#endif + m_output->Write(buf, 10); +} + +#if wxHAS_INT64 +void wxDataOutputStream::Write64(const wxUint64 *buffer, size_t size) +{ +#ifndef wxLongLong_t + DoWriteLL(buffer, size, m_output, m_be_order); +#else + DoWriteI64(buffer, size, m_output, m_be_order); +#endif +} + +void wxDataOutputStream::Write64(const wxInt64 *buffer, size_t size) +{ +#ifndef wxLongLong_t + DoWriteLL(buffer, size, m_output, m_be_order); +#else + DoWriteI64(buffer, size, m_output, m_be_order); +#endif +} +#endif // wxHAS_INT64 + +#if defined(wxLongLong_t) && wxUSE_LONGLONG +void wxDataOutputStream::Write64(const wxULongLong *buffer, size_t size) +{ + DoWriteLL(buffer, size, m_output, m_be_order); +} + +void wxDataOutputStream::Write64(const wxLongLong *buffer, size_t size) +{ + DoWriteLL(buffer, size, m_output, m_be_order); +} +#endif // wxLongLong_t + +#if wxUSE_LONGLONG +void wxDataOutputStream::WriteLL(const wxULongLong *buffer, size_t size) +{ + DoWriteLL(buffer, size, m_output, m_be_order); +} + +void wxDataOutputStream::WriteLL(const wxLongLong *buffer, size_t size) +{ + DoWriteLL(buffer, size, m_output, m_be_order); +} + +void wxDataOutputStream::WriteLL(const wxLongLong &ll) +{ + WriteLL(&ll, 1); +} + +void wxDataOutputStream::WriteLL(const wxULongLong &ll) +{ + WriteLL(&ll, 1); +} +#endif // wxUSE_LONGLONG + +void wxDataOutputStream::Write32(const wxUint32 *buffer, size_t size) +{ + if (m_be_order) + { + for (wxUint32 i=0; iWrite(&i32, 4); + } + } + else + { + for (wxUint32 i=0; iWrite(&i32, 4); + } + } +} + +void wxDataOutputStream::Write16(const wxUint16 *buffer, size_t size) +{ + if (m_be_order) + { + for (wxUint32 i=0; iWrite(&i16, 2); + } + } + else + { + for (wxUint32 i=0; iWrite(&i16, 2); + } + } +} + +void wxDataOutputStream::Write8(const wxUint8 *buffer, size_t size) +{ + m_output->Write(buffer, size); +} + +void wxDataOutputStream::WriteDouble(const double *buffer, size_t size) +{ + for (wxUint32 i=0; iWrite((const char *)string, wxStrlen(string)*sizeof(wxChar)); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(const wxString& string) +{ + WriteString(string); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(wxInt8 c) +{ + Write8((wxUint8)c); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(wxInt16 i) +{ + Write16((wxUint16)i); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(wxInt32 i) +{ + Write32((wxUint32)i); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(wxUint8 c) +{ + Write8(c); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(wxUint16 i) +{ + Write16(i); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(wxUint32 i) +{ + Write32(i); + return *this; +} + +#if wxHAS_INT64 +wxDataOutputStream& wxDataOutputStream::operator<<(wxUint64 i) +{ + Write64(i); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(wxInt64 i) +{ + Write64(i); + return *this; +} +#endif // wxHAS_INT64 + +#if defined(wxLongLong_t) && wxUSE_LONGLONG +wxDataOutputStream& wxDataOutputStream::operator<<(const wxULongLong &i) +{ + WriteLL(i); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(const wxLongLong &i) +{ + WriteLL(i); + return *this; +} +#endif // wxLongLong_t + +wxDataOutputStream& wxDataOutputStream::operator<<(double f) +{ + WriteDouble(f); + return *this; +} + +wxDataOutputStream& wxDataOutputStream::operator<<(float f) +{ + WriteDouble((double)f); + return *this; +} + +#endif + // wxUSE_STREAMS diff --git a/Source/3rd Party/wx/src/common/dcbase.cpp b/Source/3rd Party/wx/src/common/dcbase.cpp index 40e266592..ecc821d00 100644 --- a/Source/3rd Party/wx/src/common/dcbase.cpp +++ b/Source/3rd Party/wx/src/common/dcbase.cpp @@ -1,1174 +1,1174 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/dcbase.cpp -// Purpose: generic methods of the wxDC Class -// Author: Vadim Zeitlin -// Modified by: -// Created: 05/25/99 -// RCS-ID: $Id: dcbase.cpp 56135 2008-10-06 21:04:02Z VZ $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/dc.h" -#include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS - -#ifndef WX_PRECOMP - #include "wx/math.h" -#endif - -// bool wxDCBase::sm_cacheing = false; - -IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject) - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC, wxMemoryDC) -IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC, wxBufferedDC) - -#if WXWIN_COMPATIBILITY_2_6 -void wxDCBase::BeginDrawing() -{ -} - -void wxDCBase::EndDrawing() -{ -} -#endif // WXWIN_COMPATIBILITY_2_6 - -// ---------------------------------------------------------------------------- -// special symbols -// ---------------------------------------------------------------------------- - -void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1, - wxCoord width, wxCoord height) -{ - wxCHECK_RET( Ok(), wxT("invalid window dc") ); - - wxCoord x2 = x1 + width, - y2 = y1 + height; - - // the pen width is calibrated to give 3 for width == height == 10 - wxDCPenChanger pen((wxDC&)*this, - wxPen(GetTextForeground(), (width + height + 1)/7)); - - // we're drawing a scaled version of wx/generic/tick.xpm here - wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom - y3 = y1 + height / 2; // y of the left tick branch - DoDrawLine(x1, y3, x3, y2); - DoDrawLine(x3, y2, x2, y1); - - CalcBoundingBox(x1, y1); - CalcBoundingBox(x2, y2); -} - -// ---------------------------------------------------------------------------- -// line/polygons -// ---------------------------------------------------------------------------- - -void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset) -{ - int n = list->GetCount(); - wxPoint *points = new wxPoint[n]; - - int i = 0; - for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ ) - { - wxPoint *point = (wxPoint *)node->GetData(); - points[i].x = point->x; - points[i].y = point->y; - } - - DoDrawLines(n, points, xoffset, yoffset); - - delete [] points; -} - - -void wxDCBase::DrawPolygon(const wxList *list, - wxCoord xoffset, wxCoord yoffset, - int fillStyle) -{ - int n = list->GetCount(); - wxPoint *points = new wxPoint[n]; - - int i = 0; - for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ ) - { - wxPoint *point = (wxPoint *)node->GetData(); - points[i].x = point->x; - points[i].y = point->y; - } - - DoDrawPolygon(n, points, xoffset, yoffset, fillStyle); - - delete [] points; -} - -void -wxDCBase::DoDrawPolyPolygon(int n, - int count[], - wxPoint points[], - wxCoord xoffset, wxCoord yoffset, - int fillStyle) -{ - if ( n == 1 ) - { - DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle); - return; - } - - int i, j, lastOfs; - wxPoint* pts; - wxPen pen; - - for (i = j = lastOfs = 0; i < n; i++) - { - lastOfs = j; - j += count[i]; - } - pts = new wxPoint[j+n-1]; - for (i = 0; i < j; i++) - pts[i] = points[i]; - for (i = 2; i <= n; i++) - { - lastOfs -= count[n-i]; - pts[j++] = pts[lastOfs]; - } - - pen = GetPen(); - SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT)); - DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle); - SetPen(pen); - for (i = j = 0; i < n; i++) - { - DoDrawLines(count[i], pts+j, xoffset, yoffset); - j += count[i]; - } - delete[] pts; -} - -// ---------------------------------------------------------------------------- -// splines -// ---------------------------------------------------------------------------- - -#if wxUSE_SPLINES - -// TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?) -void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3) -{ - wxList point_list; - - wxPoint *point1 = new wxPoint; - point1->x = x1; point1->y = y1; - point_list.Append((wxObject*)point1); - - wxPoint *point2 = new wxPoint; - point2->x = x2; point2->y = y2; - point_list.Append((wxObject*)point2); - - wxPoint *point3 = new wxPoint; - point3->x = x3; point3->y = y3; - point_list.Append((wxObject*)point3); - - DrawSpline(&point_list); - - for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() ) - { - wxPoint *p = (wxPoint *)node->GetData(); - delete p; - } -} - -void wxDCBase::DrawSpline(int n, wxPoint points[]) -{ - wxList list; - for (int i =0; i < n; i++) - { - list.Append((wxObject*)&points[i]); - } - - DrawSpline(&list); -} - -// ----------------------------------- spline code ---------------------------------------- - -void wx_quadratic_spline(double a1, double b1, double a2, double b2, - double a3, double b3, double a4, double b4); -void wx_clear_stack(); -int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3, - double *y3, double *x4, double *y4); -void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, - double x4, double y4); -static bool wx_spline_add_point(double x, double y); -static void wx_spline_draw_point_array(wxDCBase *dc); - -wxList wx_spline_point_list; - -#define half(z1, z2) ((z1+z2)/2.0) -#define THRESHOLD 5 - -/* iterative version */ - -void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4, - double b4) -{ - register double xmid, ymid; - double x1, y1, x2, y2, x3, y3, x4, y4; - - wx_clear_stack(); - wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4); - - while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) { - xmid = (double)half(x2, x3); - ymid = (double)half(y2, y3); - if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD && - fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) { - wx_spline_add_point( x1, y1 ); - wx_spline_add_point( xmid, ymid ); - } else { - wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3), - (double)half(x3, x4), (double)half(y3, y4), x4, y4); - wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2), - (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid); - } - } -} - -/* utilities used by spline drawing routines */ - -typedef struct wx_spline_stack_struct { - double x1, y1, x2, y2, x3, y3, x4, y4; -} Stack; - -#define SPLINE_STACK_DEPTH 20 -static Stack wx_spline_stack[SPLINE_STACK_DEPTH]; -static Stack *wx_stack_top; -static int wx_stack_count; - -void wx_clear_stack() -{ - wx_stack_top = wx_spline_stack; - wx_stack_count = 0; -} - -void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) -{ - wx_stack_top->x1 = x1; - wx_stack_top->y1 = y1; - wx_stack_top->x2 = x2; - wx_stack_top->y2 = y2; - wx_stack_top->x3 = x3; - wx_stack_top->y3 = y3; - wx_stack_top->x4 = x4; - wx_stack_top->y4 = y4; - wx_stack_top++; - wx_stack_count++; -} - -int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, - double *x3, double *y3, double *x4, double *y4) -{ - if (wx_stack_count == 0) - return (0); - wx_stack_top--; - wx_stack_count--; - *x1 = wx_stack_top->x1; - *y1 = wx_stack_top->y1; - *x2 = wx_stack_top->x2; - *y2 = wx_stack_top->y2; - *x3 = wx_stack_top->x3; - *y3 = wx_stack_top->y3; - *x4 = wx_stack_top->x4; - *y4 = wx_stack_top->y4; - return (1); -} - -static bool wx_spline_add_point(double x, double y) -{ - wxPoint *point = new wxPoint ; - point->x = (int) x; - point->y = (int) y; - wx_spline_point_list.Append((wxObject*)point); - return true; -} - -static void wx_spline_draw_point_array(wxDCBase *dc) -{ - dc->DrawLines(&wx_spline_point_list, 0, 0 ); - wxList::compatibility_iterator node = wx_spline_point_list.GetFirst(); - while (node) - { - wxPoint *point = (wxPoint *)node->GetData(); - delete point; - wx_spline_point_list.Erase(node); - node = wx_spline_point_list.GetFirst(); - } -} - -void wxDCBase::DoDrawSpline( wxList *points ) -{ - wxCHECK_RET( Ok(), wxT("invalid window dc") ); - - wxPoint *p; - double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4; - double x1, y1, x2, y2; - - wxList::compatibility_iterator node = points->GetFirst(); - if (!node) - // empty list - return; - - p = (wxPoint *)node->GetData(); - - x1 = p->x; - y1 = p->y; - - node = node->GetNext(); - p = (wxPoint *)node->GetData(); - - x2 = p->x; - y2 = p->y; - cx1 = (double)((x1 + x2) / 2); - cy1 = (double)((y1 + y2) / 2); - cx2 = (double)((cx1 + x2) / 2); - cy2 = (double)((cy1 + y2) / 2); - - wx_spline_add_point(x1, y1); - - while ((node = node->GetNext()) -#if !wxUSE_STL - != NULL -#endif // !wxUSE_STL - ) - { - p = (wxPoint *)node->GetData(); - x1 = x2; - y1 = y2; - x2 = p->x; - y2 = p->y; - cx4 = (double)(x1 + x2) / 2; - cy4 = (double)(y1 + y2) / 2; - cx3 = (double)(x1 + cx4) / 2; - cy3 = (double)(y1 + cy4) / 2; - - wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4); - - cx1 = cx4; - cy1 = cy4; - cx2 = (double)(cx1 + x2) / 2; - cy2 = (double)(cy1 + y2) / 2; - } - - wx_spline_add_point( cx1, cy1 ); - wx_spline_add_point( x2, y2 ); - - wx_spline_draw_point_array( this ); -} - -#endif // wxUSE_SPLINES - -// ---------------------------------------------------------------------------- -// Partial Text Extents -// ---------------------------------------------------------------------------- - - -// Each element of the widths array will be the width of the string up to and -// including the corresponding character in text. This is the generic -// implementation, the port-specific classes should do this with native APIs -// if available and if faster. Note: pango_layout_index_to_pos is much slower -// than calling GetTextExtent!! - -#define FWC_SIZE 256 - -class FontWidthCache -{ -public: - FontWidthCache() : m_scaleX(1), m_widths(NULL) { } - ~FontWidthCache() { delete []m_widths; } - - void Reset() - { - if (!m_widths) - m_widths = new int[FWC_SIZE]; - - memset(m_widths, 0, sizeof(int)*FWC_SIZE); - } - - wxFont m_font; - double m_scaleX; - int *m_widths; -}; - -static FontWidthCache s_fontWidthCache; - -bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const -{ - int totalWidth = 0; - - const size_t len = text.length(); - widths.Empty(); - widths.Add(0, len); - - // reset the cache if font or horizontal scale have changed - if ( !s_fontWidthCache.m_widths || - !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) || - (s_fontWidthCache.m_font != GetFont()) ) - { - s_fontWidthCache.Reset(); - s_fontWidthCache.m_font = GetFont(); - s_fontWidthCache.m_scaleX = m_scaleX; - } - - // Calculate the position of each character based on the widths of - // the previous characters - int w, h; - for ( size_t i = 0; i < len; i++ ) - { - const wxChar c = text[i]; - unsigned int c_int = (unsigned int)c; - - if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0)) - { - w = s_fontWidthCache.m_widths[c_int]; - } - else - { - GetTextExtent(c, &w, &h); - if (c_int < FWC_SIZE) - s_fontWidthCache.m_widths[c_int] = w; - } - - totalWidth += w; - widths[i] = totalWidth; - } - - return true; -} - - -// ---------------------------------------------------------------------------- -// enhanced text drawing -// ---------------------------------------------------------------------------- - -void wxDCBase::GetMultiLineTextExtent(const wxString& text, - wxCoord *x, - wxCoord *y, - wxCoord *h, - wxFont *font) const -{ - wxCoord widthTextMax = 0, widthLine, - heightTextTotal = 0, heightLineDefault = 0, heightLine = 0; - - wxString curLine; - for ( const wxChar *pc = text; ; pc++ ) - { - if ( *pc == _T('\n') || *pc == _T('\0') ) - { - if ( curLine.empty() ) - { - // we can't use GetTextExtent - it will return 0 for both width - // and height and an empty line should count in height - // calculation - - // assume that this line has the same height as the previous - // one - if ( !heightLineDefault ) - heightLineDefault = heightLine; - - if ( !heightLineDefault ) - { - // but we don't know it yet - choose something reasonable - GetTextExtent(_T("W"), NULL, &heightLineDefault, - NULL, NULL, font); - } - - heightTextTotal += heightLineDefault; - } - else - { - GetTextExtent(curLine, &widthLine, &heightLine, - NULL, NULL, font); - if ( widthLine > widthTextMax ) - widthTextMax = widthLine; - heightTextTotal += heightLine; - } - - if ( *pc == _T('\n') ) - { - curLine.clear(); - } - else - { - // the end of string - break; - } - } - else - { - curLine += *pc; - } - } - - if ( x ) - *x = widthTextMax; - if ( y ) - *y = heightTextTotal; - if ( h ) - *h = heightLine; -} - -void wxDCBase::DrawLabel(const wxString& text, - const wxBitmap& bitmap, - const wxRect& rect, - int alignment, - int indexAccel, - wxRect *rectBounding) -{ - // find the text position - wxCoord widthText, heightText, heightLine; - GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine); - - wxCoord width, height; - if ( bitmap.Ok() ) - { - width = widthText + bitmap.GetWidth(); - height = bitmap.GetHeight(); - } - else // no bitmap - { - width = widthText; - height = heightText; - } - - wxCoord x, y; - if ( alignment & wxALIGN_RIGHT ) - { - x = rect.GetRight() - width; - } - else if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) - { - x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2; - } - else // alignment & wxALIGN_LEFT - { - x = rect.GetLeft(); - } - - if ( alignment & wxALIGN_BOTTOM ) - { - y = rect.GetBottom() - height; - } - else if ( alignment & wxALIGN_CENTRE_VERTICAL ) - { - y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2; - } - else // alignment & wxALIGN_TOP - { - y = rect.GetTop(); - } - - // draw the bitmap first - wxCoord x0 = x, - y0 = y, - width0 = width; - if ( bitmap.Ok() ) - { - DrawBitmap(bitmap, x, y, true /* use mask */); - - wxCoord offset = bitmap.GetWidth() + 4; - x += offset; - width -= offset; - - y += (height - heightText) / 2; - } - - // we will draw the underscore under the accel char later - wxCoord startUnderscore = 0, - endUnderscore = 0, - yUnderscore = 0; - - // split the string into lines and draw each of them separately - wxString curLine; - for ( const wxChar *pc = text; ; pc++ ) - { - if ( *pc == _T('\n') || *pc == _T('\0') ) - { - int xRealStart = x; // init it here to avoid compielr warnings - - if ( !curLine.empty() ) - { - // NB: can't test for !(alignment & wxALIGN_LEFT) because - // wxALIGN_LEFT is 0 - if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) ) - { - wxCoord widthLine; - GetTextExtent(curLine, &widthLine, NULL); - - if ( alignment & wxALIGN_RIGHT ) - { - xRealStart += width - widthLine; - } - else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) - { - xRealStart += (width - widthLine) / 2; - } - } - //else: left aligned, nothing to do - - DrawText(curLine, xRealStart, y); - } - - y += heightLine; - - // do we have underscore in this line? we can check yUnderscore - // because it is set below to just y + heightLine if we do - if ( y == yUnderscore ) - { - // adjust the horz positions to account for the shift - startUnderscore += xRealStart; - endUnderscore += xRealStart; - } - - if ( *pc == _T('\0') ) - break; - - curLine.clear(); - } - else // not end of line - { - if ( pc - text.c_str() == indexAccel ) - { - // remeber to draw underscore here - GetTextExtent(curLine, &startUnderscore, NULL); - curLine += *pc; - GetTextExtent(curLine, &endUnderscore, NULL); - - yUnderscore = y + heightLine; - } - else - { - curLine += *pc; - } - } - } - - // draw the underscore if found - if ( startUnderscore != endUnderscore ) - { - // it should be of the same colour as text - SetPen(wxPen(GetTextForeground(), 0, wxSOLID)); - - yUnderscore--; - - DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore); - } - - // return bounding rect if requested - if ( rectBounding ) - { - *rectBounding = wxRect(x, y - heightText, widthText, heightText); - } - - CalcBoundingBox(x0, y0); - CalcBoundingBox(x0 + width0, y0 + height); -} - - -void wxDCBase::DoGradientFillLinear(const wxRect& rect, - const wxColour& initialColour, - const wxColour& destColour, - wxDirection nDirection) -{ - // save old pen - wxPen oldPen = m_pen; - wxBrush oldBrush = m_brush; - - wxUint8 nR1 = initialColour.Red(); - wxUint8 nG1 = initialColour.Green(); - wxUint8 nB1 = initialColour.Blue(); - wxUint8 nR2 = destColour.Red(); - wxUint8 nG2 = destColour.Green(); - wxUint8 nB2 = destColour.Blue(); - wxUint8 nR, nG, nB; - - if ( nDirection == wxEAST || nDirection == wxWEST ) - { - wxInt32 x = rect.GetWidth(); - wxInt32 w = x; // width of area to shade - wxInt32 xDelta = w/256; // height of one shade bend - if (xDelta < 1) - xDelta = 1; - - while (x >= xDelta) - { - x -= xDelta; - if (nR1 > nR2) - nR = nR1 - (nR1-nR2)*(w-x)/w; - else - nR = nR1 + (nR2-nR1)*(w-x)/w; - - if (nG1 > nG2) - nG = nG1 - (nG1-nG2)*(w-x)/w; - else - nG = nG1 + (nG2-nG1)*(w-x)/w; - - if (nB1 > nB2) - nB = nB1 - (nB1-nB2)*(w-x)/w; - else - nB = nB1 + (nB2-nB1)*(w-x)/w; - - wxColour colour(nR,nG,nB); - SetPen(wxPen(colour, 1, wxSOLID)); - SetBrush(wxBrush(colour)); - if(nDirection == wxEAST) - DrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(), - xDelta, rect.GetHeight()); - else //nDirection == wxWEST - DrawRectangle(rect.GetLeft()+x, rect.GetTop(), - xDelta, rect.GetHeight()); - } - } - else // nDirection == wxNORTH || nDirection == wxSOUTH - { - wxInt32 y = rect.GetHeight(); - wxInt32 w = y; // height of area to shade - wxInt32 yDelta = w/255; // height of one shade bend - if (yDelta < 1) - yDelta = 1; - - while (y > 0) - { - y -= yDelta; - if (nR1 > nR2) - nR = nR1 - (nR1-nR2)*(w-y)/w; - else - nR = nR1 + (nR2-nR1)*(w-y)/w; - - if (nG1 > nG2) - nG = nG1 - (nG1-nG2)*(w-y)/w; - else - nG = nG1 + (nG2-nG1)*(w-y)/w; - - if (nB1 > nB2) - nB = nB1 - (nB1-nB2)*(w-y)/w; - else - nB = nB1 + (nB2-nB1)*(w-y)/w; - - wxColour colour(nR,nG,nB); - SetPen(wxPen(colour, 1, wxSOLID)); - SetBrush(wxBrush(colour)); - if(nDirection == wxNORTH) - DrawRectangle(rect.GetLeft(), rect.GetTop()+y, - rect.GetWidth(), yDelta); - else //nDirection == wxSOUTH - DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1, - rect.GetWidth(), yDelta); - } - } - - SetPen(oldPen); - SetBrush(oldBrush); -} - -void wxDCBase::DoGradientFillConcentric(const wxRect& rect, - const wxColour& initialColour, - const wxColour& destColour, - const wxPoint& circleCenter) -{ - //save the old pen color - wxColour oldPenColour = m_pen.GetColour(); - - wxUint8 nR1 = destColour.Red(); - wxUint8 nG1 = destColour.Green(); - wxUint8 nB1 = destColour.Blue(); - wxUint8 nR2 = initialColour.Red(); - wxUint8 nG2 = initialColour.Green(); - wxUint8 nB2 = initialColour.Blue(); - wxUint8 nR, nG, nB; - - - //Radius - wxInt32 cx = rect.GetWidth() / 2; - wxInt32 cy = rect.GetHeight() / 2; - wxInt32 nRadius; - if (cx < cy) - nRadius = cx; - else - nRadius = cy; - - //Offset of circle - wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2); - wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2); - - for ( wxInt32 x = 0; x < rect.GetWidth(); x++ ) - { - for ( wxInt32 y = 0; y < rect.GetHeight(); y++ ) - { - //get color difference - wxInt32 nGradient = ((nRadius - - (wxInt32)sqrt( - pow((double)(x - cx - nCircleOffX), 2) + - pow((double)(y - cy - nCircleOffY), 2) - )) * 100) / nRadius; - - //normalize Gradient - if (nGradient < 0 ) - nGradient = 0; - - //get dest colors - nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100)); - nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100)); - nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100)); - - //set the pixel - m_pen.SetColour(wxColour(nR,nG,nB)); - DrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop())); - } - } - //return old pen color - m_pen.SetColour(oldPenColour); -} - -/* -Notes for wxWidgets DrawEllipticArcRot(...) - -wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse. -It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...), -which are also new. - -All methods are generic, so they can be implemented in wxDCBase. -DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper -methods like (WinCE) wxDC::DoDrawArc(...). - -CalculateEllipticPoints(...) fills a given list of wxPoints with some points -of an elliptic arc. The algorithm is pixel-based: In every row (in flat -parts) or every column (in steep parts) only one pixel is calculated. -Trigonometric calculation (sin, cos, tan, atan) is only done if the -starting angle is not equal to the ending angle. The calculation of the -pixels is done using simple arithmetic only and should perform not too -bad even on devices without floating point processor. I didn't test this yet. - -Rotate(...) rotates a list of point pixel-based, you will see rounding errors. -For instance: an ellipse rotated 180 degrees is drawn -slightly different from the original. - -The points are then moved to an array and used to draw a polyline and/or polygon -(with center added, the pie). -The result looks quite similar to the native ellipse, only e few pixels differ. - -The performance on a desktop system (Athlon 1800, WinXP) is about 7 times -slower as DrawEllipse(...), which calls the native API. -An rotated ellipse outside the clipping region takes nearly the same time, -while an native ellipse outside takes nearly no time to draw. - -If you draw an arc with this new method, you will see the starting and ending angles -are calculated properly. -If you use DrawEllipticArc(...), you will see they are only correct for circles -and not properly calculated for ellipses. - -Peter Lenhard -p.lenhard@t-online.de -*/ - -#ifdef __WXWINCE__ -void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y, - wxCoord w, wxCoord h, - double sa, double ea, double angle ) -{ - wxList list; - - CalculateEllipticPoints( &list, x, y, w, h, sa, ea ); - Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) ); - - // Add center (for polygon/pie) - list.Append( (wxObject*) new wxPoint( x+w/2, y+h/2 ) ); - - // copy list into array and delete list elements - int n = list.GetCount(); - wxPoint *points = new wxPoint[n]; - int i = 0; - wxNode* node = 0; - for ( node = list.GetFirst(); node; node = node->GetNext(), i++ ) - { - wxPoint *point = (wxPoint *)node->GetData(); - points[i].x = point->x; - points[i].y = point->y; - delete point; - } - - // first draw the pie without pen, if necessary - if( GetBrush() != *wxTRANSPARENT_BRUSH ) - { - wxPen tempPen( GetPen() ); - SetPen( *wxTRANSPARENT_PEN ); - DoDrawPolygon( n, points, 0, 0 ); - SetPen( tempPen ); - } - - // then draw the arc without brush, if necessary - if( GetPen() != *wxTRANSPARENT_PEN ) - { - // without center - DoDrawLines( n-1, points, 0, 0 ); - } - - delete [] points; - -} // DrawEllipticArcRot - -void wxDCBase::Rotate( wxList* points, double angle, wxPoint center ) -{ - if( angle != 0.0 ) - { - double pi(M_PI); - double dSinA = -sin(angle*2.0*pi/360.0); - double dCosA = cos(angle*2.0*pi/360.0); - for ( wxNode* node = points->GetFirst(); node; node = node->GetNext() ) - { - wxPoint* point = (wxPoint*)node->GetData(); - - // transform coordinates, if necessary - if( center.x ) point->x -= center.x; - if( center.y ) point->y -= center.y; - - // calculate rotation, rounding simply by implicit cast to integer - int xTemp = point->x * dCosA - point->y * dSinA; - point->y = point->x * dSinA + point->y * dCosA; - point->x = xTemp; - - // back transform coordinates, if necessary - if( center.x ) point->x += center.x; - if( center.y ) point->y += center.y; - } - } -} - -void wxDCBase::CalculateEllipticPoints( wxList* points, - wxCoord xStart, wxCoord yStart, - wxCoord w, wxCoord h, - double sa, double ea ) -{ - double pi = M_PI; - double sar = 0; - double ear = 0; - int xsa = 0; - int ysa = 0; - int xea = 0; - int yea = 0; - int sq = 0; - int eq = 0; - bool bUseAngles = false; - if( w<0 ) w = -w; - if( h<0 ) h = -h; - // half-axes - wxCoord a = w/2; - wxCoord b = h/2; - // decrement 1 pixel if ellipse is smaller than 2*a, 2*b - int decrX = 0; - if( 2*a == w ) decrX = 1; - int decrY = 0; - if( 2*b == h ) decrY = 1; - // center - wxCoord xCenter = xStart + a; - wxCoord yCenter = yStart + b; - // calculate data for start and end, if necessary - if( sa != ea ) - { - bUseAngles = true; - // normalisation of angles - while( sa<0 ) sa += 360; - while( ea<0 ) ea += 360; - while( sa>=360 ) sa -= 360; - while( ea>=360 ) ea -= 360; - // calculate quadrant numbers - if( sa > 270 ) sq = 3; - else if( sa > 180 ) sq = 2; - else if( sa > 90 ) sq = 1; - if( ea > 270 ) eq = 3; - else if( ea > 180 ) eq = 2; - else if( ea > 90 ) eq = 1; - sar = sa * pi / 180.0; - ear = ea * pi / 180.0; - // correct angle circle -> ellipse - sar = atan( -a/(double)b * tan( sar ) ); - if ( sq == 1 || sq == 2 ) sar += pi; - ear = atan( -a/(double)b * tan( ear ) ); - if ( eq == 1 || eq == 2 ) ear += pi; - // coordinates of points - xsa = xCenter + a * cos( sar ); - if( sq == 0 || sq == 3 ) xsa -= decrX; - ysa = yCenter + b * sin( sar ); - if( sq == 2 || sq == 3 ) ysa -= decrY; - xea = xCenter + a * cos( ear ); - if( eq == 0 || eq == 3 ) xea -= decrX; - yea = yCenter + b * sin( ear ); - if( eq == 2 || eq == 3 ) yea -= decrY; - } // if iUseAngles - // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2 - double c1 = b * b; - double c2 = 2.0 / w; - c2 *= c2; - c2 *= c1; - wxCoord x = 0; - wxCoord y = b; - long x2 = 1; - long y2 = y*y; - long y2_old = 0; - long y_old = 0; - // Lists for quadrant 1 to 4 - wxList pointsarray[4]; - // Calculate points for first quadrant and set in all quadrants - for( x = 0; x <= a; ++x ) - { - x2 = x2+x+x-1; - y2_old = y2; - y_old = y; - bool bNewPoint = false; - while( y2 > c1 - c2 * x2 && y > 0 ) - { - bNewPoint = true; - y2 = y2-y-y+1; - --y; - } - // old y now to big: set point with old y, old x - if( bNewPoint && x>1) - { - int x1 = x - 1; - // remove points on the same line - pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) ); - pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - x1, yCenter - y_old ) ); - pointsarray[2].Insert( (wxObject*) new wxPoint( xCenter - x1, yCenter + y_old - decrY ) ); - pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) ); - } // set point - } // calculate point - - // Starting and/or ending points for the quadrants, first quadrant gets both. - pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) ); - pointsarray[0].Append( (wxObject*) new wxPoint( xCenter, yCenter - b ) ); - pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - a, yCenter ) ); - pointsarray[2].Append( (wxObject*) new wxPoint( xCenter, yCenter + b - decrY ) ); - pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) ); - - // copy quadrants in original list - if( bUseAngles ) - { - // Copy the right part of the points in the lists - // and delete the wxPoints, because they do not leave this method. - points->Append( (wxObject*) new wxPoint( xsa, ysa ) ); - int q = sq; - bool bStarted = false; - bool bReady = false; - bool bForceTurn = ( sq == eq && sa > ea ); - while( !bReady ) - { - for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() ) - { - // once: go to starting point in start quadrant - if( !bStarted && - ( - ( (wxPoint*) node->GetData() )->x < xsa+1 && q <= 1 - || - ( (wxPoint*) node->GetData() )->x > xsa-1 && q >= 2 - ) - ) - { - bStarted = true; - } - - // copy point, if not at ending point - if( bStarted ) - { - if( q != eq || bForceTurn - || - ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1 - || - ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2 - ) - { - // copy point - wxPoint* pPoint = new wxPoint( *((wxPoint*) node->GetData() ) ); - points->Append( (wxObject*) pPoint ); - } - else if( q == eq && !bForceTurn || ( (wxPoint*) node->GetData() )->x == xea) - { - bReady = true; - } - } - } // for node - ++q; - if( q > 3 ) q = 0; - bForceTurn = false; - bStarted = true; - } // while not bReady - points->Append( (wxObject*) new wxPoint( xea, yea ) ); - - // delete points - for( q = 0; q < 4; ++q ) - { - for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() ) - { - wxPoint *p = (wxPoint *)node->GetData(); - delete p; - } - } - } - else - { - wxNode* node; - // copy whole ellipse, wxPoints will be deleted outside - for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() ) - { - wxObject *p = node->GetData(); - points->Append( p ); - } - for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() ) - { - wxObject *p = node->GetData(); - points->Append( p ); - } - for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() ) - { - wxObject *p = node->GetData(); - points->Append( p ); - } - for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() ) - { - wxObject *p = node->GetData(); - points->Append( p ); - } - } // not iUseAngles -} // CalculateEllipticPoints - -#endif - - -float wxDCBase::GetFontPointSizeAdjustment(float dpi) -{ - // wxMSW has long-standing bug where wxFont point size is interpreted as - // "pixel size corresponding to given point size *on screen*". In other - // words, on a typical 600dpi printer and a typical 96dpi screen, fonts - // are ~6 times smaller when printing. Unfortunately, this bug is so severe - // that *all* printing code has to account for it and consequently, other - // ports need to emulate this bug too: - const wxSize screenPixels = wxGetDisplaySize(); - const wxSize screenMM = wxGetDisplaySizeMM(); - const float screenPPI_y = (screenPixels.y * 25.4) / screenMM.y; - return screenPPI_y / dpi; -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/dcbase.cpp +// Purpose: generic methods of the wxDC Class +// Author: Vadim Zeitlin +// Modified by: +// Created: 05/25/99 +// RCS-ID: $Id: dcbase.cpp 56135 2008-10-06 21:04:02Z VZ $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/dc.h" +#include "wx/dcbuffer.h" // for IMPLEMENT_DYNAMIC_CLASS + +#ifndef WX_PRECOMP + #include "wx/math.h" +#endif + +// bool wxDCBase::sm_cacheing = false; + +IMPLEMENT_ABSTRACT_CLASS(wxDCBase, wxObject) + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxBufferedDC, wxMemoryDC) +IMPLEMENT_ABSTRACT_CLASS(wxBufferedPaintDC, wxBufferedDC) + +#if WXWIN_COMPATIBILITY_2_6 +void wxDCBase::BeginDrawing() +{ +} + +void wxDCBase::EndDrawing() +{ +} +#endif // WXWIN_COMPATIBILITY_2_6 + +// ---------------------------------------------------------------------------- +// special symbols +// ---------------------------------------------------------------------------- + +void wxDCBase::DoDrawCheckMark(wxCoord x1, wxCoord y1, + wxCoord width, wxCoord height) +{ + wxCHECK_RET( Ok(), wxT("invalid window dc") ); + + wxCoord x2 = x1 + width, + y2 = y1 + height; + + // the pen width is calibrated to give 3 for width == height == 10 + wxDCPenChanger pen((wxDC&)*this, + wxPen(GetTextForeground(), (width + height + 1)/7)); + + // we're drawing a scaled version of wx/generic/tick.xpm here + wxCoord x3 = x1 + (4*width) / 10, // x of the tick bottom + y3 = y1 + height / 2; // y of the left tick branch + DoDrawLine(x1, y3, x3, y2); + DoDrawLine(x3, y2, x2, y1); + + CalcBoundingBox(x1, y1); + CalcBoundingBox(x2, y2); +} + +// ---------------------------------------------------------------------------- +// line/polygons +// ---------------------------------------------------------------------------- + +void wxDCBase::DrawLines(const wxList *list, wxCoord xoffset, wxCoord yoffset) +{ + int n = list->GetCount(); + wxPoint *points = new wxPoint[n]; + + int i = 0; + for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ ) + { + wxPoint *point = (wxPoint *)node->GetData(); + points[i].x = point->x; + points[i].y = point->y; + } + + DoDrawLines(n, points, xoffset, yoffset); + + delete [] points; +} + + +void wxDCBase::DrawPolygon(const wxList *list, + wxCoord xoffset, wxCoord yoffset, + int fillStyle) +{ + int n = list->GetCount(); + wxPoint *points = new wxPoint[n]; + + int i = 0; + for ( wxList::compatibility_iterator node = list->GetFirst(); node; node = node->GetNext(), i++ ) + { + wxPoint *point = (wxPoint *)node->GetData(); + points[i].x = point->x; + points[i].y = point->y; + } + + DoDrawPolygon(n, points, xoffset, yoffset, fillStyle); + + delete [] points; +} + +void +wxDCBase::DoDrawPolyPolygon(int n, + int count[], + wxPoint points[], + wxCoord xoffset, wxCoord yoffset, + int fillStyle) +{ + if ( n == 1 ) + { + DoDrawPolygon(count[0], points, xoffset, yoffset, fillStyle); + return; + } + + int i, j, lastOfs; + wxPoint* pts; + wxPen pen; + + for (i = j = lastOfs = 0; i < n; i++) + { + lastOfs = j; + j += count[i]; + } + pts = new wxPoint[j+n-1]; + for (i = 0; i < j; i++) + pts[i] = points[i]; + for (i = 2; i <= n; i++) + { + lastOfs -= count[n-i]; + pts[j++] = pts[lastOfs]; + } + + pen = GetPen(); + SetPen(wxPen(*wxBLACK, 0, wxTRANSPARENT)); + DoDrawPolygon(j, pts, xoffset, yoffset, fillStyle); + SetPen(pen); + for (i = j = 0; i < n; i++) + { + DoDrawLines(count[i], pts+j, xoffset, yoffset); + j += count[i]; + } + delete[] pts; +} + +// ---------------------------------------------------------------------------- +// splines +// ---------------------------------------------------------------------------- + +#if wxUSE_SPLINES + +// TODO: this API needs fixing (wxPointList, why (!const) "wxList *"?) +void wxDCBase::DrawSpline(wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2, wxCoord x3, wxCoord y3) +{ + wxList point_list; + + wxPoint *point1 = new wxPoint; + point1->x = x1; point1->y = y1; + point_list.Append((wxObject*)point1); + + wxPoint *point2 = new wxPoint; + point2->x = x2; point2->y = y2; + point_list.Append((wxObject*)point2); + + wxPoint *point3 = new wxPoint; + point3->x = x3; point3->y = y3; + point_list.Append((wxObject*)point3); + + DrawSpline(&point_list); + + for( wxList::compatibility_iterator node = point_list.GetFirst(); node; node = node->GetNext() ) + { + wxPoint *p = (wxPoint *)node->GetData(); + delete p; + } +} + +void wxDCBase::DrawSpline(int n, wxPoint points[]) +{ + wxList list; + for (int i =0; i < n; i++) + { + list.Append((wxObject*)&points[i]); + } + + DrawSpline(&list); +} + +// ----------------------------------- spline code ---------------------------------------- + +void wx_quadratic_spline(double a1, double b1, double a2, double b2, + double a3, double b3, double a4, double b4); +void wx_clear_stack(); +int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, double *x3, + double *y3, double *x4, double *y4); +void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, + double x4, double y4); +static bool wx_spline_add_point(double x, double y); +static void wx_spline_draw_point_array(wxDCBase *dc); + +wxList wx_spline_point_list; + +#define half(z1, z2) ((z1+z2)/2.0) +#define THRESHOLD 5 + +/* iterative version */ + +void wx_quadratic_spline(double a1, double b1, double a2, double b2, double a3, double b3, double a4, + double b4) +{ + register double xmid, ymid; + double x1, y1, x2, y2, x3, y3, x4, y4; + + wx_clear_stack(); + wx_spline_push(a1, b1, a2, b2, a3, b3, a4, b4); + + while (wx_spline_pop(&x1, &y1, &x2, &y2, &x3, &y3, &x4, &y4)) { + xmid = (double)half(x2, x3); + ymid = (double)half(y2, y3); + if (fabs(x1 - xmid) < THRESHOLD && fabs(y1 - ymid) < THRESHOLD && + fabs(xmid - x4) < THRESHOLD && fabs(ymid - y4) < THRESHOLD) { + wx_spline_add_point( x1, y1 ); + wx_spline_add_point( xmid, ymid ); + } else { + wx_spline_push(xmid, ymid, (double)half(xmid, x3), (double)half(ymid, y3), + (double)half(x3, x4), (double)half(y3, y4), x4, y4); + wx_spline_push(x1, y1, (double)half(x1, x2), (double)half(y1, y2), + (double)half(x2, xmid), (double)half(y2, ymid), xmid, ymid); + } + } +} + +/* utilities used by spline drawing routines */ + +typedef struct wx_spline_stack_struct { + double x1, y1, x2, y2, x3, y3, x4, y4; +} Stack; + +#define SPLINE_STACK_DEPTH 20 +static Stack wx_spline_stack[SPLINE_STACK_DEPTH]; +static Stack *wx_stack_top; +static int wx_stack_count; + +void wx_clear_stack() +{ + wx_stack_top = wx_spline_stack; + wx_stack_count = 0; +} + +void wx_spline_push(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) +{ + wx_stack_top->x1 = x1; + wx_stack_top->y1 = y1; + wx_stack_top->x2 = x2; + wx_stack_top->y2 = y2; + wx_stack_top->x3 = x3; + wx_stack_top->y3 = y3; + wx_stack_top->x4 = x4; + wx_stack_top->y4 = y4; + wx_stack_top++; + wx_stack_count++; +} + +int wx_spline_pop(double *x1, double *y1, double *x2, double *y2, + double *x3, double *y3, double *x4, double *y4) +{ + if (wx_stack_count == 0) + return (0); + wx_stack_top--; + wx_stack_count--; + *x1 = wx_stack_top->x1; + *y1 = wx_stack_top->y1; + *x2 = wx_stack_top->x2; + *y2 = wx_stack_top->y2; + *x3 = wx_stack_top->x3; + *y3 = wx_stack_top->y3; + *x4 = wx_stack_top->x4; + *y4 = wx_stack_top->y4; + return (1); +} + +static bool wx_spline_add_point(double x, double y) +{ + wxPoint *point = new wxPoint ; + point->x = (int) x; + point->y = (int) y; + wx_spline_point_list.Append((wxObject*)point); + return true; +} + +static void wx_spline_draw_point_array(wxDCBase *dc) +{ + dc->DrawLines(&wx_spline_point_list, 0, 0 ); + wxList::compatibility_iterator node = wx_spline_point_list.GetFirst(); + while (node) + { + wxPoint *point = (wxPoint *)node->GetData(); + delete point; + wx_spline_point_list.Erase(node); + node = wx_spline_point_list.GetFirst(); + } +} + +void wxDCBase::DoDrawSpline( wxList *points ) +{ + wxCHECK_RET( Ok(), wxT("invalid window dc") ); + + wxPoint *p; + double cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4; + double x1, y1, x2, y2; + + wxList::compatibility_iterator node = points->GetFirst(); + if (!node) + // empty list + return; + + p = (wxPoint *)node->GetData(); + + x1 = p->x; + y1 = p->y; + + node = node->GetNext(); + p = (wxPoint *)node->GetData(); + + x2 = p->x; + y2 = p->y; + cx1 = (double)((x1 + x2) / 2); + cy1 = (double)((y1 + y2) / 2); + cx2 = (double)((cx1 + x2) / 2); + cy2 = (double)((cy1 + y2) / 2); + + wx_spline_add_point(x1, y1); + + while ((node = node->GetNext()) +#if !wxUSE_STL + != NULL +#endif // !wxUSE_STL + ) + { + p = (wxPoint *)node->GetData(); + x1 = x2; + y1 = y2; + x2 = p->x; + y2 = p->y; + cx4 = (double)(x1 + x2) / 2; + cy4 = (double)(y1 + y2) / 2; + cx3 = (double)(x1 + cx4) / 2; + cy3 = (double)(y1 + cy4) / 2; + + wx_quadratic_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4); + + cx1 = cx4; + cy1 = cy4; + cx2 = (double)(cx1 + x2) / 2; + cy2 = (double)(cy1 + y2) / 2; + } + + wx_spline_add_point( cx1, cy1 ); + wx_spline_add_point( x2, y2 ); + + wx_spline_draw_point_array( this ); +} + +#endif // wxUSE_SPLINES + +// ---------------------------------------------------------------------------- +// Partial Text Extents +// ---------------------------------------------------------------------------- + + +// Each element of the widths array will be the width of the string up to and +// including the corresponding character in text. This is the generic +// implementation, the port-specific classes should do this with native APIs +// if available and if faster. Note: pango_layout_index_to_pos is much slower +// than calling GetTextExtent!! + +#define FWC_SIZE 256 + +class FontWidthCache +{ +public: + FontWidthCache() : m_scaleX(1), m_widths(NULL) { } + ~FontWidthCache() { delete []m_widths; } + + void Reset() + { + if (!m_widths) + m_widths = new int[FWC_SIZE]; + + memset(m_widths, 0, sizeof(int)*FWC_SIZE); + } + + wxFont m_font; + double m_scaleX; + int *m_widths; +}; + +static FontWidthCache s_fontWidthCache; + +bool wxDCBase::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const +{ + int totalWidth = 0; + + const size_t len = text.length(); + widths.Empty(); + widths.Add(0, len); + + // reset the cache if font or horizontal scale have changed + if ( !s_fontWidthCache.m_widths || + !wxIsSameDouble(s_fontWidthCache.m_scaleX, m_scaleX) || + (s_fontWidthCache.m_font != GetFont()) ) + { + s_fontWidthCache.Reset(); + s_fontWidthCache.m_font = GetFont(); + s_fontWidthCache.m_scaleX = m_scaleX; + } + + // Calculate the position of each character based on the widths of + // the previous characters + int w, h; + for ( size_t i = 0; i < len; i++ ) + { + const wxChar c = text[i]; + unsigned int c_int = (unsigned int)c; + + if ((c_int < FWC_SIZE) && (s_fontWidthCache.m_widths[c_int] != 0)) + { + w = s_fontWidthCache.m_widths[c_int]; + } + else + { + GetTextExtent(c, &w, &h); + if (c_int < FWC_SIZE) + s_fontWidthCache.m_widths[c_int] = w; + } + + totalWidth += w; + widths[i] = totalWidth; + } + + return true; +} + + +// ---------------------------------------------------------------------------- +// enhanced text drawing +// ---------------------------------------------------------------------------- + +void wxDCBase::GetMultiLineTextExtent(const wxString& text, + wxCoord *x, + wxCoord *y, + wxCoord *h, + wxFont *font) const +{ + wxCoord widthTextMax = 0, widthLine, + heightTextTotal = 0, heightLineDefault = 0, heightLine = 0; + + wxString curLine; + for ( const wxChar *pc = text; ; pc++ ) + { + if ( *pc == _T('\n') || *pc == _T('\0') ) + { + if ( curLine.empty() ) + { + // we can't use GetTextExtent - it will return 0 for both width + // and height and an empty line should count in height + // calculation + + // assume that this line has the same height as the previous + // one + if ( !heightLineDefault ) + heightLineDefault = heightLine; + + if ( !heightLineDefault ) + { + // but we don't know it yet - choose something reasonable + GetTextExtent(_T("W"), NULL, &heightLineDefault, + NULL, NULL, font); + } + + heightTextTotal += heightLineDefault; + } + else + { + GetTextExtent(curLine, &widthLine, &heightLine, + NULL, NULL, font); + if ( widthLine > widthTextMax ) + widthTextMax = widthLine; + heightTextTotal += heightLine; + } + + if ( *pc == _T('\n') ) + { + curLine.clear(); + } + else + { + // the end of string + break; + } + } + else + { + curLine += *pc; + } + } + + if ( x ) + *x = widthTextMax; + if ( y ) + *y = heightTextTotal; + if ( h ) + *h = heightLine; +} + +void wxDCBase::DrawLabel(const wxString& text, + const wxBitmap& bitmap, + const wxRect& rect, + int alignment, + int indexAccel, + wxRect *rectBounding) +{ + // find the text position + wxCoord widthText, heightText, heightLine; + GetMultiLineTextExtent(text, &widthText, &heightText, &heightLine); + + wxCoord width, height; + if ( bitmap.Ok() ) + { + width = widthText + bitmap.GetWidth(); + height = bitmap.GetHeight(); + } + else // no bitmap + { + width = widthText; + height = heightText; + } + + wxCoord x, y; + if ( alignment & wxALIGN_RIGHT ) + { + x = rect.GetRight() - width; + } + else if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) + { + x = (rect.GetLeft() + rect.GetRight() + 1 - width) / 2; + } + else // alignment & wxALIGN_LEFT + { + x = rect.GetLeft(); + } + + if ( alignment & wxALIGN_BOTTOM ) + { + y = rect.GetBottom() - height; + } + else if ( alignment & wxALIGN_CENTRE_VERTICAL ) + { + y = (rect.GetTop() + rect.GetBottom() + 1 - height) / 2; + } + else // alignment & wxALIGN_TOP + { + y = rect.GetTop(); + } + + // draw the bitmap first + wxCoord x0 = x, + y0 = y, + width0 = width; + if ( bitmap.Ok() ) + { + DrawBitmap(bitmap, x, y, true /* use mask */); + + wxCoord offset = bitmap.GetWidth() + 4; + x += offset; + width -= offset; + + y += (height - heightText) / 2; + } + + // we will draw the underscore under the accel char later + wxCoord startUnderscore = 0, + endUnderscore = 0, + yUnderscore = 0; + + // split the string into lines and draw each of them separately + wxString curLine; + for ( const wxChar *pc = text; ; pc++ ) + { + if ( *pc == _T('\n') || *pc == _T('\0') ) + { + int xRealStart = x; // init it here to avoid compielr warnings + + if ( !curLine.empty() ) + { + // NB: can't test for !(alignment & wxALIGN_LEFT) because + // wxALIGN_LEFT is 0 + if ( alignment & (wxALIGN_RIGHT | wxALIGN_CENTRE_HORIZONTAL) ) + { + wxCoord widthLine; + GetTextExtent(curLine, &widthLine, NULL); + + if ( alignment & wxALIGN_RIGHT ) + { + xRealStart += width - widthLine; + } + else // if ( alignment & wxALIGN_CENTRE_HORIZONTAL ) + { + xRealStart += (width - widthLine) / 2; + } + } + //else: left aligned, nothing to do + + DrawText(curLine, xRealStart, y); + } + + y += heightLine; + + // do we have underscore in this line? we can check yUnderscore + // because it is set below to just y + heightLine if we do + if ( y == yUnderscore ) + { + // adjust the horz positions to account for the shift + startUnderscore += xRealStart; + endUnderscore += xRealStart; + } + + if ( *pc == _T('\0') ) + break; + + curLine.clear(); + } + else // not end of line + { + if ( pc - text.c_str() == indexAccel ) + { + // remeber to draw underscore here + GetTextExtent(curLine, &startUnderscore, NULL); + curLine += *pc; + GetTextExtent(curLine, &endUnderscore, NULL); + + yUnderscore = y + heightLine; + } + else + { + curLine += *pc; + } + } + } + + // draw the underscore if found + if ( startUnderscore != endUnderscore ) + { + // it should be of the same colour as text + SetPen(wxPen(GetTextForeground(), 0, wxSOLID)); + + yUnderscore--; + + DrawLine(startUnderscore, yUnderscore, endUnderscore, yUnderscore); + } + + // return bounding rect if requested + if ( rectBounding ) + { + *rectBounding = wxRect(x, y - heightText, widthText, heightText); + } + + CalcBoundingBox(x0, y0); + CalcBoundingBox(x0 + width0, y0 + height); +} + + +void wxDCBase::DoGradientFillLinear(const wxRect& rect, + const wxColour& initialColour, + const wxColour& destColour, + wxDirection nDirection) +{ + // save old pen + wxPen oldPen = m_pen; + wxBrush oldBrush = m_brush; + + wxUint8 nR1 = initialColour.Red(); + wxUint8 nG1 = initialColour.Green(); + wxUint8 nB1 = initialColour.Blue(); + wxUint8 nR2 = destColour.Red(); + wxUint8 nG2 = destColour.Green(); + wxUint8 nB2 = destColour.Blue(); + wxUint8 nR, nG, nB; + + if ( nDirection == wxEAST || nDirection == wxWEST ) + { + wxInt32 x = rect.GetWidth(); + wxInt32 w = x; // width of area to shade + wxInt32 xDelta = w/256; // height of one shade bend + if (xDelta < 1) + xDelta = 1; + + while (x >= xDelta) + { + x -= xDelta; + if (nR1 > nR2) + nR = nR1 - (nR1-nR2)*(w-x)/w; + else + nR = nR1 + (nR2-nR1)*(w-x)/w; + + if (nG1 > nG2) + nG = nG1 - (nG1-nG2)*(w-x)/w; + else + nG = nG1 + (nG2-nG1)*(w-x)/w; + + if (nB1 > nB2) + nB = nB1 - (nB1-nB2)*(w-x)/w; + else + nB = nB1 + (nB2-nB1)*(w-x)/w; + + wxColour colour(nR,nG,nB); + SetPen(wxPen(colour, 1, wxSOLID)); + SetBrush(wxBrush(colour)); + if(nDirection == wxEAST) + DrawRectangle(rect.GetRight()-x-xDelta+1, rect.GetTop(), + xDelta, rect.GetHeight()); + else //nDirection == wxWEST + DrawRectangle(rect.GetLeft()+x, rect.GetTop(), + xDelta, rect.GetHeight()); + } + } + else // nDirection == wxNORTH || nDirection == wxSOUTH + { + wxInt32 y = rect.GetHeight(); + wxInt32 w = y; // height of area to shade + wxInt32 yDelta = w/255; // height of one shade bend + if (yDelta < 1) + yDelta = 1; + + while (y > 0) + { + y -= yDelta; + if (nR1 > nR2) + nR = nR1 - (nR1-nR2)*(w-y)/w; + else + nR = nR1 + (nR2-nR1)*(w-y)/w; + + if (nG1 > nG2) + nG = nG1 - (nG1-nG2)*(w-y)/w; + else + nG = nG1 + (nG2-nG1)*(w-y)/w; + + if (nB1 > nB2) + nB = nB1 - (nB1-nB2)*(w-y)/w; + else + nB = nB1 + (nB2-nB1)*(w-y)/w; + + wxColour colour(nR,nG,nB); + SetPen(wxPen(colour, 1, wxSOLID)); + SetBrush(wxBrush(colour)); + if(nDirection == wxNORTH) + DrawRectangle(rect.GetLeft(), rect.GetTop()+y, + rect.GetWidth(), yDelta); + else //nDirection == wxSOUTH + DrawRectangle(rect.GetLeft(), rect.GetBottom()-y-yDelta+1, + rect.GetWidth(), yDelta); + } + } + + SetPen(oldPen); + SetBrush(oldBrush); +} + +void wxDCBase::DoGradientFillConcentric(const wxRect& rect, + const wxColour& initialColour, + const wxColour& destColour, + const wxPoint& circleCenter) +{ + //save the old pen color + wxColour oldPenColour = m_pen.GetColour(); + + wxUint8 nR1 = destColour.Red(); + wxUint8 nG1 = destColour.Green(); + wxUint8 nB1 = destColour.Blue(); + wxUint8 nR2 = initialColour.Red(); + wxUint8 nG2 = initialColour.Green(); + wxUint8 nB2 = initialColour.Blue(); + wxUint8 nR, nG, nB; + + + //Radius + wxInt32 cx = rect.GetWidth() / 2; + wxInt32 cy = rect.GetHeight() / 2; + wxInt32 nRadius; + if (cx < cy) + nRadius = cx; + else + nRadius = cy; + + //Offset of circle + wxInt32 nCircleOffX = circleCenter.x - (rect.GetWidth() / 2); + wxInt32 nCircleOffY = circleCenter.y - (rect.GetHeight() / 2); + + for ( wxInt32 x = 0; x < rect.GetWidth(); x++ ) + { + for ( wxInt32 y = 0; y < rect.GetHeight(); y++ ) + { + //get color difference + wxInt32 nGradient = ((nRadius - + (wxInt32)sqrt( + pow((double)(x - cx - nCircleOffX), 2) + + pow((double)(y - cy - nCircleOffY), 2) + )) * 100) / nRadius; + + //normalize Gradient + if (nGradient < 0 ) + nGradient = 0; + + //get dest colors + nR = (wxUint8)(nR1 + ((nR2 - nR1) * nGradient / 100)); + nG = (wxUint8)(nG1 + ((nG2 - nG1) * nGradient / 100)); + nB = (wxUint8)(nB1 + ((nB2 - nB1) * nGradient / 100)); + + //set the pixel + m_pen.SetColour(wxColour(nR,nG,nB)); + DrawPoint(wxPoint(x + rect.GetLeft(), y + rect.GetTop())); + } + } + //return old pen color + m_pen.SetColour(oldPenColour); +} + +/* +Notes for wxWidgets DrawEllipticArcRot(...) + +wxDCBase::DrawEllipticArcRot(...) draws a rotated elliptic arc or an ellipse. +It uses wxDCBase::CalculateEllipticPoints(...) and wxDCBase::Rotate(...), +which are also new. + +All methods are generic, so they can be implemented in wxDCBase. +DoDrawEllipticArcRot(...) is virtual, so it can be called from deeper +methods like (WinCE) wxDC::DoDrawArc(...). + +CalculateEllipticPoints(...) fills a given list of wxPoints with some points +of an elliptic arc. The algorithm is pixel-based: In every row (in flat +parts) or every column (in steep parts) only one pixel is calculated. +Trigonometric calculation (sin, cos, tan, atan) is only done if the +starting angle is not equal to the ending angle. The calculation of the +pixels is done using simple arithmetic only and should perform not too +bad even on devices without floating point processor. I didn't test this yet. + +Rotate(...) rotates a list of point pixel-based, you will see rounding errors. +For instance: an ellipse rotated 180 degrees is drawn +slightly different from the original. + +The points are then moved to an array and used to draw a polyline and/or polygon +(with center added, the pie). +The result looks quite similar to the native ellipse, only e few pixels differ. + +The performance on a desktop system (Athlon 1800, WinXP) is about 7 times +slower as DrawEllipse(...), which calls the native API. +An rotated ellipse outside the clipping region takes nearly the same time, +while an native ellipse outside takes nearly no time to draw. + +If you draw an arc with this new method, you will see the starting and ending angles +are calculated properly. +If you use DrawEllipticArc(...), you will see they are only correct for circles +and not properly calculated for ellipses. + +Peter Lenhard +p.lenhard@t-online.de +*/ + +#ifdef __WXWINCE__ +void wxDCBase::DoDrawEllipticArcRot( wxCoord x, wxCoord y, + wxCoord w, wxCoord h, + double sa, double ea, double angle ) +{ + wxList list; + + CalculateEllipticPoints( &list, x, y, w, h, sa, ea ); + Rotate( &list, angle, wxPoint( x+w/2, y+h/2 ) ); + + // Add center (for polygon/pie) + list.Append( (wxObject*) new wxPoint( x+w/2, y+h/2 ) ); + + // copy list into array and delete list elements + int n = list.GetCount(); + wxPoint *points = new wxPoint[n]; + int i = 0; + wxNode* node = 0; + for ( node = list.GetFirst(); node; node = node->GetNext(), i++ ) + { + wxPoint *point = (wxPoint *)node->GetData(); + points[i].x = point->x; + points[i].y = point->y; + delete point; + } + + // first draw the pie without pen, if necessary + if( GetBrush() != *wxTRANSPARENT_BRUSH ) + { + wxPen tempPen( GetPen() ); + SetPen( *wxTRANSPARENT_PEN ); + DoDrawPolygon( n, points, 0, 0 ); + SetPen( tempPen ); + } + + // then draw the arc without brush, if necessary + if( GetPen() != *wxTRANSPARENT_PEN ) + { + // without center + DoDrawLines( n-1, points, 0, 0 ); + } + + delete [] points; + +} // DrawEllipticArcRot + +void wxDCBase::Rotate( wxList* points, double angle, wxPoint center ) +{ + if( angle != 0.0 ) + { + double pi(M_PI); + double dSinA = -sin(angle*2.0*pi/360.0); + double dCosA = cos(angle*2.0*pi/360.0); + for ( wxNode* node = points->GetFirst(); node; node = node->GetNext() ) + { + wxPoint* point = (wxPoint*)node->GetData(); + + // transform coordinates, if necessary + if( center.x ) point->x -= center.x; + if( center.y ) point->y -= center.y; + + // calculate rotation, rounding simply by implicit cast to integer + int xTemp = point->x * dCosA - point->y * dSinA; + point->y = point->x * dSinA + point->y * dCosA; + point->x = xTemp; + + // back transform coordinates, if necessary + if( center.x ) point->x += center.x; + if( center.y ) point->y += center.y; + } + } +} + +void wxDCBase::CalculateEllipticPoints( wxList* points, + wxCoord xStart, wxCoord yStart, + wxCoord w, wxCoord h, + double sa, double ea ) +{ + double pi = M_PI; + double sar = 0; + double ear = 0; + int xsa = 0; + int ysa = 0; + int xea = 0; + int yea = 0; + int sq = 0; + int eq = 0; + bool bUseAngles = false; + if( w<0 ) w = -w; + if( h<0 ) h = -h; + // half-axes + wxCoord a = w/2; + wxCoord b = h/2; + // decrement 1 pixel if ellipse is smaller than 2*a, 2*b + int decrX = 0; + if( 2*a == w ) decrX = 1; + int decrY = 0; + if( 2*b == h ) decrY = 1; + // center + wxCoord xCenter = xStart + a; + wxCoord yCenter = yStart + b; + // calculate data for start and end, if necessary + if( sa != ea ) + { + bUseAngles = true; + // normalisation of angles + while( sa<0 ) sa += 360; + while( ea<0 ) ea += 360; + while( sa>=360 ) sa -= 360; + while( ea>=360 ) ea -= 360; + // calculate quadrant numbers + if( sa > 270 ) sq = 3; + else if( sa > 180 ) sq = 2; + else if( sa > 90 ) sq = 1; + if( ea > 270 ) eq = 3; + else if( ea > 180 ) eq = 2; + else if( ea > 90 ) eq = 1; + sar = sa * pi / 180.0; + ear = ea * pi / 180.0; + // correct angle circle -> ellipse + sar = atan( -a/(double)b * tan( sar ) ); + if ( sq == 1 || sq == 2 ) sar += pi; + ear = atan( -a/(double)b * tan( ear ) ); + if ( eq == 1 || eq == 2 ) ear += pi; + // coordinates of points + xsa = xCenter + a * cos( sar ); + if( sq == 0 || sq == 3 ) xsa -= decrX; + ysa = yCenter + b * sin( sar ); + if( sq == 2 || sq == 3 ) ysa -= decrY; + xea = xCenter + a * cos( ear ); + if( eq == 0 || eq == 3 ) xea -= decrX; + yea = yCenter + b * sin( ear ); + if( eq == 2 || eq == 3 ) yea -= decrY; + } // if iUseAngles + // calculate c1 = b^2, c2 = b^2/a^2 with a = w/2, b = h/2 + double c1 = b * b; + double c2 = 2.0 / w; + c2 *= c2; + c2 *= c1; + wxCoord x = 0; + wxCoord y = b; + long x2 = 1; + long y2 = y*y; + long y2_old = 0; + long y_old = 0; + // Lists for quadrant 1 to 4 + wxList pointsarray[4]; + // Calculate points for first quadrant and set in all quadrants + for( x = 0; x <= a; ++x ) + { + x2 = x2+x+x-1; + y2_old = y2; + y_old = y; + bool bNewPoint = false; + while( y2 > c1 - c2 * x2 && y > 0 ) + { + bNewPoint = true; + y2 = y2-y-y+1; + --y; + } + // old y now to big: set point with old y, old x + if( bNewPoint && x>1) + { + int x1 = x - 1; + // remove points on the same line + pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter - y_old ) ); + pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - x1, yCenter - y_old ) ); + pointsarray[2].Insert( (wxObject*) new wxPoint( xCenter - x1, yCenter + y_old - decrY ) ); + pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + x1 - decrX, yCenter + y_old - decrY ) ); + } // set point + } // calculate point + + // Starting and/or ending points for the quadrants, first quadrant gets both. + pointsarray[0].Insert( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) ); + pointsarray[0].Append( (wxObject*) new wxPoint( xCenter, yCenter - b ) ); + pointsarray[1].Append( (wxObject*) new wxPoint( xCenter - a, yCenter ) ); + pointsarray[2].Append( (wxObject*) new wxPoint( xCenter, yCenter + b - decrY ) ); + pointsarray[3].Append( (wxObject*) new wxPoint( xCenter + a - decrX, yCenter ) ); + + // copy quadrants in original list + if( bUseAngles ) + { + // Copy the right part of the points in the lists + // and delete the wxPoints, because they do not leave this method. + points->Append( (wxObject*) new wxPoint( xsa, ysa ) ); + int q = sq; + bool bStarted = false; + bool bReady = false; + bool bForceTurn = ( sq == eq && sa > ea ); + while( !bReady ) + { + for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() ) + { + // once: go to starting point in start quadrant + if( !bStarted && + ( + ( (wxPoint*) node->GetData() )->x < xsa+1 && q <= 1 + || + ( (wxPoint*) node->GetData() )->x > xsa-1 && q >= 2 + ) + ) + { + bStarted = true; + } + + // copy point, if not at ending point + if( bStarted ) + { + if( q != eq || bForceTurn + || + ( (wxPoint*) node->GetData() )->x > xea+1 && q <= 1 + || + ( (wxPoint*) node->GetData() )->x < xea-1 && q >= 2 + ) + { + // copy point + wxPoint* pPoint = new wxPoint( *((wxPoint*) node->GetData() ) ); + points->Append( (wxObject*) pPoint ); + } + else if( q == eq && !bForceTurn || ( (wxPoint*) node->GetData() )->x == xea) + { + bReady = true; + } + } + } // for node + ++q; + if( q > 3 ) q = 0; + bForceTurn = false; + bStarted = true; + } // while not bReady + points->Append( (wxObject*) new wxPoint( xea, yea ) ); + + // delete points + for( q = 0; q < 4; ++q ) + { + for( wxNode *node = pointsarray[q].GetFirst(); node; node = node->GetNext() ) + { + wxPoint *p = (wxPoint *)node->GetData(); + delete p; + } + } + } + else + { + wxNode* node; + // copy whole ellipse, wxPoints will be deleted outside + for( node = pointsarray[0].GetFirst(); node; node = node->GetNext() ) + { + wxObject *p = node->GetData(); + points->Append( p ); + } + for( node = pointsarray[1].GetFirst(); node; node = node->GetNext() ) + { + wxObject *p = node->GetData(); + points->Append( p ); + } + for( node = pointsarray[2].GetFirst(); node; node = node->GetNext() ) + { + wxObject *p = node->GetData(); + points->Append( p ); + } + for( node = pointsarray[3].GetFirst(); node; node = node->GetNext() ) + { + wxObject *p = node->GetData(); + points->Append( p ); + } + } // not iUseAngles +} // CalculateEllipticPoints + +#endif + + +float wxDCBase::GetFontPointSizeAdjustment(float dpi) +{ + // wxMSW has long-standing bug where wxFont point size is interpreted as + // "pixel size corresponding to given point size *on screen*". In other + // words, on a typical 600dpi printer and a typical 96dpi screen, fonts + // are ~6 times smaller when printing. Unfortunately, this bug is so severe + // that *all* printing code has to account for it and consequently, other + // ports need to emulate this bug too: + const wxSize screenPixels = wxGetDisplaySize(); + const wxSize screenMM = wxGetDisplaySizeMM(); + const float screenPPI_y = (screenPixels.y * 25.4) / screenMM.y; + return screenPPI_y / dpi; +} diff --git a/Source/3rd Party/wx/src/common/dcbufcmn.cpp b/Source/3rd Party/wx/src/common/dcbufcmn.cpp index 88751fe85..3ac28eae9 100644 --- a/Source/3rd Party/wx/src/common/dcbufcmn.cpp +++ b/Source/3rd Party/wx/src/common/dcbufcmn.cpp @@ -1,95 +1,95 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/dcbufcmn.cpp -// Purpose: Buffered DC implementation -// Author: Ron Lee, Jaakko Salli -// Modified by: -// Created: Sep-20-2006 -// RCS-ID: $Id: dcbufcmn.cpp 52152 2008-02-27 18:03:12Z VZ $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/dcbuffer.h" - -#ifndef WX_PRECOMP - #include "wx/module.h" -#endif - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxSharedDCBufferManager: helper class maintaining backing store bitmap -// ---------------------------------------------------------------------------- - -class wxSharedDCBufferManager : public wxModule -{ -public: - wxSharedDCBufferManager() { } - - virtual bool OnInit() { return true; } - virtual void OnExit() { wxDELETE(ms_buffer); } - - static wxBitmap* GetBuffer(int w, int h) - { - if ( !ms_buffer || - w > ms_buffer->GetWidth() || - h > ms_buffer->GetHeight() ) - { - delete ms_buffer; - - // we must always return a valid bitmap but creating a bitmap of - // size 0 would fail, so create a 1*1 bitmap in this case - if ( !w ) - w = 1; - if ( !h ) - h = 1; - - ms_buffer = new wxBitmap(w, h); - } - return ms_buffer; - } - -private: - static wxBitmap *ms_buffer; - - DECLARE_DYNAMIC_CLASS(wxSharedDCBufferManager) -}; - -wxBitmap* wxSharedDCBufferManager::ms_buffer = NULL; - -IMPLEMENT_DYNAMIC_CLASS(wxSharedDCBufferManager, wxModule) - -// ============================================================================ -// wxBufferedDC -// ============================================================================ - -void wxBufferedDC::UseBuffer(wxCoord w, wxCoord h) -{ - if ( !m_buffer || !m_buffer->IsOk() ) - { - if ( w == -1 || h == -1 ) - m_dc->GetSize(&w, &h); - - m_buffer = wxSharedDCBufferManager::GetBuffer(w, h); - } - - SelectObject(*m_buffer); -} - +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/dcbufcmn.cpp +// Purpose: Buffered DC implementation +// Author: Ron Lee, Jaakko Salli +// Modified by: +// Created: Sep-20-2006 +// RCS-ID: $Id: dcbufcmn.cpp 52152 2008-02-27 18:03:12Z VZ $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/dcbuffer.h" + +#ifndef WX_PRECOMP + #include "wx/module.h" +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxSharedDCBufferManager: helper class maintaining backing store bitmap +// ---------------------------------------------------------------------------- + +class wxSharedDCBufferManager : public wxModule +{ +public: + wxSharedDCBufferManager() { } + + virtual bool OnInit() { return true; } + virtual void OnExit() { wxDELETE(ms_buffer); } + + static wxBitmap* GetBuffer(int w, int h) + { + if ( !ms_buffer || + w > ms_buffer->GetWidth() || + h > ms_buffer->GetHeight() ) + { + delete ms_buffer; + + // we must always return a valid bitmap but creating a bitmap of + // size 0 would fail, so create a 1*1 bitmap in this case + if ( !w ) + w = 1; + if ( !h ) + h = 1; + + ms_buffer = new wxBitmap(w, h); + } + return ms_buffer; + } + +private: + static wxBitmap *ms_buffer; + + DECLARE_DYNAMIC_CLASS(wxSharedDCBufferManager) +}; + +wxBitmap* wxSharedDCBufferManager::ms_buffer = NULL; + +IMPLEMENT_DYNAMIC_CLASS(wxSharedDCBufferManager, wxModule) + +// ============================================================================ +// wxBufferedDC +// ============================================================================ + +void wxBufferedDC::UseBuffer(wxCoord w, wxCoord h) +{ + if ( !m_buffer || !m_buffer->IsOk() ) + { + if ( w == -1 || h == -1 ) + m_dc->GetSize(&w, &h); + + m_buffer = wxSharedDCBufferManager::GetBuffer(w, h); + } + + SelectObject(*m_buffer); +} + diff --git a/Source/3rd Party/wx/src/common/dcgraph.cpp b/Source/3rd Party/wx/src/common/dcgraph.cpp index 2dcc9aa61..c9d5e11fe 100644 --- a/Source/3rd Party/wx/src/common/dcgraph.cpp +++ b/Source/3rd Party/wx/src/common/dcgraph.cpp @@ -1,1034 +1,1034 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/graphcmn.cpp -// Purpose: graphics context methods common to all platforms -// Author: Stefan Csomor -// Modified by: -// Created: -// RCS-ID: $Id: dcgraph.cpp 60190 2009-04-16 00:57:35Z KO $ -// Copyright: (c) Stefan Csomor -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#if wxUSE_GRAPHICS_CONTEXT - -#include "wx/graphics.h" - -#ifndef WX_PRECOMP - #include "wx/icon.h" - #include "wx/bitmap.h" - #include "wx/dcmemory.h" - #include "wx/region.h" -#endif - -#ifdef __WXMAC__ -#include "wx/mac/private.h" -#endif -//----------------------------------------------------------------------------- -// constants -//----------------------------------------------------------------------------- - -static const double RAD2DEG = 180.0 / M_PI; - -//----------------------------------------------------------------------------- -// Local functions -//----------------------------------------------------------------------------- - -static inline double DegToRad(double deg) -{ - return (deg * M_PI) / 180.0; -} - -//----------------------------------------------------------------------------- -// wxDC bridge class -//----------------------------------------------------------------------------- - -#ifdef __WXMAC__ -IMPLEMENT_DYNAMIC_CLASS(wxGCDC, wxDCBase) -#else -IMPLEMENT_DYNAMIC_CLASS(wxGCDC, wxDC) -#endif - -wxGCDC::wxGCDC() -{ - Init(); -} - -void wxGCDC::SetGraphicsContext( wxGraphicsContext* ctx ) -{ - delete m_graphicContext; - m_graphicContext = ctx; - if ( m_graphicContext ) - { - m_matrixOriginal = m_graphicContext->GetTransform(); - m_ok = true; - // apply the stored transformations to the passed in context - ComputeScaleAndOrigin(); - m_graphicContext->SetFont( m_font , m_textForegroundColour ); - m_graphicContext->SetPen( m_pen ); - m_graphicContext->SetBrush( m_brush); - } -} - -wxGCDC::wxGCDC(const wxWindowDC& dc) -{ - Init(); - wxGraphicsContext* context; -#if wxUSE_CAIRO - wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetCairoRenderer(); - context = renderer->CreateContext(dc); -#else - context = wxGraphicsContext::Create(dc); -#endif - - SetGraphicsContext( context ); -} - -#ifdef __WXMSW__ -wxGCDC::wxGCDC(const wxMemoryDC& dc) -{ - Init(); - SetGraphicsContext( wxGraphicsContext::Create(dc) ); -} -#endif - -void wxGCDC::Init() -{ - m_ok = false; - m_colour = true; - m_mm_to_pix_x = mm2pt; - m_mm_to_pix_y = mm2pt; - - m_pen = *wxBLACK_PEN; - m_font = *wxNORMAL_FONT; - m_brush = *wxWHITE_BRUSH; - - m_graphicContext = NULL; - m_logicalFunctionSupported = true; -} - - -wxGCDC::~wxGCDC() -{ - delete m_graphicContext; -} - -void wxGCDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool WXUNUSED(useMask) ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid DC") ); - wxCHECK_RET( bmp.Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid bitmap") ); - - if ( bmp.GetDepth() == 1 ) - { - m_graphicContext->SetPen(*wxTRANSPARENT_PEN); - m_graphicContext->SetBrush( wxBrush( m_textBackgroundColour , wxSOLID ) ); - m_graphicContext->DrawRectangle( x , y , bmp.GetWidth() , bmp.GetHeight() ); - m_graphicContext->SetBrush( wxBrush( m_textForegroundColour , wxSOLID ) ); - m_graphicContext->DrawBitmap( bmp, x , y , bmp.GetWidth() , bmp.GetHeight() ); - m_graphicContext->SetBrush( m_graphicContext->CreateBrush(m_brush)); - m_graphicContext->SetPen( m_graphicContext->CreatePen(m_pen)); - } - else - m_graphicContext->DrawBitmap( bmp, x , y , bmp.GetWidth() , bmp.GetHeight() ); -} - -void wxGCDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid DC") ); - wxCHECK_RET( icon.Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid icon") ); - - wxCoord w = icon.GetWidth(); - wxCoord h = icon.GetHeight(); - - m_graphicContext->DrawIcon( icon , x, y, w, h ); -} - -bool wxGCDC::StartDoc( const wxString& WXUNUSED(message) ) -{ - return true; -} - -void wxGCDC::EndDoc() -{ -} - -void wxGCDC::StartPage() -{ -} - -void wxGCDC::EndPage() -{ -} - -void wxGCDC::Flush() -{ -#ifdef __WXMAC__ - CGContextFlush( (CGContextRef) m_graphicContext->GetNativeContext() ); -#endif -} - -void wxGCDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegion - invalid DC") ); - - m_graphicContext->Clip( x, y, w, h ); - if ( m_clipping ) - { - m_clipX1 = wxMax( m_clipX1, x ); - m_clipY1 = wxMax( m_clipY1, y ); - m_clipX2 = wxMin( m_clipX2, (x + w) ); - m_clipY2 = wxMin( m_clipY2, (y + h) ); - } - else - { - m_clipping = true; - - m_clipX1 = x; - m_clipY1 = y; - m_clipX2 = x + w; - m_clipY2 = y + h; - } -} - -void wxGCDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) -{ - // region is in device coordinates - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegionAsRegion - invalid DC") ); - - if (region.Empty()) - { - //DestroyClippingRegion(); - return; - } - - wxRegion logRegion( region ); - wxCoord x, y, w, h; - - logRegion.Offset( DeviceToLogicalX(0), DeviceToLogicalY(0) ); - logRegion.GetBox( x, y, w, h ); - - m_graphicContext->Clip( logRegion ); - if ( m_clipping ) - { - m_clipX1 = wxMax( m_clipX1, x ); - m_clipY1 = wxMax( m_clipY1, y ); - m_clipX2 = wxMin( m_clipX2, (x + w) ); - m_clipY2 = wxMin( m_clipY2, (y + h) ); - } - else - { - m_clipping = true; - - m_clipX1 = x; - m_clipY1 = y; - m_clipX2 = x + w; - m_clipY2 = y + h; - } -} - -void wxGCDC::DestroyClippingRegion() -{ - m_graphicContext->ResetClip(); - // currently the clip eg of a window extends to the area between the scrollbars - // so we must explicitely make sure it only covers the area we want it to draw - int width, height ; - GetSize( &width , &height ) ; - m_graphicContext->Clip( DeviceToLogicalX(0) , DeviceToLogicalY(0) , DeviceToLogicalXRel(width), DeviceToLogicalYRel(height) ); - - m_graphicContext->SetPen( m_pen ); - m_graphicContext->SetBrush( m_brush ); - - m_clipping = false; -} - -void wxGCDC::DoGetSizeMM( int* width, int* height ) const -{ - int w = 0, h = 0; - - GetSize( &w, &h ); - if (width) - *width = long( double(w) / (m_scaleX * m_mm_to_pix_x) ); - if (height) - *height = long( double(h) / (m_scaleY * m_mm_to_pix_y) ); -} - -void wxGCDC::SetTextForeground( const wxColour &col ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::SetTextForeground - invalid DC") ); - - if ( col != m_textForegroundColour ) - { - m_textForegroundColour = col; - m_graphicContext->SetFont( m_font, m_textForegroundColour ); - } -} - -void wxGCDC::SetTextBackground( const wxColour &col ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::SetTextBackground - invalid DC") ); - - m_textBackgroundColour = col; -} - -void wxGCDC::SetMapMode( int mode ) -{ - switch (mode) - { - case wxMM_TWIPS: - SetLogicalScale( twips2mm * m_mm_to_pix_x, twips2mm * m_mm_to_pix_y ); - break; - - case wxMM_POINTS: - SetLogicalScale( pt2mm * m_mm_to_pix_x, pt2mm * m_mm_to_pix_y ); - break; - - case wxMM_METRIC: - SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y ); - break; - - case wxMM_LOMETRIC: - SetLogicalScale( m_mm_to_pix_x / 10.0, m_mm_to_pix_y / 10.0 ); - break; - - case wxMM_TEXT: - default: - SetLogicalScale( 1.0, 1.0 ); - break; - } - - ComputeScaleAndOrigin(); -} - -void wxGCDC::SetUserScale( double x, double y ) -{ - // allow negative ? -> no - - m_userScaleX = x; - m_userScaleY = y; - ComputeScaleAndOrigin(); -} - -void wxGCDC::SetLogicalScale( double x, double y ) -{ - // allow negative ? - m_logicalScaleX = x; - m_logicalScaleY = y; - ComputeScaleAndOrigin(); -} - -void wxGCDC::SetLogicalOrigin( wxCoord x, wxCoord y ) -{ - m_logicalOriginX = x * m_signX; // is this still correct ? - m_logicalOriginY = y * m_signY; - ComputeScaleAndOrigin(); -} - -void wxGCDC::SetDeviceOrigin( wxCoord x, wxCoord y ) -{ - m_deviceOriginX = x; - m_deviceOriginY = y; - ComputeScaleAndOrigin(); -} - -void wxGCDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) -{ - m_signX = (xLeftRight ? 1 : -1); - m_signY = (yBottomUp ? -1 : 1); - ComputeScaleAndOrigin(); -} - -wxSize wxGCDC::GetPPI() const -{ - return wxSize(72, 72); -} - -int wxGCDC::GetDepth() const -{ - return 32; -} - -void wxGCDC::ComputeScaleAndOrigin() -{ - m_scaleX = m_logicalScaleX * m_userScaleX; - m_scaleY = m_logicalScaleY * m_userScaleY; - - if ( m_graphicContext ) - { - m_matrixCurrent = m_graphicContext->CreateMatrix(); - m_matrixCurrent.Translate( m_deviceOriginX, m_deviceOriginY ); - m_matrixCurrent.Scale( m_scaleX, m_scaleY ); - // the logical origin sets the origin to have new coordinates - m_matrixCurrent.Translate( -m_logicalOriginX, -m_logicalOriginY ); - - m_graphicContext->SetTransform( m_matrixOriginal ); - m_graphicContext->ConcatTransform( m_matrixCurrent ); - } -} - -void wxGCDC::SetPalette( const wxPalette& WXUNUSED(palette) ) -{ - -} - -void wxGCDC::SetBackgroundMode( int mode ) -{ - m_backgroundMode = mode; -} - -void wxGCDC::SetFont( const wxFont &font ) -{ - m_font = font; - if ( m_graphicContext ) - { - wxFont f = font; - if ( f.Ok() ) - f.SetPointSize( /*LogicalToDeviceYRel*/(font.GetPointSize())); - m_graphicContext->SetFont( f, m_textForegroundColour ); - } -} - -void wxGCDC::SetPen( const wxPen &pen ) -{ - if ( m_pen == pen ) - return; - - m_pen = pen; - if ( m_graphicContext ) - { - m_graphicContext->SetPen( m_pen ); - } -} - -void wxGCDC::SetBrush( const wxBrush &brush ) -{ - if (m_brush == brush) - return; - - m_brush = brush; - if ( m_graphicContext ) - { - m_graphicContext->SetBrush( m_brush ); - } -} - -void wxGCDC::SetBackground( const wxBrush &brush ) -{ - if (m_backgroundBrush == brush) - return; - - m_backgroundBrush = brush; - if (!m_backgroundBrush.Ok()) - return; -} - -void wxGCDC::SetLogicalFunction( int function ) -{ - if (m_logicalFunction == function) - return; - - m_logicalFunction = function; - if ( m_graphicContext->SetLogicalFunction( function ) ) - m_logicalFunctionSupported=true; - else - m_logicalFunctionSupported=false; -} - -bool wxGCDC::DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), - const wxColour& WXUNUSED(col), int WXUNUSED(style)) -{ - return false; -} - -bool wxGCDC::DoGetPixel( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour *WXUNUSED(col) ) const -{ - // wxCHECK_MSG( 0 , false, wxT("wxGCDC(cg)::DoGetPixel - not implemented") ); - return false; -} - -void wxGCDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLine - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - m_graphicContext->StrokeLine(x1,y1,x2,y2); - - CalcBoundingBox(x1, y1); - CalcBoundingBox(x2, y2); -} - -void wxGCDC::DoCrossHair( wxCoord x, wxCoord y ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoCrossHair - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - int w = 0, h = 0; - - GetSize( &w, &h ); - - m_graphicContext->StrokeLine(0,y,w,y); - m_graphicContext->StrokeLine(x,0,x,h); - - CalcBoundingBox(0, 0); - CalcBoundingBox(0+w, 0+h); -} - -void wxGCDC::DoDrawArc( wxCoord x1, wxCoord y1, - wxCoord x2, wxCoord y2, - wxCoord xc, wxCoord yc ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawArc - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - double dx = x1 - xc; - double dy = y1 - yc; - double radius = sqrt((double)(dx * dx + dy * dy)); - wxCoord rad = (wxCoord)radius; - double sa, ea; - if (x1 == x2 && y1 == y2) - { - sa = 0.0; - ea = 360.0; - } - else if (radius == 0.0) - { - sa = ea = 0.0; - } - else - { - sa = (x1 - xc == 0) ? - (y1 - yc < 0) ? 90.0 : -90.0 : - -atan2(double(y1 - yc), double(x1 - xc)) * RAD2DEG; - ea = (x2 - xc == 0) ? - (y2 - yc < 0) ? 90.0 : -90.0 : - -atan2(double(y2 - yc), double(x2 - xc)) * RAD2DEG; - } - - bool fill = m_brush.GetStyle() != wxTRANSPARENT; - - wxGraphicsPath path = m_graphicContext->CreatePath(); - if ( fill && ((x1!=x2)||(y1!=y2)) ) - path.MoveToPoint( xc, yc ); - // since these angles (ea,sa) are measured counter-clockwise, we invert them to - // get clockwise angles - path.AddArc( xc, yc , rad , DegToRad(-sa) , DegToRad(-ea), false ); - if ( fill && ((x1!=x2)||(y1!=y2)) ) - path.AddLineToPoint( xc, yc ); - m_graphicContext->DrawPath(path); -} - -void wxGCDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h, - double sa, double ea ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipticArc - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - m_graphicContext->PushState(); - m_graphicContext->Translate(x+w/2.0,y+h/2.0); - wxDouble factor = ((wxDouble) w) / h; - m_graphicContext->Scale( factor , 1.0); - - // since these angles (ea,sa) are measured counter-clockwise, we invert them to - // get clockwise angles - if ( m_brush.GetStyle() != wxTRANSPARENT ) - { - wxGraphicsPath path = m_graphicContext->CreatePath(); - path.MoveToPoint( 0, 0 ); - path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); - path.AddLineToPoint( 0, 0 ); - m_graphicContext->FillPath( path ); - - path = m_graphicContext->CreatePath(); - path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); - m_graphicContext->StrokePath( path ); - } - else - { - wxGraphicsPath path = m_graphicContext->CreatePath(); - path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); - m_graphicContext->DrawPath( path ); - } - - m_graphicContext->PopState(); -} - -void wxGCDC::DoDrawPoint( wxCoord x, wxCoord y ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawPoint - invalid DC") ); - - DoDrawLine( x , y , x + 1 , y + 1 ); -} - -void wxGCDC::DoDrawLines(int n, wxPoint points[], - wxCoord xoffset, wxCoord yoffset) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLines - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - wxPoint2DDouble* pointsD = new wxPoint2DDouble[n]; - for( int i = 0; i < n; ++i) - { - pointsD[i].m_x = points[i].x + xoffset; - pointsD[i].m_y = points[i].y + yoffset; - } - - m_graphicContext->StrokeLines( n , pointsD); - delete[] pointsD; -} - -#if wxUSE_SPLINES -void wxGCDC::DoDrawSpline(wxList *points) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawSpline - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - wxGraphicsPath path = m_graphicContext->CreatePath(); - - wxList::compatibility_iterator node = points->GetFirst(); - if (node == wxList::compatibility_iterator()) - // empty list - return; - - wxPoint *p = (wxPoint *)node->GetData(); - - wxCoord x1 = p->x; - wxCoord y1 = p->y; - - node = node->GetNext(); - p = (wxPoint *)node->GetData(); - - wxCoord x2 = p->x; - wxCoord y2 = p->y; - wxCoord cx1 = ( x1 + x2 ) / 2; - wxCoord cy1 = ( y1 + y2 ) / 2; - - path.MoveToPoint( x1 , y1 ); - path.AddLineToPoint( cx1 , cy1 ); -#if !wxUSE_STL - - while ((node = node->GetNext()) != NULL) -#else - - while ((node = node->GetNext())) -#endif // !wxUSE_STL - - { - p = (wxPoint *)node->GetData(); - x1 = x2; - y1 = y2; - x2 = p->x; - y2 = p->y; - wxCoord cx4 = (x1 + x2) / 2; - wxCoord cy4 = (y1 + y2) / 2; - - path.AddQuadCurveToPoint(x1 , y1 ,cx4 , cy4 ); - - cx1 = cx4; - cy1 = cy4; - } - - path.AddLineToPoint( x2 , y2 ); - - m_graphicContext->StrokePath( path ); -} -#endif // wxUSE_SPLINES - -void wxGCDC::DoDrawPolygon( int n, wxPoint points[], - wxCoord xoffset, wxCoord yoffset, - int fillStyle ) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawPolygon - invalid DC") ); - - if ( n <= 0 || (m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) ) - return; - if ( !m_logicalFunctionSupported ) - return; - - bool closeIt = false; - if (points[n-1] != points[0]) - closeIt = true; - - wxPoint2DDouble* pointsD = new wxPoint2DDouble[n+(closeIt?1:0)]; - for( int i = 0; i < n; ++i) - { - pointsD[i].m_x = points[i].x + xoffset; - pointsD[i].m_y = points[i].y + yoffset; - } - if ( closeIt ) - pointsD[n] = pointsD[0]; - - m_graphicContext->DrawLines( n+(closeIt?1:0) , pointsD, fillStyle); - delete[] pointsD; -} - -void wxGCDC::DoDrawPolyPolygon(int n, - int count[], - wxPoint points[], - wxCoord xoffset, - wxCoord yoffset, - int fillStyle) -{ - wxASSERT(n > 1); - wxGraphicsPath path = m_graphicContext->CreatePath(); - - int i = 0; - for ( int j = 0; j < n; ++j) - { - wxPoint start = points[i]; - path.MoveToPoint( start.x+ xoffset, start.y+ yoffset); - ++i; - int l = count[j]; - for ( int k = 1; k < l; ++k) - { - path.AddLineToPoint( points[i].x+ xoffset, points[i].y+ yoffset); - ++i; - } - // close the polygon - if ( start != points[i-1]) - path.AddLineToPoint( start.x+ xoffset, start.y+ yoffset); - } - m_graphicContext->DrawPath( path , fillStyle); -} - -void wxGCDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRectangle - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - // CMB: draw nothing if transformed w or h is 0 - if (w == 0 || h == 0) - return; - - if ( m_graphicContext->ShouldOffset() ) - { - // if we are offsetting the entire rectangle is moved 0.5, so the - // border line gets off by 1 - w -= 1; - h -= 1; - } - m_graphicContext->DrawRectangle(x,y,w,h); -} - -void wxGCDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, - wxCoord w, wxCoord h, - double radius) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRoundedRectangle - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - if (radius < 0.0) - radius = - radius * ((w < h) ? w : h); - - // CMB: draw nothing if transformed w or h is 0 - if (w == 0 || h == 0) - return; - - if ( m_graphicContext->ShouldOffset() ) - { - // if we are offsetting the entire rectangle is moved 0.5, so the - // border line gets off by 1 - w -= 1; - h -= 1; - } - m_graphicContext->DrawRoundedRectangle( x,y,w,h,radius); -} - -void wxGCDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord w, wxCoord h) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipse - invalid DC") ); - - if ( !m_logicalFunctionSupported ) - return; - - if ( m_graphicContext->ShouldOffset() ) - { - // if we are offsetting the entire rectangle is moved 0.5, so the - // border line gets off by 1 - w -= 1; - h -= 1; - } - m_graphicContext->DrawEllipse(x,y,w,h); -} - -bool wxGCDC::CanDrawBitmap() const -{ - return true; -} - -bool wxGCDC::DoBlit( - wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, - wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool WXUNUSED(useMask), - wxCoord xsrcMask, wxCoord ysrcMask ) -{ - wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid DC") ); - wxCHECK_MSG( source->Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid source DC") ); - - if ( logical_func == wxNO_OP ) - return true; - else if ( !m_graphicContext->SetLogicalFunction( logical_func ) ) - - { - wxFAIL_MSG( wxT("Logical function is not supported by the graphics context.") ); - return false; - } - - if (xsrcMask == -1 && ysrcMask == -1) - { - xsrcMask = xsrc; - ysrcMask = ysrc; - } - - wxRect subrect(source->LogicalToDeviceX(xsrc), - source->LogicalToDeviceY(ysrc), - source->LogicalToDeviceXRel(width), - source->LogicalToDeviceYRel(height)); - - // if needed clip the subrect down to the size of the source DC - wxCoord sw, sh; - source->GetSize(&sw, &sh); - sw = source->LogicalToDeviceXRel(sw); - sh = source->LogicalToDeviceYRel(sh); - if (subrect.x + subrect.width > sw) - subrect.width = sw - subrect.x; - if (subrect.y + subrect.height > sh) - subrect.height = sh - subrect.y; - - wxBitmap blit = source->GetAsBitmap( &subrect ); - - if ( blit.Ok() ) - { - m_graphicContext->DrawBitmap( blit, xdest, ydest, - wxMin(width, blit.GetWidth()), - wxMin(height, blit.GetHeight())); - } - else - { - wxFAIL_MSG( wxT("Cannot Blit. Unable to get contents of DC as bitmap.") ); - return false; - } - - // reset logical function - m_graphicContext->SetLogicalFunction( m_logicalFunction ); - - return true; -} - -void wxGCDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y, - double angle) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") ); - - if ( str.length() == 0 ) - return; - if ( !m_logicalFunctionSupported ) - return; - - if ( m_backgroundMode == wxTRANSPARENT ) - m_graphicContext->DrawText( str, x ,y , DegToRad(angle )); - else - m_graphicContext->DrawText( str, x ,y , DegToRad(angle ), m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) ); -} - -void wxGCDC::DoDrawText(const wxString& str, wxCoord x, wxCoord y) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") ); - - if ( str.length() == 0 ) - return; - - if ( !m_logicalFunctionSupported ) - return; - - if ( m_backgroundMode == wxTRANSPARENT ) - m_graphicContext->DrawText( str, x ,y); - else - m_graphicContext->DrawText( str, x ,y , m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) ); -} - -bool wxGCDC::CanGetTextExtent() const -{ - wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::CanGetTextExtent - invalid DC") ); - - return true; -} - -void wxGCDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height, - wxCoord *descent, wxCoord *externalLeading , - wxFont *theFont ) const -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoGetTextExtent - invalid DC") ); - - if ( theFont ) - { - m_graphicContext->SetFont( *theFont, m_textForegroundColour ); - } - - wxDouble h , d , e , w; - - m_graphicContext->GetTextExtent( str, &w, &h, &d, &e ); - - if ( height ) - *height = (wxCoord)(h+0.5); - if ( descent ) - *descent = (wxCoord)(d+0.5); - if ( externalLeading ) - *externalLeading = (wxCoord)(e+0.5); - if ( width ) - *width = (wxCoord)(w+0.5); - - if ( theFont ) - { - m_graphicContext->SetFont( m_font, m_textForegroundColour ); - } -} - -bool wxGCDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const -{ - wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoGetPartialTextExtents - invalid DC") ); - widths.Clear(); - widths.Add(0,text.Length()); - if ( text.IsEmpty() ) - return true; - - wxArrayDouble widthsD; - - m_graphicContext->GetPartialTextExtents( text, widthsD ); - for ( size_t i = 0; i < widths.GetCount(); ++i ) - widths[i] = (wxCoord)(widthsD[i] + 0.5); - - return true; -} - -wxCoord wxGCDC::GetCharWidth(void) const -{ - wxCoord width; - DoGetTextExtent( wxT("g") , &width , NULL , NULL , NULL , NULL ); - - return width; -} - -wxCoord wxGCDC::GetCharHeight(void) const -{ - wxCoord height; - DoGetTextExtent( wxT("g") , NULL , &height , NULL , NULL , NULL ); - - return height; -} - -void wxGCDC::Clear(void) -{ - wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::Clear - invalid DC") ); - // TODO better implementation / incorporate size info into wxGCDC or context - m_graphicContext->SetBrush( m_backgroundBrush ); - wxPen p = *wxTRANSPARENT_PEN; - m_graphicContext->SetPen( p ); - DoDrawRectangle( 0, 0, 32000 , 32000 ); - m_graphicContext->SetPen( m_pen ); - m_graphicContext->SetBrush( m_brush ); -} - -void wxGCDC::DoGetSize(int *width, int *height) const -{ - *width = 10000; - *height = 10000; -} - -void wxGCDC::DoGradientFillLinear(const wxRect& rect, - const wxColour& initialColour, - const wxColour& destColour, - wxDirection nDirection ) -{ - wxPoint start; - wxPoint end; - switch( nDirection) - { - case wxWEST : - start = rect.GetRightBottom(); - start.x++; - end = rect.GetLeftBottom(); - break; - case wxEAST : - start = rect.GetLeftBottom(); - end = rect.GetRightBottom(); - end.x++; - break; - case wxNORTH : - start = rect.GetLeftBottom(); - start.y++; - end = rect.GetLeftTop(); - break; - case wxSOUTH : - start = rect.GetLeftTop(); - end = rect.GetLeftBottom(); - end.y++; - break; - default : - break; - } - - if (rect.width == 0 || rect.height == 0) - return; - - m_graphicContext->SetBrush( m_graphicContext->CreateLinearGradientBrush( - start.x,start.y,end.x,end.y, initialColour, destColour)); - m_graphicContext->SetPen(*wxTRANSPARENT_PEN); - m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); - m_graphicContext->SetPen(m_pen); -} - -void wxGCDC::DoGradientFillConcentric(const wxRect& rect, - const wxColour& initialColour, - const wxColour& destColour, - const wxPoint& circleCenter) -{ - //Radius - wxInt32 cx = rect.GetWidth() / 2; - wxInt32 cy = rect.GetHeight() / 2; - wxInt32 nRadius; - if (cx < cy) - nRadius = cx; - else - nRadius = cy; - - // make sure the background is filled (todo move into specific platform implementation ?) - m_graphicContext->SetPen(*wxTRANSPARENT_PEN); - m_graphicContext->SetBrush( wxBrush( destColour) ); - m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); - - m_graphicContext->SetBrush( m_graphicContext->CreateRadialGradientBrush( - rect.x+circleCenter.x,rect.y+circleCenter.y, - rect.x+circleCenter.x,rect.y+circleCenter.y, - nRadius,initialColour,destColour)); - - m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); - m_graphicContext->SetPen(m_pen); -} - -void wxGCDC::DoDrawCheckMark(wxCoord x, wxCoord y, - wxCoord width, wxCoord height) -{ - wxDCBase::DoDrawCheckMark(x,y,width,height); -} - -#endif // wxUSE_GRAPHICS_CONTEXT +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/graphcmn.cpp +// Purpose: graphics context methods common to all platforms +// Author: Stefan Csomor +// Modified by: +// Created: +// RCS-ID: $Id: dcgraph.cpp 60190 2009-04-16 00:57:35Z KO $ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#if wxUSE_GRAPHICS_CONTEXT + +#include "wx/graphics.h" + +#ifndef WX_PRECOMP + #include "wx/icon.h" + #include "wx/bitmap.h" + #include "wx/dcmemory.h" + #include "wx/region.h" +#endif + +#ifdef __WXMAC__ +#include "wx/mac/private.h" +#endif +//----------------------------------------------------------------------------- +// constants +//----------------------------------------------------------------------------- + +static const double RAD2DEG = 180.0 / M_PI; + +//----------------------------------------------------------------------------- +// Local functions +//----------------------------------------------------------------------------- + +static inline double DegToRad(double deg) +{ + return (deg * M_PI) / 180.0; +} + +//----------------------------------------------------------------------------- +// wxDC bridge class +//----------------------------------------------------------------------------- + +#ifdef __WXMAC__ +IMPLEMENT_DYNAMIC_CLASS(wxGCDC, wxDCBase) +#else +IMPLEMENT_DYNAMIC_CLASS(wxGCDC, wxDC) +#endif + +wxGCDC::wxGCDC() +{ + Init(); +} + +void wxGCDC::SetGraphicsContext( wxGraphicsContext* ctx ) +{ + delete m_graphicContext; + m_graphicContext = ctx; + if ( m_graphicContext ) + { + m_matrixOriginal = m_graphicContext->GetTransform(); + m_ok = true; + // apply the stored transformations to the passed in context + ComputeScaleAndOrigin(); + m_graphicContext->SetFont( m_font , m_textForegroundColour ); + m_graphicContext->SetPen( m_pen ); + m_graphicContext->SetBrush( m_brush); + } +} + +wxGCDC::wxGCDC(const wxWindowDC& dc) +{ + Init(); + wxGraphicsContext* context; +#if wxUSE_CAIRO + wxGraphicsRenderer* renderer = wxGraphicsRenderer::GetCairoRenderer(); + context = renderer->CreateContext(dc); +#else + context = wxGraphicsContext::Create(dc); +#endif + + SetGraphicsContext( context ); +} + +#ifdef __WXMSW__ +wxGCDC::wxGCDC(const wxMemoryDC& dc) +{ + Init(); + SetGraphicsContext( wxGraphicsContext::Create(dc) ); +} +#endif + +void wxGCDC::Init() +{ + m_ok = false; + m_colour = true; + m_mm_to_pix_x = mm2pt; + m_mm_to_pix_y = mm2pt; + + m_pen = *wxBLACK_PEN; + m_font = *wxNORMAL_FONT; + m_brush = *wxWHITE_BRUSH; + + m_graphicContext = NULL; + m_logicalFunctionSupported = true; +} + + +wxGCDC::~wxGCDC() +{ + delete m_graphicContext; +} + +void wxGCDC::DoDrawBitmap( const wxBitmap &bmp, wxCoord x, wxCoord y, bool WXUNUSED(useMask) ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid DC") ); + wxCHECK_RET( bmp.Ok(), wxT("wxGCDC(cg)::DoDrawBitmap - invalid bitmap") ); + + if ( bmp.GetDepth() == 1 ) + { + m_graphicContext->SetPen(*wxTRANSPARENT_PEN); + m_graphicContext->SetBrush( wxBrush( m_textBackgroundColour , wxSOLID ) ); + m_graphicContext->DrawRectangle( x , y , bmp.GetWidth() , bmp.GetHeight() ); + m_graphicContext->SetBrush( wxBrush( m_textForegroundColour , wxSOLID ) ); + m_graphicContext->DrawBitmap( bmp, x , y , bmp.GetWidth() , bmp.GetHeight() ); + m_graphicContext->SetBrush( m_graphicContext->CreateBrush(m_brush)); + m_graphicContext->SetPen( m_graphicContext->CreatePen(m_pen)); + } + else + m_graphicContext->DrawBitmap( bmp, x , y , bmp.GetWidth() , bmp.GetHeight() ); +} + +void wxGCDC::DoDrawIcon( const wxIcon &icon, wxCoord x, wxCoord y ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid DC") ); + wxCHECK_RET( icon.Ok(), wxT("wxGCDC(cg)::DoDrawIcon - invalid icon") ); + + wxCoord w = icon.GetWidth(); + wxCoord h = icon.GetHeight(); + + m_graphicContext->DrawIcon( icon , x, y, w, h ); +} + +bool wxGCDC::StartDoc( const wxString& WXUNUSED(message) ) +{ + return true; +} + +void wxGCDC::EndDoc() +{ +} + +void wxGCDC::StartPage() +{ +} + +void wxGCDC::EndPage() +{ +} + +void wxGCDC::Flush() +{ +#ifdef __WXMAC__ + CGContextFlush( (CGContextRef) m_graphicContext->GetNativeContext() ); +#endif +} + +void wxGCDC::DoSetClippingRegion( wxCoord x, wxCoord y, wxCoord w, wxCoord h ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegion - invalid DC") ); + + m_graphicContext->Clip( x, y, w, h ); + if ( m_clipping ) + { + m_clipX1 = wxMax( m_clipX1, x ); + m_clipY1 = wxMax( m_clipY1, y ); + m_clipX2 = wxMin( m_clipX2, (x + w) ); + m_clipY2 = wxMin( m_clipY2, (y + h) ); + } + else + { + m_clipping = true; + + m_clipX1 = x; + m_clipY1 = y; + m_clipX2 = x + w; + m_clipY2 = y + h; + } +} + +void wxGCDC::DoSetClippingRegionAsRegion( const wxRegion ®ion ) +{ + // region is in device coordinates + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoSetClippingRegionAsRegion - invalid DC") ); + + if (region.Empty()) + { + //DestroyClippingRegion(); + return; + } + + wxRegion logRegion( region ); + wxCoord x, y, w, h; + + logRegion.Offset( DeviceToLogicalX(0), DeviceToLogicalY(0) ); + logRegion.GetBox( x, y, w, h ); + + m_graphicContext->Clip( logRegion ); + if ( m_clipping ) + { + m_clipX1 = wxMax( m_clipX1, x ); + m_clipY1 = wxMax( m_clipY1, y ); + m_clipX2 = wxMin( m_clipX2, (x + w) ); + m_clipY2 = wxMin( m_clipY2, (y + h) ); + } + else + { + m_clipping = true; + + m_clipX1 = x; + m_clipY1 = y; + m_clipX2 = x + w; + m_clipY2 = y + h; + } +} + +void wxGCDC::DestroyClippingRegion() +{ + m_graphicContext->ResetClip(); + // currently the clip eg of a window extends to the area between the scrollbars + // so we must explicitely make sure it only covers the area we want it to draw + int width, height ; + GetSize( &width , &height ) ; + m_graphicContext->Clip( DeviceToLogicalX(0) , DeviceToLogicalY(0) , DeviceToLogicalXRel(width), DeviceToLogicalYRel(height) ); + + m_graphicContext->SetPen( m_pen ); + m_graphicContext->SetBrush( m_brush ); + + m_clipping = false; +} + +void wxGCDC::DoGetSizeMM( int* width, int* height ) const +{ + int w = 0, h = 0; + + GetSize( &w, &h ); + if (width) + *width = long( double(w) / (m_scaleX * m_mm_to_pix_x) ); + if (height) + *height = long( double(h) / (m_scaleY * m_mm_to_pix_y) ); +} + +void wxGCDC::SetTextForeground( const wxColour &col ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::SetTextForeground - invalid DC") ); + + if ( col != m_textForegroundColour ) + { + m_textForegroundColour = col; + m_graphicContext->SetFont( m_font, m_textForegroundColour ); + } +} + +void wxGCDC::SetTextBackground( const wxColour &col ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::SetTextBackground - invalid DC") ); + + m_textBackgroundColour = col; +} + +void wxGCDC::SetMapMode( int mode ) +{ + switch (mode) + { + case wxMM_TWIPS: + SetLogicalScale( twips2mm * m_mm_to_pix_x, twips2mm * m_mm_to_pix_y ); + break; + + case wxMM_POINTS: + SetLogicalScale( pt2mm * m_mm_to_pix_x, pt2mm * m_mm_to_pix_y ); + break; + + case wxMM_METRIC: + SetLogicalScale( m_mm_to_pix_x, m_mm_to_pix_y ); + break; + + case wxMM_LOMETRIC: + SetLogicalScale( m_mm_to_pix_x / 10.0, m_mm_to_pix_y / 10.0 ); + break; + + case wxMM_TEXT: + default: + SetLogicalScale( 1.0, 1.0 ); + break; + } + + ComputeScaleAndOrigin(); +} + +void wxGCDC::SetUserScale( double x, double y ) +{ + // allow negative ? -> no + + m_userScaleX = x; + m_userScaleY = y; + ComputeScaleAndOrigin(); +} + +void wxGCDC::SetLogicalScale( double x, double y ) +{ + // allow negative ? + m_logicalScaleX = x; + m_logicalScaleY = y; + ComputeScaleAndOrigin(); +} + +void wxGCDC::SetLogicalOrigin( wxCoord x, wxCoord y ) +{ + m_logicalOriginX = x * m_signX; // is this still correct ? + m_logicalOriginY = y * m_signY; + ComputeScaleAndOrigin(); +} + +void wxGCDC::SetDeviceOrigin( wxCoord x, wxCoord y ) +{ + m_deviceOriginX = x; + m_deviceOriginY = y; + ComputeScaleAndOrigin(); +} + +void wxGCDC::SetAxisOrientation( bool xLeftRight, bool yBottomUp ) +{ + m_signX = (xLeftRight ? 1 : -1); + m_signY = (yBottomUp ? -1 : 1); + ComputeScaleAndOrigin(); +} + +wxSize wxGCDC::GetPPI() const +{ + return wxSize(72, 72); +} + +int wxGCDC::GetDepth() const +{ + return 32; +} + +void wxGCDC::ComputeScaleAndOrigin() +{ + m_scaleX = m_logicalScaleX * m_userScaleX; + m_scaleY = m_logicalScaleY * m_userScaleY; + + if ( m_graphicContext ) + { + m_matrixCurrent = m_graphicContext->CreateMatrix(); + m_matrixCurrent.Translate( m_deviceOriginX, m_deviceOriginY ); + m_matrixCurrent.Scale( m_scaleX, m_scaleY ); + // the logical origin sets the origin to have new coordinates + m_matrixCurrent.Translate( -m_logicalOriginX, -m_logicalOriginY ); + + m_graphicContext->SetTransform( m_matrixOriginal ); + m_graphicContext->ConcatTransform( m_matrixCurrent ); + } +} + +void wxGCDC::SetPalette( const wxPalette& WXUNUSED(palette) ) +{ + +} + +void wxGCDC::SetBackgroundMode( int mode ) +{ + m_backgroundMode = mode; +} + +void wxGCDC::SetFont( const wxFont &font ) +{ + m_font = font; + if ( m_graphicContext ) + { + wxFont f = font; + if ( f.Ok() ) + f.SetPointSize( /*LogicalToDeviceYRel*/(font.GetPointSize())); + m_graphicContext->SetFont( f, m_textForegroundColour ); + } +} + +void wxGCDC::SetPen( const wxPen &pen ) +{ + if ( m_pen == pen ) + return; + + m_pen = pen; + if ( m_graphicContext ) + { + m_graphicContext->SetPen( m_pen ); + } +} + +void wxGCDC::SetBrush( const wxBrush &brush ) +{ + if (m_brush == brush) + return; + + m_brush = brush; + if ( m_graphicContext ) + { + m_graphicContext->SetBrush( m_brush ); + } +} + +void wxGCDC::SetBackground( const wxBrush &brush ) +{ + if (m_backgroundBrush == brush) + return; + + m_backgroundBrush = brush; + if (!m_backgroundBrush.Ok()) + return; +} + +void wxGCDC::SetLogicalFunction( int function ) +{ + if (m_logicalFunction == function) + return; + + m_logicalFunction = function; + if ( m_graphicContext->SetLogicalFunction( function ) ) + m_logicalFunctionSupported=true; + else + m_logicalFunctionSupported=false; +} + +bool wxGCDC::DoFloodFill(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), + const wxColour& WXUNUSED(col), int WXUNUSED(style)) +{ + return false; +} + +bool wxGCDC::DoGetPixel( wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxColour *WXUNUSED(col) ) const +{ + // wxCHECK_MSG( 0 , false, wxT("wxGCDC(cg)::DoGetPixel - not implemented") ); + return false; +} + +void wxGCDC::DoDrawLine( wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2 ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLine - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + m_graphicContext->StrokeLine(x1,y1,x2,y2); + + CalcBoundingBox(x1, y1); + CalcBoundingBox(x2, y2); +} + +void wxGCDC::DoCrossHair( wxCoord x, wxCoord y ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoCrossHair - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + int w = 0, h = 0; + + GetSize( &w, &h ); + + m_graphicContext->StrokeLine(0,y,w,y); + m_graphicContext->StrokeLine(x,0,x,h); + + CalcBoundingBox(0, 0); + CalcBoundingBox(0+w, 0+h); +} + +void wxGCDC::DoDrawArc( wxCoord x1, wxCoord y1, + wxCoord x2, wxCoord y2, + wxCoord xc, wxCoord yc ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawArc - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + double dx = x1 - xc; + double dy = y1 - yc; + double radius = sqrt((double)(dx * dx + dy * dy)); + wxCoord rad = (wxCoord)radius; + double sa, ea; + if (x1 == x2 && y1 == y2) + { + sa = 0.0; + ea = 360.0; + } + else if (radius == 0.0) + { + sa = ea = 0.0; + } + else + { + sa = (x1 - xc == 0) ? + (y1 - yc < 0) ? 90.0 : -90.0 : + -atan2(double(y1 - yc), double(x1 - xc)) * RAD2DEG; + ea = (x2 - xc == 0) ? + (y2 - yc < 0) ? 90.0 : -90.0 : + -atan2(double(y2 - yc), double(x2 - xc)) * RAD2DEG; + } + + bool fill = m_brush.GetStyle() != wxTRANSPARENT; + + wxGraphicsPath path = m_graphicContext->CreatePath(); + if ( fill && ((x1!=x2)||(y1!=y2)) ) + path.MoveToPoint( xc, yc ); + // since these angles (ea,sa) are measured counter-clockwise, we invert them to + // get clockwise angles + path.AddArc( xc, yc , rad , DegToRad(-sa) , DegToRad(-ea), false ); + if ( fill && ((x1!=x2)||(y1!=y2)) ) + path.AddLineToPoint( xc, yc ); + m_graphicContext->DrawPath(path); +} + +void wxGCDC::DoDrawEllipticArc( wxCoord x, wxCoord y, wxCoord w, wxCoord h, + double sa, double ea ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipticArc - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + m_graphicContext->PushState(); + m_graphicContext->Translate(x+w/2.0,y+h/2.0); + wxDouble factor = ((wxDouble) w) / h; + m_graphicContext->Scale( factor , 1.0); + + // since these angles (ea,sa) are measured counter-clockwise, we invert them to + // get clockwise angles + if ( m_brush.GetStyle() != wxTRANSPARENT ) + { + wxGraphicsPath path = m_graphicContext->CreatePath(); + path.MoveToPoint( 0, 0 ); + path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); + path.AddLineToPoint( 0, 0 ); + m_graphicContext->FillPath( path ); + + path = m_graphicContext->CreatePath(); + path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); + m_graphicContext->StrokePath( path ); + } + else + { + wxGraphicsPath path = m_graphicContext->CreatePath(); + path.AddArc( 0, 0, h/2.0 , DegToRad(-sa) , DegToRad(-ea), sa > ea ); + m_graphicContext->DrawPath( path ); + } + + m_graphicContext->PopState(); +} + +void wxGCDC::DoDrawPoint( wxCoord x, wxCoord y ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawPoint - invalid DC") ); + + DoDrawLine( x , y , x + 1 , y + 1 ); +} + +void wxGCDC::DoDrawLines(int n, wxPoint points[], + wxCoord xoffset, wxCoord yoffset) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawLines - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + wxPoint2DDouble* pointsD = new wxPoint2DDouble[n]; + for( int i = 0; i < n; ++i) + { + pointsD[i].m_x = points[i].x + xoffset; + pointsD[i].m_y = points[i].y + yoffset; + } + + m_graphicContext->StrokeLines( n , pointsD); + delete[] pointsD; +} + +#if wxUSE_SPLINES +void wxGCDC::DoDrawSpline(wxList *points) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawSpline - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + wxGraphicsPath path = m_graphicContext->CreatePath(); + + wxList::compatibility_iterator node = points->GetFirst(); + if (node == wxList::compatibility_iterator()) + // empty list + return; + + wxPoint *p = (wxPoint *)node->GetData(); + + wxCoord x1 = p->x; + wxCoord y1 = p->y; + + node = node->GetNext(); + p = (wxPoint *)node->GetData(); + + wxCoord x2 = p->x; + wxCoord y2 = p->y; + wxCoord cx1 = ( x1 + x2 ) / 2; + wxCoord cy1 = ( y1 + y2 ) / 2; + + path.MoveToPoint( x1 , y1 ); + path.AddLineToPoint( cx1 , cy1 ); +#if !wxUSE_STL + + while ((node = node->GetNext()) != NULL) +#else + + while ((node = node->GetNext())) +#endif // !wxUSE_STL + + { + p = (wxPoint *)node->GetData(); + x1 = x2; + y1 = y2; + x2 = p->x; + y2 = p->y; + wxCoord cx4 = (x1 + x2) / 2; + wxCoord cy4 = (y1 + y2) / 2; + + path.AddQuadCurveToPoint(x1 , y1 ,cx4 , cy4 ); + + cx1 = cx4; + cy1 = cy4; + } + + path.AddLineToPoint( x2 , y2 ); + + m_graphicContext->StrokePath( path ); +} +#endif // wxUSE_SPLINES + +void wxGCDC::DoDrawPolygon( int n, wxPoint points[], + wxCoord xoffset, wxCoord yoffset, + int fillStyle ) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawPolygon - invalid DC") ); + + if ( n <= 0 || (m_brush.GetStyle() == wxTRANSPARENT && m_pen.GetStyle() == wxTRANSPARENT ) ) + return; + if ( !m_logicalFunctionSupported ) + return; + + bool closeIt = false; + if (points[n-1] != points[0]) + closeIt = true; + + wxPoint2DDouble* pointsD = new wxPoint2DDouble[n+(closeIt?1:0)]; + for( int i = 0; i < n; ++i) + { + pointsD[i].m_x = points[i].x + xoffset; + pointsD[i].m_y = points[i].y + yoffset; + } + if ( closeIt ) + pointsD[n] = pointsD[0]; + + m_graphicContext->DrawLines( n+(closeIt?1:0) , pointsD, fillStyle); + delete[] pointsD; +} + +void wxGCDC::DoDrawPolyPolygon(int n, + int count[], + wxPoint points[], + wxCoord xoffset, + wxCoord yoffset, + int fillStyle) +{ + wxASSERT(n > 1); + wxGraphicsPath path = m_graphicContext->CreatePath(); + + int i = 0; + for ( int j = 0; j < n; ++j) + { + wxPoint start = points[i]; + path.MoveToPoint( start.x+ xoffset, start.y+ yoffset); + ++i; + int l = count[j]; + for ( int k = 1; k < l; ++k) + { + path.AddLineToPoint( points[i].x+ xoffset, points[i].y+ yoffset); + ++i; + } + // close the polygon + if ( start != points[i-1]) + path.AddLineToPoint( start.x+ xoffset, start.y+ yoffset); + } + m_graphicContext->DrawPath( path , fillStyle); +} + +void wxGCDC::DoDrawRectangle(wxCoord x, wxCoord y, wxCoord w, wxCoord h) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRectangle - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + // CMB: draw nothing if transformed w or h is 0 + if (w == 0 || h == 0) + return; + + if ( m_graphicContext->ShouldOffset() ) + { + // if we are offsetting the entire rectangle is moved 0.5, so the + // border line gets off by 1 + w -= 1; + h -= 1; + } + m_graphicContext->DrawRectangle(x,y,w,h); +} + +void wxGCDC::DoDrawRoundedRectangle(wxCoord x, wxCoord y, + wxCoord w, wxCoord h, + double radius) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRoundedRectangle - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + if (radius < 0.0) + radius = - radius * ((w < h) ? w : h); + + // CMB: draw nothing if transformed w or h is 0 + if (w == 0 || h == 0) + return; + + if ( m_graphicContext->ShouldOffset() ) + { + // if we are offsetting the entire rectangle is moved 0.5, so the + // border line gets off by 1 + w -= 1; + h -= 1; + } + m_graphicContext->DrawRoundedRectangle( x,y,w,h,radius); +} + +void wxGCDC::DoDrawEllipse(wxCoord x, wxCoord y, wxCoord w, wxCoord h) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawEllipse - invalid DC") ); + + if ( !m_logicalFunctionSupported ) + return; + + if ( m_graphicContext->ShouldOffset() ) + { + // if we are offsetting the entire rectangle is moved 0.5, so the + // border line gets off by 1 + w -= 1; + h -= 1; + } + m_graphicContext->DrawEllipse(x,y,w,h); +} + +bool wxGCDC::CanDrawBitmap() const +{ + return true; +} + +bool wxGCDC::DoBlit( + wxCoord xdest, wxCoord ydest, wxCoord width, wxCoord height, + wxDC *source, wxCoord xsrc, wxCoord ysrc, int logical_func , bool WXUNUSED(useMask), + wxCoord xsrcMask, wxCoord ysrcMask ) +{ + wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid DC") ); + wxCHECK_MSG( source->Ok(), false, wxT("wxGCDC(cg)::DoBlit - invalid source DC") ); + + if ( logical_func == wxNO_OP ) + return true; + else if ( !m_graphicContext->SetLogicalFunction( logical_func ) ) + + { + wxFAIL_MSG( wxT("Logical function is not supported by the graphics context.") ); + return false; + } + + if (xsrcMask == -1 && ysrcMask == -1) + { + xsrcMask = xsrc; + ysrcMask = ysrc; + } + + wxRect subrect(source->LogicalToDeviceX(xsrc), + source->LogicalToDeviceY(ysrc), + source->LogicalToDeviceXRel(width), + source->LogicalToDeviceYRel(height)); + + // if needed clip the subrect down to the size of the source DC + wxCoord sw, sh; + source->GetSize(&sw, &sh); + sw = source->LogicalToDeviceXRel(sw); + sh = source->LogicalToDeviceYRel(sh); + if (subrect.x + subrect.width > sw) + subrect.width = sw - subrect.x; + if (subrect.y + subrect.height > sh) + subrect.height = sh - subrect.y; + + wxBitmap blit = source->GetAsBitmap( &subrect ); + + if ( blit.Ok() ) + { + m_graphicContext->DrawBitmap( blit, xdest, ydest, + wxMin(width, blit.GetWidth()), + wxMin(height, blit.GetHeight())); + } + else + { + wxFAIL_MSG( wxT("Cannot Blit. Unable to get contents of DC as bitmap.") ); + return false; + } + + // reset logical function + m_graphicContext->SetLogicalFunction( m_logicalFunction ); + + return true; +} + +void wxGCDC::DoDrawRotatedText(const wxString& str, wxCoord x, wxCoord y, + double angle) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") ); + + if ( str.length() == 0 ) + return; + if ( !m_logicalFunctionSupported ) + return; + + if ( m_backgroundMode == wxTRANSPARENT ) + m_graphicContext->DrawText( str, x ,y , DegToRad(angle )); + else + m_graphicContext->DrawText( str, x ,y , DegToRad(angle ), m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) ); +} + +void wxGCDC::DoDrawText(const wxString& str, wxCoord x, wxCoord y) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoDrawRotatedText - invalid DC") ); + + if ( str.length() == 0 ) + return; + + if ( !m_logicalFunctionSupported ) + return; + + if ( m_backgroundMode == wxTRANSPARENT ) + m_graphicContext->DrawText( str, x ,y); + else + m_graphicContext->DrawText( str, x ,y , m_graphicContext->CreateBrush( wxBrush(m_textBackgroundColour,wxSOLID) ) ); +} + +bool wxGCDC::CanGetTextExtent() const +{ + wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::CanGetTextExtent - invalid DC") ); + + return true; +} + +void wxGCDC::DoGetTextExtent( const wxString &str, wxCoord *width, wxCoord *height, + wxCoord *descent, wxCoord *externalLeading , + wxFont *theFont ) const +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::DoGetTextExtent - invalid DC") ); + + if ( theFont ) + { + m_graphicContext->SetFont( *theFont, m_textForegroundColour ); + } + + wxDouble h , d , e , w; + + m_graphicContext->GetTextExtent( str, &w, &h, &d, &e ); + + if ( height ) + *height = (wxCoord)(h+0.5); + if ( descent ) + *descent = (wxCoord)(d+0.5); + if ( externalLeading ) + *externalLeading = (wxCoord)(e+0.5); + if ( width ) + *width = (wxCoord)(w+0.5); + + if ( theFont ) + { + m_graphicContext->SetFont( m_font, m_textForegroundColour ); + } +} + +bool wxGCDC::DoGetPartialTextExtents(const wxString& text, wxArrayInt& widths) const +{ + wxCHECK_MSG( Ok(), false, wxT("wxGCDC(cg)::DoGetPartialTextExtents - invalid DC") ); + widths.Clear(); + widths.Add(0,text.Length()); + if ( text.IsEmpty() ) + return true; + + wxArrayDouble widthsD; + + m_graphicContext->GetPartialTextExtents( text, widthsD ); + for ( size_t i = 0; i < widths.GetCount(); ++i ) + widths[i] = (wxCoord)(widthsD[i] + 0.5); + + return true; +} + +wxCoord wxGCDC::GetCharWidth(void) const +{ + wxCoord width; + DoGetTextExtent( wxT("g") , &width , NULL , NULL , NULL , NULL ); + + return width; +} + +wxCoord wxGCDC::GetCharHeight(void) const +{ + wxCoord height; + DoGetTextExtent( wxT("g") , NULL , &height , NULL , NULL , NULL ); + + return height; +} + +void wxGCDC::Clear(void) +{ + wxCHECK_RET( Ok(), wxT("wxGCDC(cg)::Clear - invalid DC") ); + // TODO better implementation / incorporate size info into wxGCDC or context + m_graphicContext->SetBrush( m_backgroundBrush ); + wxPen p = *wxTRANSPARENT_PEN; + m_graphicContext->SetPen( p ); + DoDrawRectangle( 0, 0, 32000 , 32000 ); + m_graphicContext->SetPen( m_pen ); + m_graphicContext->SetBrush( m_brush ); +} + +void wxGCDC::DoGetSize(int *width, int *height) const +{ + *width = 10000; + *height = 10000; +} + +void wxGCDC::DoGradientFillLinear(const wxRect& rect, + const wxColour& initialColour, + const wxColour& destColour, + wxDirection nDirection ) +{ + wxPoint start; + wxPoint end; + switch( nDirection) + { + case wxWEST : + start = rect.GetRightBottom(); + start.x++; + end = rect.GetLeftBottom(); + break; + case wxEAST : + start = rect.GetLeftBottom(); + end = rect.GetRightBottom(); + end.x++; + break; + case wxNORTH : + start = rect.GetLeftBottom(); + start.y++; + end = rect.GetLeftTop(); + break; + case wxSOUTH : + start = rect.GetLeftTop(); + end = rect.GetLeftBottom(); + end.y++; + break; + default : + break; + } + + if (rect.width == 0 || rect.height == 0) + return; + + m_graphicContext->SetBrush( m_graphicContext->CreateLinearGradientBrush( + start.x,start.y,end.x,end.y, initialColour, destColour)); + m_graphicContext->SetPen(*wxTRANSPARENT_PEN); + m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); + m_graphicContext->SetPen(m_pen); +} + +void wxGCDC::DoGradientFillConcentric(const wxRect& rect, + const wxColour& initialColour, + const wxColour& destColour, + const wxPoint& circleCenter) +{ + //Radius + wxInt32 cx = rect.GetWidth() / 2; + wxInt32 cy = rect.GetHeight() / 2; + wxInt32 nRadius; + if (cx < cy) + nRadius = cx; + else + nRadius = cy; + + // make sure the background is filled (todo move into specific platform implementation ?) + m_graphicContext->SetPen(*wxTRANSPARENT_PEN); + m_graphicContext->SetBrush( wxBrush( destColour) ); + m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); + + m_graphicContext->SetBrush( m_graphicContext->CreateRadialGradientBrush( + rect.x+circleCenter.x,rect.y+circleCenter.y, + rect.x+circleCenter.x,rect.y+circleCenter.y, + nRadius,initialColour,destColour)); + + m_graphicContext->DrawRectangle(rect.x,rect.y,rect.width,rect.height); + m_graphicContext->SetPen(m_pen); +} + +void wxGCDC::DoDrawCheckMark(wxCoord x, wxCoord y, + wxCoord width, wxCoord height) +{ + wxDCBase::DoDrawCheckMark(x,y,width,height); +} + +#endif // wxUSE_GRAPHICS_CONTEXT diff --git a/Source/3rd Party/wx/src/common/dircmn.cpp b/Source/3rd Party/wx/src/common/dircmn.cpp index 2e2b24a34..3e79a7a4e 100644 --- a/Source/3rd Party/wx/src/common/dircmn.cpp +++ b/Source/3rd Party/wx/src/common/dircmn.cpp @@ -1,357 +1,357 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/dircmn.cpp -// Purpose: wxDir methods common to all implementations -// Author: Vadim Zeitlin -// Modified by: -// Created: 19.05.01 -// RCS-ID: $Id: dircmn.cpp 40665 2006-08-19 08:45:31Z JS $ -// Copyright: (c) 2001 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/filefn.h" - #include "wx/arrstr.h" -#endif //WX_PRECOMP - -#include "wx/dir.h" -#include "wx/filename.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxDirTraverser -// ---------------------------------------------------------------------------- - -wxDirTraverseResult -wxDirTraverser::OnOpenError(const wxString& WXUNUSED(dirname)) -{ - return wxDIR_IGNORE; -} - -// ---------------------------------------------------------------------------- -// wxDir::HasFiles() and HasSubDirs() -// ---------------------------------------------------------------------------- - -// dumb generic implementation - -bool wxDir::HasFiles(const wxString& spec) -{ - wxString s; - return GetFirst(&s, spec, wxDIR_FILES | wxDIR_HIDDEN); -} - -// we have a (much) faster version for Unix -#if (defined(__CYGWIN__) && defined(__WINDOWS__)) || !defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__EMX__) || defined(__WINE__) - -bool wxDir::HasSubDirs(const wxString& spec) -{ - wxString s; - return GetFirst(&s, spec, wxDIR_DIRS | wxDIR_HIDDEN); -} - -#endif // !Unix - -// ---------------------------------------------------------------------------- -// wxDir::Traverse() -// ---------------------------------------------------------------------------- - -size_t wxDir::Traverse(wxDirTraverser& sink, - const wxString& filespec, - int flags) const -{ - wxCHECK_MSG( IsOpened(), (size_t)-1, - _T("dir must be opened before traversing it") ); - - // the total number of files found - size_t nFiles = 0; - - // the name of this dir with path delimiter at the end - wxString prefix = GetName(); - prefix += wxFILE_SEP_PATH; - - // first, recurse into subdirs - if ( flags & wxDIR_DIRS ) - { - wxString dirname; - for ( bool cont = GetFirst(&dirname, wxEmptyString, wxDIR_DIRS | (flags & wxDIR_HIDDEN) ); - cont; - cont = cont && GetNext(&dirname) ) - { - const wxString fulldirname = prefix + dirname; - - switch ( sink.OnDir(fulldirname) ) - { - default: - wxFAIL_MSG(_T("unexpected OnDir() return value") ); - // fall through - - case wxDIR_STOP: - cont = false; - break; - - case wxDIR_CONTINUE: - { - wxDir subdir; - - // don't give the error messages for the directories - // which we can't open: there can be all sorts of good - // reason for this (e.g. insufficient privileges) and - // this shouldn't be treated as an error -- instead - // let the user code decide what to do - bool ok; - do - { - wxLogNull noLog; - ok = subdir.Open(fulldirname); - if ( !ok ) - { - // ask the user code what to do - bool tryagain; - switch ( sink.OnOpenError(fulldirname) ) - { - default: - wxFAIL_MSG(_T("unexpected OnOpenError() return value") ); - // fall through - - case wxDIR_STOP: - cont = false; - // fall through - - case wxDIR_IGNORE: - tryagain = false; - break; - - case wxDIR_CONTINUE: - tryagain = true; - } - - if ( !tryagain ) - break; - } - } - while ( !ok ); - - if ( ok ) - { - nFiles += subdir.Traverse(sink, filespec, flags); - } - } - break; - - case wxDIR_IGNORE: - // nothing to do - ; - } - } - } - - // now enum our own files - if ( flags & wxDIR_FILES ) - { - flags &= ~wxDIR_DIRS; - - wxString filename; - bool cont = GetFirst(&filename, filespec, flags); - while ( cont ) - { - wxDirTraverseResult res = sink.OnFile(prefix + filename); - if ( res == wxDIR_STOP ) - break; - - wxASSERT_MSG( res == wxDIR_CONTINUE, - _T("unexpected OnFile() return value") ); - - nFiles++; - - cont = GetNext(&filename); - } - } - - return nFiles; -} - -// ---------------------------------------------------------------------------- -// wxDir::GetAllFiles() -// ---------------------------------------------------------------------------- - -class wxDirTraverserSimple : public wxDirTraverser -{ -public: - wxDirTraverserSimple(wxArrayString& files) : m_files(files) { } - - virtual wxDirTraverseResult OnFile(const wxString& filename) - { - m_files.push_back(filename); - return wxDIR_CONTINUE; - } - - virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) - { - return wxDIR_CONTINUE; - } - -private: - wxArrayString& m_files; - - DECLARE_NO_COPY_CLASS(wxDirTraverserSimple) -}; - -/* static */ -size_t wxDir::GetAllFiles(const wxString& dirname, - wxArrayString *files, - const wxString& filespec, - int flags) -{ - wxCHECK_MSG( files, (size_t)-1, _T("NULL pointer in wxDir::GetAllFiles") ); - - size_t nFiles = 0; - - wxDir dir(dirname); - if ( dir.IsOpened() ) - { - wxDirTraverserSimple traverser(*files); - - nFiles += dir.Traverse(traverser, filespec, flags); - } - - return nFiles; -} - -// ---------------------------------------------------------------------------- -// wxDir::FindFirst() -// ---------------------------------------------------------------------------- - -class wxDirTraverserFindFirst : public wxDirTraverser -{ -public: - wxDirTraverserFindFirst() { } - - virtual wxDirTraverseResult OnFile(const wxString& filename) - { - m_file = filename; - return wxDIR_STOP; - } - - virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) - { - return wxDIR_CONTINUE; - } - - const wxString& GetFile() const - { - return m_file; - } - -private: - wxString m_file; - - DECLARE_NO_COPY_CLASS(wxDirTraverserFindFirst) -}; - -/* static */ -wxString wxDir::FindFirst(const wxString& dirname, - const wxString& filespec, - int flags) -{ - wxDir dir(dirname); - if ( dir.IsOpened() ) - { - wxDirTraverserFindFirst traverser; - - dir.Traverse(traverser, filespec, flags | wxDIR_FILES); - return traverser.GetFile(); - } - - return wxEmptyString; -} - - -// ---------------------------------------------------------------------------- -// wxDir::GetTotalSize() -// ---------------------------------------------------------------------------- - -class wxDirTraverserSumSize : public wxDirTraverser -{ -public: - wxDirTraverserSumSize() { } - - virtual wxDirTraverseResult OnFile(const wxString& filename) - { - wxULongLong sz = wxFileName::GetSize(filename); - - // wxFileName::GetSize won't use this class again as - // we're passing it a file and not a directory; - // thus we are sure to avoid an endless loop - if (sz == wxInvalidSize) - { - // if the GetSize() failed (this can happen because e.g. a - // file is locked by another process), we can proceed but - // we need to at least warn the user that the resulting - // final size could be not reliable (if e.g. the locked - // file is very big). - m_skippedFiles.Add(filename); - return wxDIR_CONTINUE; - } - - m_sz += sz; - return wxDIR_CONTINUE; - } - - virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) - { - return wxDIR_CONTINUE; - } - - wxULongLong GetTotalSize() const - { return m_sz; } - wxArrayString &FilesSkipped() - { return m_skippedFiles; } - -protected: - wxULongLong m_sz; - wxArrayString m_skippedFiles; -}; - -wxULongLong wxDir::GetTotalSize(const wxString &dirname, wxArrayString *filesSkipped) -{ - if (!wxDirExists(dirname)) - return wxInvalidSize; - - // to get the size of this directory and its contents we need - // to recursively walk it... - wxDir dir(dirname); - if ( !dir.IsOpened() ) - return wxInvalidSize; - - wxDirTraverserSumSize traverser; - if (dir.Traverse(traverser) == (size_t)-1 || - traverser.GetTotalSize() == 0) - return wxInvalidSize; - - if (filesSkipped) - *filesSkipped = traverser.FilesSkipped(); - - return traverser.GetTotalSize(); -} - +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/dircmn.cpp +// Purpose: wxDir methods common to all implementations +// Author: Vadim Zeitlin +// Modified by: +// Created: 19.05.01 +// RCS-ID: $Id: dircmn.cpp 40665 2006-08-19 08:45:31Z JS $ +// Copyright: (c) 2001 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/filefn.h" + #include "wx/arrstr.h" +#endif //WX_PRECOMP + +#include "wx/dir.h" +#include "wx/filename.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxDirTraverser +// ---------------------------------------------------------------------------- + +wxDirTraverseResult +wxDirTraverser::OnOpenError(const wxString& WXUNUSED(dirname)) +{ + return wxDIR_IGNORE; +} + +// ---------------------------------------------------------------------------- +// wxDir::HasFiles() and HasSubDirs() +// ---------------------------------------------------------------------------- + +// dumb generic implementation + +bool wxDir::HasFiles(const wxString& spec) +{ + wxString s; + return GetFirst(&s, spec, wxDIR_FILES | wxDIR_HIDDEN); +} + +// we have a (much) faster version for Unix +#if (defined(__CYGWIN__) && defined(__WINDOWS__)) || !defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__EMX__) || defined(__WINE__) + +bool wxDir::HasSubDirs(const wxString& spec) +{ + wxString s; + return GetFirst(&s, spec, wxDIR_DIRS | wxDIR_HIDDEN); +} + +#endif // !Unix + +// ---------------------------------------------------------------------------- +// wxDir::Traverse() +// ---------------------------------------------------------------------------- + +size_t wxDir::Traverse(wxDirTraverser& sink, + const wxString& filespec, + int flags) const +{ + wxCHECK_MSG( IsOpened(), (size_t)-1, + _T("dir must be opened before traversing it") ); + + // the total number of files found + size_t nFiles = 0; + + // the name of this dir with path delimiter at the end + wxString prefix = GetName(); + prefix += wxFILE_SEP_PATH; + + // first, recurse into subdirs + if ( flags & wxDIR_DIRS ) + { + wxString dirname; + for ( bool cont = GetFirst(&dirname, wxEmptyString, wxDIR_DIRS | (flags & wxDIR_HIDDEN) ); + cont; + cont = cont && GetNext(&dirname) ) + { + const wxString fulldirname = prefix + dirname; + + switch ( sink.OnDir(fulldirname) ) + { + default: + wxFAIL_MSG(_T("unexpected OnDir() return value") ); + // fall through + + case wxDIR_STOP: + cont = false; + break; + + case wxDIR_CONTINUE: + { + wxDir subdir; + + // don't give the error messages for the directories + // which we can't open: there can be all sorts of good + // reason for this (e.g. insufficient privileges) and + // this shouldn't be treated as an error -- instead + // let the user code decide what to do + bool ok; + do + { + wxLogNull noLog; + ok = subdir.Open(fulldirname); + if ( !ok ) + { + // ask the user code what to do + bool tryagain; + switch ( sink.OnOpenError(fulldirname) ) + { + default: + wxFAIL_MSG(_T("unexpected OnOpenError() return value") ); + // fall through + + case wxDIR_STOP: + cont = false; + // fall through + + case wxDIR_IGNORE: + tryagain = false; + break; + + case wxDIR_CONTINUE: + tryagain = true; + } + + if ( !tryagain ) + break; + } + } + while ( !ok ); + + if ( ok ) + { + nFiles += subdir.Traverse(sink, filespec, flags); + } + } + break; + + case wxDIR_IGNORE: + // nothing to do + ; + } + } + } + + // now enum our own files + if ( flags & wxDIR_FILES ) + { + flags &= ~wxDIR_DIRS; + + wxString filename; + bool cont = GetFirst(&filename, filespec, flags); + while ( cont ) + { + wxDirTraverseResult res = sink.OnFile(prefix + filename); + if ( res == wxDIR_STOP ) + break; + + wxASSERT_MSG( res == wxDIR_CONTINUE, + _T("unexpected OnFile() return value") ); + + nFiles++; + + cont = GetNext(&filename); + } + } + + return nFiles; +} + +// ---------------------------------------------------------------------------- +// wxDir::GetAllFiles() +// ---------------------------------------------------------------------------- + +class wxDirTraverserSimple : public wxDirTraverser +{ +public: + wxDirTraverserSimple(wxArrayString& files) : m_files(files) { } + + virtual wxDirTraverseResult OnFile(const wxString& filename) + { + m_files.push_back(filename); + return wxDIR_CONTINUE; + } + + virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) + { + return wxDIR_CONTINUE; + } + +private: + wxArrayString& m_files; + + DECLARE_NO_COPY_CLASS(wxDirTraverserSimple) +}; + +/* static */ +size_t wxDir::GetAllFiles(const wxString& dirname, + wxArrayString *files, + const wxString& filespec, + int flags) +{ + wxCHECK_MSG( files, (size_t)-1, _T("NULL pointer in wxDir::GetAllFiles") ); + + size_t nFiles = 0; + + wxDir dir(dirname); + if ( dir.IsOpened() ) + { + wxDirTraverserSimple traverser(*files); + + nFiles += dir.Traverse(traverser, filespec, flags); + } + + return nFiles; +} + +// ---------------------------------------------------------------------------- +// wxDir::FindFirst() +// ---------------------------------------------------------------------------- + +class wxDirTraverserFindFirst : public wxDirTraverser +{ +public: + wxDirTraverserFindFirst() { } + + virtual wxDirTraverseResult OnFile(const wxString& filename) + { + m_file = filename; + return wxDIR_STOP; + } + + virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) + { + return wxDIR_CONTINUE; + } + + const wxString& GetFile() const + { + return m_file; + } + +private: + wxString m_file; + + DECLARE_NO_COPY_CLASS(wxDirTraverserFindFirst) +}; + +/* static */ +wxString wxDir::FindFirst(const wxString& dirname, + const wxString& filespec, + int flags) +{ + wxDir dir(dirname); + if ( dir.IsOpened() ) + { + wxDirTraverserFindFirst traverser; + + dir.Traverse(traverser, filespec, flags | wxDIR_FILES); + return traverser.GetFile(); + } + + return wxEmptyString; +} + + +// ---------------------------------------------------------------------------- +// wxDir::GetTotalSize() +// ---------------------------------------------------------------------------- + +class wxDirTraverserSumSize : public wxDirTraverser +{ +public: + wxDirTraverserSumSize() { } + + virtual wxDirTraverseResult OnFile(const wxString& filename) + { + wxULongLong sz = wxFileName::GetSize(filename); + + // wxFileName::GetSize won't use this class again as + // we're passing it a file and not a directory; + // thus we are sure to avoid an endless loop + if (sz == wxInvalidSize) + { + // if the GetSize() failed (this can happen because e.g. a + // file is locked by another process), we can proceed but + // we need to at least warn the user that the resulting + // final size could be not reliable (if e.g. the locked + // file is very big). + m_skippedFiles.Add(filename); + return wxDIR_CONTINUE; + } + + m_sz += sz; + return wxDIR_CONTINUE; + } + + virtual wxDirTraverseResult OnDir(const wxString& WXUNUSED(dirname)) + { + return wxDIR_CONTINUE; + } + + wxULongLong GetTotalSize() const + { return m_sz; } + wxArrayString &FilesSkipped() + { return m_skippedFiles; } + +protected: + wxULongLong m_sz; + wxArrayString m_skippedFiles; +}; + +wxULongLong wxDir::GetTotalSize(const wxString &dirname, wxArrayString *filesSkipped) +{ + if (!wxDirExists(dirname)) + return wxInvalidSize; + + // to get the size of this directory and its contents we need + // to recursively walk it... + wxDir dir(dirname); + if ( !dir.IsOpened() ) + return wxInvalidSize; + + wxDirTraverserSumSize traverser; + if (dir.Traverse(traverser) == (size_t)-1 || + traverser.GetTotalSize() == 0) + return wxInvalidSize; + + if (filesSkipped) + *filesSkipped = traverser.FilesSkipped(); + + return traverser.GetTotalSize(); +} + diff --git a/Source/3rd Party/wx/src/common/dlgcmn.cpp b/Source/3rd Party/wx/src/common/dlgcmn.cpp index f119b8601..597b14e2c 100644 --- a/Source/3rd Party/wx/src/common/dlgcmn.cpp +++ b/Source/3rd Party/wx/src/common/dlgcmn.cpp @@ -1,565 +1,565 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/dlgcmn.cpp -// Purpose: common (to all ports) wxDialog functions -// Author: Vadim Zeitlin -// Modified by: -// Created: 28.06.99 -// RCS-ID: $Id: dlgcmn.cpp 49747 2007-11-09 15:06:52Z JS $ -// Copyright: (c) Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/dialog.h" - -#ifndef WX_PRECOMP - #include "wx/button.h" - #include "wx/dcclient.h" - #include "wx/intl.h" - #include "wx/settings.h" - #include "wx/stattext.h" - #include "wx/sizer.h" - #include "wx/containr.h" -#endif - -#include "wx/statline.h" -#include "wx/sysopt.h" - -#if wxUSE_STATTEXT - -// ---------------------------------------------------------------------------- -// wxTextWrapper -// ---------------------------------------------------------------------------- - -// this class is used to wrap the text on word boundary: wrapping is done by -// calling OnStartLine() and OnOutputLine() functions -class wxTextWrapper -{ -public: - wxTextWrapper() { m_eol = false; } - - // win is used for getting the font, text is the text to wrap, width is the - // max line width or -1 to disable wrapping - void Wrap(wxWindow *win, const wxString& text, int widthMax); - - // we don't need it, but just to avoid compiler warnings - virtual ~wxTextWrapper() { } - -protected: - // line may be empty - virtual void OnOutputLine(const wxString& line) = 0; - - // called at the start of every new line (except the very first one) - virtual void OnNewLine() { } - -private: - // call OnOutputLine() and set m_eol to true - void DoOutputLine(const wxString& line) - { - OnOutputLine(line); - - m_eol = true; - } - - // this function is a destructive inspector: when it returns true it also - // resets the flag to false so calling it again woulnd't return true any - // more - bool IsStartOfNewLine() - { - if ( !m_eol ) - return false; - - m_eol = false; - - return true; - } - - - bool m_eol; -}; - -#endif // wxUSE_STATTEXT - -// ---------------------------------------------------------------------------- -// wxDialogBase -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxDialogBase, wxTopLevelWindow) - EVT_BUTTON(wxID_ANY, wxDialogBase::OnButton) - - EVT_CLOSE(wxDialogBase::OnCloseWindow) - - EVT_CHAR_HOOK(wxDialogBase::OnCharHook) - - WX_EVENT_TABLE_CONTROL_CONTAINER(wxDialogBase) -END_EVENT_TABLE() - -WX_DELEGATE_TO_CONTROL_CONTAINER(wxDialogBase, wxTopLevelWindow) - -void wxDialogBase::Init() -{ - m_returnCode = 0; - m_affirmativeId = wxID_OK; - m_escapeId = wxID_ANY; - - // the dialogs have this flag on by default to prevent the events from the - // dialog controls from reaching the parent frame which is usually - // undesirable and can lead to unexpected and hard to find bugs - SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS); - - m_container.SetContainerWindow(this); -} - -#if wxUSE_STATTEXT - -void wxTextWrapper::Wrap(wxWindow *win, const wxString& text, int widthMax) -{ - const wxChar *lastSpace = NULL; - wxString line; - - const wxChar *lineStart = text.c_str(); - for ( const wxChar *p = lineStart; ; p++ ) - { - if ( IsStartOfNewLine() ) - { - OnNewLine(); - - lastSpace = NULL; - line.clear(); - lineStart = p; - } - - if ( *p == _T('\n') || *p == _T('\0') ) - { - DoOutputLine(line); - - if ( *p == _T('\0') ) - break; - } - else // not EOL - { - if ( *p == _T(' ') ) - lastSpace = p; - - line += *p; - - if ( widthMax >= 0 && lastSpace ) - { - int width; - win->GetTextExtent(line, &width, NULL); - - if ( width > widthMax ) - { - // remove the last word from this line - line.erase(lastSpace - lineStart, p + 1 - lineStart); - DoOutputLine(line); - - // go back to the last word of this line which we didn't - // output yet - p = lastSpace; - } - } - //else: no wrapping at all or impossible to wrap - } - } -} - -class wxTextSizerWrapper : public wxTextWrapper -{ -public: - wxTextSizerWrapper(wxWindow *win) - { - m_win = win; - m_hLine = 0; - } - - wxSizer *CreateSizer(const wxString& text, int widthMax) - { - m_sizer = new wxBoxSizer(wxVERTICAL); - Wrap(m_win, text, widthMax); - return m_sizer; - } - -protected: - virtual void OnOutputLine(const wxString& line) - { - if ( !line.empty() ) - { - m_sizer->Add(new wxStaticText(m_win, wxID_ANY, line)); - } - else // empty line, no need to create a control for it - { - if ( !m_hLine ) - m_hLine = m_win->GetCharHeight(); - - m_sizer->Add(5, m_hLine); - } - } - -private: - wxWindow *m_win; - wxSizer *m_sizer; - int m_hLine; -}; - -wxSizer *wxDialogBase::CreateTextSizer(const wxString& message) -{ - // I admit that this is complete bogus, but it makes - // message boxes work for pda screens temporarily.. - int widthMax = -1; - const bool is_pda = wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA; - if (is_pda) - { - widthMax = wxSystemSettings::GetMetric( wxSYS_SCREEN_X ) - 25; - } - - // '&' is used as accel mnemonic prefix in the wxWidgets controls but in - // the static messages created by CreateTextSizer() (used by wxMessageBox, - // for example), we don't want this special meaning, so we need to quote it - wxString text(message); - text.Replace(_T("&"), _T("&&")); - - wxTextSizerWrapper wrapper(this); - - return wrapper.CreateSizer(text, widthMax); -} - -class wxLabelWrapper : public wxTextWrapper -{ -public: - void WrapLabel(wxWindow *text, int widthMax) - { - m_text.clear(); - Wrap(text, text->GetLabel(), widthMax); - text->SetLabel(m_text); - } - -protected: - virtual void OnOutputLine(const wxString& line) - { - m_text += line; - } - - virtual void OnNewLine() - { - m_text += _T('\n'); - } - -private: - wxString m_text; -}; - -// NB: don't "factor out" the scope operator, SGI MIPSpro 7.3 (but not 7.4) -// gets confused if it doesn't immediately follow the class name -void -#if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) -wxStaticText:: -#else -wxStaticTextBase:: -#endif -Wrap(int width) -{ - wxLabelWrapper wrapper; - wrapper.WrapLabel(this, width); -} - -#endif // wxUSE_STATTEXT - -wxSizer *wxDialogBase::CreateButtonSizer(long flags) -{ - wxSizer *sizer = NULL; - -#ifdef __SMARTPHONE__ - wxDialog* dialog = (wxDialog*) this; - if ( flags & wxOK ) - dialog->SetLeftMenu(wxID_OK); - - if ( flags & wxCANCEL ) - dialog->SetRightMenu(wxID_CANCEL); - - if ( flags & wxYES ) - dialog->SetLeftMenu(wxID_YES); - - if ( flags & wxNO ) - dialog->SetRightMenu(wxID_NO); -#else // !__SMARTPHONE__ - -#if wxUSE_BUTTON - -#ifdef __POCKETPC__ - // PocketPC guidelines recommend for Ok/Cancel dialogs to use OK button - // located inside caption bar and implement Cancel functionality through - // Undo outside dialog. As native behaviour this will be default here but - // can be replaced with real wxButtons by setting the option below to 1 - if ( (flags & ~(wxCANCEL|wxNO_DEFAULT)) != wxOK || - wxSystemOptions::GetOptionInt(wxT("wince.dialog.real-ok-cancel")) ) -#endif // __POCKETPC__ - { - sizer = CreateStdDialogButtonSizer(flags); - } -#endif // wxUSE_BUTTON - -#endif // __SMARTPHONE__/!__SMARTPHONE__ - - return sizer; -} - -wxSizer *wxDialogBase::CreateSeparatedButtonSizer(long flags) -{ - wxSizer *sizer = CreateButtonSizer(flags); - if ( !sizer ) - return NULL; - - // Mac Human Interface Guidelines recommend not to use static lines as - // grouping elements -#if wxUSE_STATLINE && !defined(__WXMAC__) - wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL); - topsizer->Add(new wxStaticLine(this), - wxSizerFlags().Expand().DoubleBorder(wxBOTTOM)); - topsizer->Add(sizer, wxSizerFlags().Expand()); - sizer = topsizer; -#endif // wxUSE_STATLINE - - return sizer; -} - -#if wxUSE_BUTTON - -wxStdDialogButtonSizer *wxDialogBase::CreateStdDialogButtonSizer( long flags ) -{ - wxStdDialogButtonSizer *sizer = new wxStdDialogButtonSizer(); - - wxButton *ok = NULL; - wxButton *yes = NULL; - wxButton *no = NULL; - - if (flags & wxOK) - { - ok = new wxButton(this, wxID_OK); - sizer->AddButton(ok); - } - - if (flags & wxCANCEL) - { - wxButton *cancel = new wxButton(this, wxID_CANCEL); - sizer->AddButton(cancel); - } - - if (flags & wxYES) - { - yes = new wxButton(this, wxID_YES); - sizer->AddButton(yes); - } - - if (flags & wxNO) - { - no = new wxButton(this, wxID_NO); - sizer->AddButton(no); - } - - if (flags & wxHELP) - { - wxButton *help = new wxButton(this, wxID_HELP); - sizer->AddButton(help); - } - - if (flags & wxNO_DEFAULT) - { - if (no) - { - no->SetDefault(); - no->SetFocus(); - } - } - else - { - if (ok) - { - ok->SetDefault(); - ok->SetFocus(); - } - else if (yes) - { - yes->SetDefault(); - yes->SetFocus(); - } - } - - if (flags & wxOK) - SetAffirmativeId(wxID_OK); - else if (flags & wxYES) - SetAffirmativeId(wxID_YES); - - sizer->Realize(); - - return sizer; -} - -#endif // wxUSE_BUTTON - -// ---------------------------------------------------------------------------- -// standard buttons handling -// ---------------------------------------------------------------------------- - -void wxDialogBase::EndDialog(int rc) -{ - if ( IsModal() ) - EndModal(rc); - else - Hide(); -} - -void wxDialogBase::AcceptAndClose() -{ - if ( Validate() && TransferDataFromWindow() ) - { - EndDialog(m_affirmativeId); - } -} - -void wxDialogBase::SetAffirmativeId(int affirmativeId) -{ - m_affirmativeId = affirmativeId; -} - -void wxDialogBase::SetEscapeId(int escapeId) -{ - m_escapeId = escapeId; -} - -bool wxDialogBase::EmulateButtonClickIfPresent(int id) -{ -#if wxUSE_BUTTON - wxButton *btn = wxDynamicCast(FindWindow(id), wxButton); - - if ( !btn || !btn->IsEnabled() || !btn->IsShown() ) - return false; - - wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, id); - event.SetEventObject(btn); - btn->GetEventHandler()->ProcessEvent(event); - - return true; -#else // !wxUSE_BUTTON - wxUnusedVar(id); - return false; -#endif // wxUSE_BUTTON/!wxUSE_BUTTON -} - -bool wxDialogBase::IsEscapeKey(const wxKeyEvent& event) -{ - // for most platforms, Esc key is used to close the dialogs - return event.GetKeyCode() == WXK_ESCAPE && - event.GetModifiers() == wxMOD_NONE; -} - -void wxDialogBase::OnCharHook(wxKeyEvent& event) -{ - if ( event.GetKeyCode() == WXK_ESCAPE ) - { - int idCancel = GetEscapeId(); - switch ( idCancel ) - { - case wxID_NONE: - // don't handle Esc specially at all - break; - - case wxID_ANY: - // this value is special: it means translate Esc to wxID_CANCEL - // but if there is no such button, then fall back to wxID_OK - if ( EmulateButtonClickIfPresent(wxID_CANCEL) ) - return; - idCancel = GetAffirmativeId(); - // fall through - - default: - // translate Esc to button press for the button with given id - if ( EmulateButtonClickIfPresent(idCancel) ) - return; - } - } - - event.Skip(); -} - -void wxDialogBase::OnButton(wxCommandEvent& event) -{ - const int id = event.GetId(); - if ( id == GetAffirmativeId() ) - { - AcceptAndClose(); - } - else if ( id == wxID_APPLY ) - { - if ( Validate() ) - TransferDataFromWindow(); - - // TODO: disable the Apply button until things change again - } - else if ( id == GetEscapeId() || - (id == wxID_CANCEL && GetEscapeId() == wxID_ANY) ) - { - EndDialog(wxID_CANCEL); - } - else // not a standard button - { - event.Skip(); - } -} - -// ---------------------------------------------------------------------------- -// other event handlers -// ---------------------------------------------------------------------------- - -void wxDialogBase::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) -{ - // We'll send a Cancel message by default, which may close the dialog. - // Check for looping if the Cancel event handler calls Close(). - - // Note that if a cancel button and handler aren't present in the dialog, - // nothing will happen when you close the dialog via the window manager, or - // via Close(). We wouldn't want to destroy the dialog by default, since - // the dialog may have been created on the stack. However, this does mean - // that calling dialog->Close() won't delete the dialog unless the handler - // for wxID_CANCEL does so. So use Destroy() if you want to be sure to - // destroy the dialog. The default OnCancel (above) simply ends a modal - // dialog, and hides a modeless dialog. - - // VZ: this is horrible and MT-unsafe. Can't we reuse some of these global - // lists here? don't dare to change it now, but should be done later! - static wxList closing; - - if ( closing.Member(this) ) - return; - - closing.Append(this); - - wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL); - cancelEvent.SetEventObject( this ); - GetEventHandler()->ProcessEvent(cancelEvent); // This may close the dialog - - closing.DeleteObject(this); -} - -void wxDialogBase::OnSysColourChanged(wxSysColourChangedEvent& event) -{ -#ifndef __WXGTK__ - SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); - Refresh(); -#endif - event.Skip(); -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/dlgcmn.cpp +// Purpose: common (to all ports) wxDialog functions +// Author: Vadim Zeitlin +// Modified by: +// Created: 28.06.99 +// RCS-ID: $Id: dlgcmn.cpp 49747 2007-11-09 15:06:52Z JS $ +// Copyright: (c) Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/dialog.h" + +#ifndef WX_PRECOMP + #include "wx/button.h" + #include "wx/dcclient.h" + #include "wx/intl.h" + #include "wx/settings.h" + #include "wx/stattext.h" + #include "wx/sizer.h" + #include "wx/containr.h" +#endif + +#include "wx/statline.h" +#include "wx/sysopt.h" + +#if wxUSE_STATTEXT + +// ---------------------------------------------------------------------------- +// wxTextWrapper +// ---------------------------------------------------------------------------- + +// this class is used to wrap the text on word boundary: wrapping is done by +// calling OnStartLine() and OnOutputLine() functions +class wxTextWrapper +{ +public: + wxTextWrapper() { m_eol = false; } + + // win is used for getting the font, text is the text to wrap, width is the + // max line width or -1 to disable wrapping + void Wrap(wxWindow *win, const wxString& text, int widthMax); + + // we don't need it, but just to avoid compiler warnings + virtual ~wxTextWrapper() { } + +protected: + // line may be empty + virtual void OnOutputLine(const wxString& line) = 0; + + // called at the start of every new line (except the very first one) + virtual void OnNewLine() { } + +private: + // call OnOutputLine() and set m_eol to true + void DoOutputLine(const wxString& line) + { + OnOutputLine(line); + + m_eol = true; + } + + // this function is a destructive inspector: when it returns true it also + // resets the flag to false so calling it again woulnd't return true any + // more + bool IsStartOfNewLine() + { + if ( !m_eol ) + return false; + + m_eol = false; + + return true; + } + + + bool m_eol; +}; + +#endif // wxUSE_STATTEXT + +// ---------------------------------------------------------------------------- +// wxDialogBase +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxDialogBase, wxTopLevelWindow) + EVT_BUTTON(wxID_ANY, wxDialogBase::OnButton) + + EVT_CLOSE(wxDialogBase::OnCloseWindow) + + EVT_CHAR_HOOK(wxDialogBase::OnCharHook) + + WX_EVENT_TABLE_CONTROL_CONTAINER(wxDialogBase) +END_EVENT_TABLE() + +WX_DELEGATE_TO_CONTROL_CONTAINER(wxDialogBase, wxTopLevelWindow) + +void wxDialogBase::Init() +{ + m_returnCode = 0; + m_affirmativeId = wxID_OK; + m_escapeId = wxID_ANY; + + // the dialogs have this flag on by default to prevent the events from the + // dialog controls from reaching the parent frame which is usually + // undesirable and can lead to unexpected and hard to find bugs + SetExtraStyle(GetExtraStyle() | wxWS_EX_BLOCK_EVENTS); + + m_container.SetContainerWindow(this); +} + +#if wxUSE_STATTEXT + +void wxTextWrapper::Wrap(wxWindow *win, const wxString& text, int widthMax) +{ + const wxChar *lastSpace = NULL; + wxString line; + + const wxChar *lineStart = text.c_str(); + for ( const wxChar *p = lineStart; ; p++ ) + { + if ( IsStartOfNewLine() ) + { + OnNewLine(); + + lastSpace = NULL; + line.clear(); + lineStart = p; + } + + if ( *p == _T('\n') || *p == _T('\0') ) + { + DoOutputLine(line); + + if ( *p == _T('\0') ) + break; + } + else // not EOL + { + if ( *p == _T(' ') ) + lastSpace = p; + + line += *p; + + if ( widthMax >= 0 && lastSpace ) + { + int width; + win->GetTextExtent(line, &width, NULL); + + if ( width > widthMax ) + { + // remove the last word from this line + line.erase(lastSpace - lineStart, p + 1 - lineStart); + DoOutputLine(line); + + // go back to the last word of this line which we didn't + // output yet + p = lastSpace; + } + } + //else: no wrapping at all or impossible to wrap + } + } +} + +class wxTextSizerWrapper : public wxTextWrapper +{ +public: + wxTextSizerWrapper(wxWindow *win) + { + m_win = win; + m_hLine = 0; + } + + wxSizer *CreateSizer(const wxString& text, int widthMax) + { + m_sizer = new wxBoxSizer(wxVERTICAL); + Wrap(m_win, text, widthMax); + return m_sizer; + } + +protected: + virtual void OnOutputLine(const wxString& line) + { + if ( !line.empty() ) + { + m_sizer->Add(new wxStaticText(m_win, wxID_ANY, line)); + } + else // empty line, no need to create a control for it + { + if ( !m_hLine ) + m_hLine = m_win->GetCharHeight(); + + m_sizer->Add(5, m_hLine); + } + } + +private: + wxWindow *m_win; + wxSizer *m_sizer; + int m_hLine; +}; + +wxSizer *wxDialogBase::CreateTextSizer(const wxString& message) +{ + // I admit that this is complete bogus, but it makes + // message boxes work for pda screens temporarily.. + int widthMax = -1; + const bool is_pda = wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA; + if (is_pda) + { + widthMax = wxSystemSettings::GetMetric( wxSYS_SCREEN_X ) - 25; + } + + // '&' is used as accel mnemonic prefix in the wxWidgets controls but in + // the static messages created by CreateTextSizer() (used by wxMessageBox, + // for example), we don't want this special meaning, so we need to quote it + wxString text(message); + text.Replace(_T("&"), _T("&&")); + + wxTextSizerWrapper wrapper(this); + + return wrapper.CreateSizer(text, widthMax); +} + +class wxLabelWrapper : public wxTextWrapper +{ +public: + void WrapLabel(wxWindow *text, int widthMax) + { + m_text.clear(); + Wrap(text, text->GetLabel(), widthMax); + text->SetLabel(m_text); + } + +protected: + virtual void OnOutputLine(const wxString& line) + { + m_text += line; + } + + virtual void OnNewLine() + { + m_text += _T('\n'); + } + +private: + wxString m_text; +}; + +// NB: don't "factor out" the scope operator, SGI MIPSpro 7.3 (but not 7.4) +// gets confused if it doesn't immediately follow the class name +void +#if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) +wxStaticText:: +#else +wxStaticTextBase:: +#endif +Wrap(int width) +{ + wxLabelWrapper wrapper; + wrapper.WrapLabel(this, width); +} + +#endif // wxUSE_STATTEXT + +wxSizer *wxDialogBase::CreateButtonSizer(long flags) +{ + wxSizer *sizer = NULL; + +#ifdef __SMARTPHONE__ + wxDialog* dialog = (wxDialog*) this; + if ( flags & wxOK ) + dialog->SetLeftMenu(wxID_OK); + + if ( flags & wxCANCEL ) + dialog->SetRightMenu(wxID_CANCEL); + + if ( flags & wxYES ) + dialog->SetLeftMenu(wxID_YES); + + if ( flags & wxNO ) + dialog->SetRightMenu(wxID_NO); +#else // !__SMARTPHONE__ + +#if wxUSE_BUTTON + +#ifdef __POCKETPC__ + // PocketPC guidelines recommend for Ok/Cancel dialogs to use OK button + // located inside caption bar and implement Cancel functionality through + // Undo outside dialog. As native behaviour this will be default here but + // can be replaced with real wxButtons by setting the option below to 1 + if ( (flags & ~(wxCANCEL|wxNO_DEFAULT)) != wxOK || + wxSystemOptions::GetOptionInt(wxT("wince.dialog.real-ok-cancel")) ) +#endif // __POCKETPC__ + { + sizer = CreateStdDialogButtonSizer(flags); + } +#endif // wxUSE_BUTTON + +#endif // __SMARTPHONE__/!__SMARTPHONE__ + + return sizer; +} + +wxSizer *wxDialogBase::CreateSeparatedButtonSizer(long flags) +{ + wxSizer *sizer = CreateButtonSizer(flags); + if ( !sizer ) + return NULL; + + // Mac Human Interface Guidelines recommend not to use static lines as + // grouping elements +#if wxUSE_STATLINE && !defined(__WXMAC__) + wxBoxSizer *topsizer = new wxBoxSizer(wxVERTICAL); + topsizer->Add(new wxStaticLine(this), + wxSizerFlags().Expand().DoubleBorder(wxBOTTOM)); + topsizer->Add(sizer, wxSizerFlags().Expand()); + sizer = topsizer; +#endif // wxUSE_STATLINE + + return sizer; +} + +#if wxUSE_BUTTON + +wxStdDialogButtonSizer *wxDialogBase::CreateStdDialogButtonSizer( long flags ) +{ + wxStdDialogButtonSizer *sizer = new wxStdDialogButtonSizer(); + + wxButton *ok = NULL; + wxButton *yes = NULL; + wxButton *no = NULL; + + if (flags & wxOK) + { + ok = new wxButton(this, wxID_OK); + sizer->AddButton(ok); + } + + if (flags & wxCANCEL) + { + wxButton *cancel = new wxButton(this, wxID_CANCEL); + sizer->AddButton(cancel); + } + + if (flags & wxYES) + { + yes = new wxButton(this, wxID_YES); + sizer->AddButton(yes); + } + + if (flags & wxNO) + { + no = new wxButton(this, wxID_NO); + sizer->AddButton(no); + } + + if (flags & wxHELP) + { + wxButton *help = new wxButton(this, wxID_HELP); + sizer->AddButton(help); + } + + if (flags & wxNO_DEFAULT) + { + if (no) + { + no->SetDefault(); + no->SetFocus(); + } + } + else + { + if (ok) + { + ok->SetDefault(); + ok->SetFocus(); + } + else if (yes) + { + yes->SetDefault(); + yes->SetFocus(); + } + } + + if (flags & wxOK) + SetAffirmativeId(wxID_OK); + else if (flags & wxYES) + SetAffirmativeId(wxID_YES); + + sizer->Realize(); + + return sizer; +} + +#endif // wxUSE_BUTTON + +// ---------------------------------------------------------------------------- +// standard buttons handling +// ---------------------------------------------------------------------------- + +void wxDialogBase::EndDialog(int rc) +{ + if ( IsModal() ) + EndModal(rc); + else + Hide(); +} + +void wxDialogBase::AcceptAndClose() +{ + if ( Validate() && TransferDataFromWindow() ) + { + EndDialog(m_affirmativeId); + } +} + +void wxDialogBase::SetAffirmativeId(int affirmativeId) +{ + m_affirmativeId = affirmativeId; +} + +void wxDialogBase::SetEscapeId(int escapeId) +{ + m_escapeId = escapeId; +} + +bool wxDialogBase::EmulateButtonClickIfPresent(int id) +{ +#if wxUSE_BUTTON + wxButton *btn = wxDynamicCast(FindWindow(id), wxButton); + + if ( !btn || !btn->IsEnabled() || !btn->IsShown() ) + return false; + + wxCommandEvent event(wxEVT_COMMAND_BUTTON_CLICKED, id); + event.SetEventObject(btn); + btn->GetEventHandler()->ProcessEvent(event); + + return true; +#else // !wxUSE_BUTTON + wxUnusedVar(id); + return false; +#endif // wxUSE_BUTTON/!wxUSE_BUTTON +} + +bool wxDialogBase::IsEscapeKey(const wxKeyEvent& event) +{ + // for most platforms, Esc key is used to close the dialogs + return event.GetKeyCode() == WXK_ESCAPE && + event.GetModifiers() == wxMOD_NONE; +} + +void wxDialogBase::OnCharHook(wxKeyEvent& event) +{ + if ( event.GetKeyCode() == WXK_ESCAPE ) + { + int idCancel = GetEscapeId(); + switch ( idCancel ) + { + case wxID_NONE: + // don't handle Esc specially at all + break; + + case wxID_ANY: + // this value is special: it means translate Esc to wxID_CANCEL + // but if there is no such button, then fall back to wxID_OK + if ( EmulateButtonClickIfPresent(wxID_CANCEL) ) + return; + idCancel = GetAffirmativeId(); + // fall through + + default: + // translate Esc to button press for the button with given id + if ( EmulateButtonClickIfPresent(idCancel) ) + return; + } + } + + event.Skip(); +} + +void wxDialogBase::OnButton(wxCommandEvent& event) +{ + const int id = event.GetId(); + if ( id == GetAffirmativeId() ) + { + AcceptAndClose(); + } + else if ( id == wxID_APPLY ) + { + if ( Validate() ) + TransferDataFromWindow(); + + // TODO: disable the Apply button until things change again + } + else if ( id == GetEscapeId() || + (id == wxID_CANCEL && GetEscapeId() == wxID_ANY) ) + { + EndDialog(wxID_CANCEL); + } + else // not a standard button + { + event.Skip(); + } +} + +// ---------------------------------------------------------------------------- +// other event handlers +// ---------------------------------------------------------------------------- + +void wxDialogBase::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) +{ + // We'll send a Cancel message by default, which may close the dialog. + // Check for looping if the Cancel event handler calls Close(). + + // Note that if a cancel button and handler aren't present in the dialog, + // nothing will happen when you close the dialog via the window manager, or + // via Close(). We wouldn't want to destroy the dialog by default, since + // the dialog may have been created on the stack. However, this does mean + // that calling dialog->Close() won't delete the dialog unless the handler + // for wxID_CANCEL does so. So use Destroy() if you want to be sure to + // destroy the dialog. The default OnCancel (above) simply ends a modal + // dialog, and hides a modeless dialog. + + // VZ: this is horrible and MT-unsafe. Can't we reuse some of these global + // lists here? don't dare to change it now, but should be done later! + static wxList closing; + + if ( closing.Member(this) ) + return; + + closing.Append(this); + + wxCommandEvent cancelEvent(wxEVT_COMMAND_BUTTON_CLICKED, wxID_CANCEL); + cancelEvent.SetEventObject( this ); + GetEventHandler()->ProcessEvent(cancelEvent); // This may close the dialog + + closing.DeleteObject(this); +} + +void wxDialogBase::OnSysColourChanged(wxSysColourChangedEvent& event) +{ +#ifndef __WXGTK__ + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE)); + Refresh(); +#endif + event.Skip(); +} diff --git a/Source/3rd Party/wx/src/common/dndcmn.cpp b/Source/3rd Party/wx/src/common/dndcmn.cpp index 75b8a8d31..5daf3da7d 100644 --- a/Source/3rd Party/wx/src/common/dndcmn.cpp +++ b/Source/3rd Party/wx/src/common/dndcmn.cpp @@ -1,31 +1,31 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: common/dndcmn.cpp -// Author: Robert Roebling -// Modified by: -// Created: 19.10.99 -// RCS-ID: $Id: dndcmn.cpp 43664 2006-11-26 21:50:51Z JS $ -// Copyright: (c) wxWidgets Team -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/dnd.h" - -#if wxUSE_DRAG_AND_DROP - -bool wxIsDragResultOk(wxDragResult res) -{ - return res == wxDragCopy || res == wxDragMove || res == wxDragLink; -} - -#endif - +/////////////////////////////////////////////////////////////////////////////// +// Name: common/dndcmn.cpp +// Author: Robert Roebling +// Modified by: +// Created: 19.10.99 +// RCS-ID: $Id: dndcmn.cpp 43664 2006-11-26 21:50:51Z JS $ +// Copyright: (c) wxWidgets Team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/dnd.h" + +#if wxUSE_DRAG_AND_DROP + +bool wxIsDragResultOk(wxDragResult res) +{ + return res == wxDragCopy || res == wxDragMove || res == wxDragLink; +} + +#endif + diff --git a/Source/3rd Party/wx/src/common/dobjcmn.cpp b/Source/3rd Party/wx/src/common/dobjcmn.cpp index f9404928e..68b194d3e 100644 --- a/Source/3rd Party/wx/src/common/dobjcmn.cpp +++ b/Source/3rd Party/wx/src/common/dobjcmn.cpp @@ -1,517 +1,517 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/dobjcmn.cpp -// Purpose: implementation of data object methods common to all platforms -// Author: Vadim Zeitlin, Robert Roebling -// Modified by: -// Created: 19.10.99 -// RCS-ID: $Id: dobjcmn.cpp 49036 2007-10-04 10:10:06Z SC $ -// Copyright: (c) wxWidgets Team -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DATAOBJ - -#include "wx/dataobj.h" - -#ifndef WX_PRECOMP - #include "wx/app.h" -#endif - -// ---------------------------------------------------------------------------- -// lists -// ---------------------------------------------------------------------------- - -#include "wx/listimpl.cpp" - -WX_DEFINE_LIST(wxSimpleDataObjectList) - -// ---------------------------------------------------------------------------- -// globals -// ---------------------------------------------------------------------------- - -static wxDataFormat dataFormatInvalid; -WXDLLEXPORT const wxDataFormat& wxFormatInvalid = dataFormatInvalid; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxDataObjectBase -// ---------------------------------------------------------------------------- - -wxDataObjectBase::~wxDataObjectBase() -{ -} - -bool wxDataObjectBase::IsSupported(const wxDataFormat& format, - Direction dir) const -{ - size_t nFormatCount = GetFormatCount( dir ); - if ( nFormatCount == 1 ) - { - return format == GetPreferredFormat( dir ); - } - else - { - wxDataFormat *formats = new wxDataFormat[nFormatCount]; - GetAllFormats( formats, dir ); - - size_t n; - for ( n = 0; n < nFormatCount; n++ ) - { - if ( formats[n] == format ) - break; - } - - delete [] formats; - - // found? - return n < nFormatCount; - } -} - -// ---------------------------------------------------------------------------- -// wxDataObjectComposite -// ---------------------------------------------------------------------------- - -wxDataObjectComposite::wxDataObjectComposite() -{ - m_preferred = 0; - m_receivedFormat = wxFormatInvalid; -} - -wxDataObjectComposite::~wxDataObjectComposite() -{ - WX_CLEAR_LIST( wxSimpleDataObjectList, m_dataObjects ); -} - -wxDataObjectSimple * -wxDataObjectComposite::GetObject(const wxDataFormat& format) const -{ - wxSimpleDataObjectList::compatibility_iterator node = m_dataObjects.GetFirst(); - while ( node ) - { - wxDataObjectSimple *dataObj = node->GetData(); - - if ( dataObj->GetFormat() == format ) - { - return dataObj; - } - - node = node->GetNext(); - } - - return (wxDataObjectSimple *)NULL; -} - -void wxDataObjectComposite::Add(wxDataObjectSimple *dataObject, bool preferred) -{ - if ( preferred ) - m_preferred = m_dataObjects.GetCount(); - - m_dataObjects.Append( dataObject ); -} - -wxDataFormat wxDataObjectComposite::GetReceivedFormat() const -{ - return m_receivedFormat; -} - -wxDataFormat -wxDataObjectComposite::GetPreferredFormat(Direction WXUNUSED(dir)) const -{ - wxSimpleDataObjectList::compatibility_iterator node = m_dataObjects.Item( m_preferred ); - - wxCHECK_MSG( node, wxFormatInvalid, wxT("no preferred format") ); - - wxDataObjectSimple* dataObj = node->GetData(); - - return dataObj->GetFormat(); -} - -#if defined(__WXMSW__) - -size_t wxDataObjectComposite::GetBufferOffset( const wxDataFormat& format ) -{ - wxDataObjectSimple *dataObj = GetObject(format); - - wxCHECK_MSG( dataObj, 0, - wxT("unsupported format in wxDataObjectComposite")); - - return dataObj->GetBufferOffset( format ); -} - - -const void* wxDataObjectComposite::GetSizeFromBuffer( const void* buffer, - size_t* size, - const wxDataFormat& format ) -{ - wxDataObjectSimple *dataObj = GetObject(format); - - wxCHECK_MSG( dataObj, NULL, - wxT("unsupported format in wxDataObjectComposite")); - - return dataObj->GetSizeFromBuffer( buffer, size, format ); -} - - -void* wxDataObjectComposite::SetSizeInBuffer( void* buffer, size_t size, - const wxDataFormat& format ) -{ - wxDataObjectSimple *dataObj = GetObject( format ); - - wxCHECK_MSG( dataObj, NULL, - wxT("unsupported format in wxDataObjectComposite")); - - return dataObj->SetSizeInBuffer( buffer, size, format ); -} - -#endif - -size_t wxDataObjectComposite::GetFormatCount(Direction WXUNUSED(dir)) const -{ - // TODO what about the Get/Set only formats? - return m_dataObjects.GetCount(); -} - -void wxDataObjectComposite::GetAllFormats(wxDataFormat *formats, - Direction WXUNUSED(dir)) const -{ - size_t n = 0; - wxSimpleDataObjectList::compatibility_iterator node; - for ( node = m_dataObjects.GetFirst(); node; node = node->GetNext() ) - { - // TODO if ( !outputOnlyToo ) && this one counts ... - formats[n++] = node->GetData()->GetFormat(); - } -} - -size_t wxDataObjectComposite::GetDataSize(const wxDataFormat& format) const -{ - wxDataObjectSimple *dataObj = GetObject(format); - - wxCHECK_MSG( dataObj, 0, - wxT("unsupported format in wxDataObjectComposite")); - - return dataObj->GetDataSize(); -} - -bool wxDataObjectComposite::GetDataHere(const wxDataFormat& format, - void *buf) const -{ - wxDataObjectSimple *dataObj = GetObject( format ); - - wxCHECK_MSG( dataObj, false, - wxT("unsupported format in wxDataObjectComposite")); - - return dataObj->GetDataHere( buf ); -} - -bool wxDataObjectComposite::SetData(const wxDataFormat& format, - size_t len, - const void *buf) -{ - wxDataObjectSimple *dataObj = GetObject( format ); - - wxCHECK_MSG( dataObj, false, - wxT("unsupported format in wxDataObjectComposite")); - - m_receivedFormat = format; - return dataObj->SetData( len, buf ); -} - -// ---------------------------------------------------------------------------- -// wxTextDataObject -// ---------------------------------------------------------------------------- - -#if defined(__WXGTK20__) && wxUSE_UNICODE - -static inline wxMBConv& GetConv(const wxDataFormat& format) -{ - // use UTF8 for wxDF_UNICODETEXT and UCS4 for wxDF_TEXT - return format == wxDF_UNICODETEXT ? wxConvUTF8 : wxConvLibc; -} - -size_t wxTextDataObject::GetDataSize(const wxDataFormat& format) const -{ - wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); - - return buffer ? strlen( buffer ) : 0; -} - -bool wxTextDataObject::GetDataHere(const wxDataFormat& format, void *buf) const -{ - if ( !buf ) - return false; - - wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); - if ( !buffer ) - return false; - - memcpy( (char*) buf, buffer, GetDataSize(format) ); - // strcpy( (char*) buf, buffer ); - - return true; -} - -bool wxTextDataObject::SetData(const wxDataFormat& format, - size_t WXUNUSED(len), const void *buf) -{ - if ( buf == NULL ) - return false; - - wxWCharBuffer buffer = GetConv(format).cMB2WX( (const char*)buf ); - - SetText( buffer ); - - return true; -} - -#elif wxUSE_UNICODE && defined(__WXMAC__) - -static wxMBConvUTF16 sUTF16Converter; - -static inline wxMBConv& GetConv(const wxDataFormat& format) -{ - return - format == wxDF_UNICODETEXT - ? (wxMBConv&) sUTF16Converter - : (wxMBConv&) wxConvLocal; -} - -size_t wxTextDataObject::GetDataSize(const wxDataFormat& format) const -{ - wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); - if ( !buffer ) - return 0; - - size_t len = GetConv(format).WC2MB( NULL, GetText().c_str(), 0 ); - return len; -} - -bool wxTextDataObject::GetDataHere(const wxDataFormat& format, void *buf) const -{ - if ( buf == NULL ) - return false; - - wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); - if ( !buffer ) - return false; - - size_t len = GetConv(format).WC2MB( NULL, GetText().c_str(), 0 ); - memcpy( (char*)buf, (const char*)buffer, len ); - - return true; -} - -bool wxTextDataObject::SetData(const wxDataFormat& format, - size_t WXUNUSED(len), const void *buf) -{ - if ( buf == NULL ) - return false; - - wxWCharBuffer buffer = GetConv(format).cMB2WX( (const char*)buf ); - - SetText( buffer ); - - return true; -} - -#else - -size_t wxTextDataObject::GetDataSize() const -{ - return GetTextLength() * sizeof(wxChar); -} - -bool wxTextDataObject::GetDataHere(void *buf) const -{ - wxStrcpy( (wxChar*)buf, GetText().c_str() ); - - return true; -} - -bool wxTextDataObject::SetData(size_t WXUNUSED(len), const void *buf) -{ - SetText( wxString((const wxChar*)buf) ); - - return true; -} - -#endif - -// ---------------------------------------------------------------------------- -// wxFileDataObjectBase -// ---------------------------------------------------------------------------- - -// VZ: I don't need this in MSW finally, so if it is needed in wxGTK, it should -// be moved to gtk/dataobj.cpp -#if 0 - -wxString wxFileDataObjectBase::GetFilenames() const -{ - wxString str; - size_t count = m_filenames.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - str << m_filenames[n] << wxT('\0'); - } - - return str; -} - -void wxFileDataObjectBase::SetFilenames(const wxChar* filenames) -{ - m_filenames.Empty(); - - wxString current; - for ( const wxChar *pc = filenames; ; pc++ ) - { - if ( *pc ) - { - current += *pc; - } - else - { - if ( !current ) - { - // 2 consecutive NULs - this is the end of the string - break; - } - - m_filenames.Add(current); - current.Empty(); - } - } -} - -#endif - -// ---------------------------------------------------------------------------- -// wxCustomDataObject -// ---------------------------------------------------------------------------- - -wxCustomDataObject::wxCustomDataObject(const wxDataFormat& format) - : wxDataObjectSimple(format) -{ - m_data = NULL; - m_size = 0; -} - -wxCustomDataObject::~wxCustomDataObject() -{ - Free(); -} - -void wxCustomDataObject::TakeData(size_t size, void *data) -{ - Free(); - - m_size = size; - m_data = data; -} - -void *wxCustomDataObject::Alloc(size_t size) -{ - return (void *)new char[size]; -} - -void wxCustomDataObject::Free() -{ - delete [] (char*)m_data; - m_size = 0; - m_data = (void*)NULL; -} - -size_t wxCustomDataObject::GetDataSize() const -{ - return GetSize(); -} - -bool wxCustomDataObject::GetDataHere(void *buf) const -{ - if ( buf == NULL ) - return false; - - void *data = GetData(); - if ( data == NULL ) - return false; - - memcpy( buf, data, GetSize() ); - - return true; -} - -bool wxCustomDataObject::SetData(size_t size, const void *buf) -{ - Free(); - - m_data = Alloc(size); - if ( m_data == NULL ) - return false; - - m_size = size; - memcpy( m_data, buf, m_size ); - - return true; -} - -// ============================================================================ -// some common dnd related code -// ============================================================================ - -#if wxUSE_DRAG_AND_DROP - -#include "wx/dnd.h" - -// ---------------------------------------------------------------------------- -// wxTextDropTarget -// ---------------------------------------------------------------------------- - -// NB: we can't use "new" in ctor initializer lists because this provokes an -// internal compiler error with VC++ 5.0 (hey, even gcc compiles this!), -// so use SetDataObject() instead - -wxTextDropTarget::wxTextDropTarget() -{ - SetDataObject(new wxTextDataObject); -} - -wxDragResult wxTextDropTarget::OnData(wxCoord x, wxCoord y, wxDragResult def) -{ - if ( !GetData() ) - return wxDragNone; - - wxTextDataObject *dobj = (wxTextDataObject *)m_dataObject; - return OnDropText( x, y, dobj->GetText() ) ? def : wxDragNone; -} - -// ---------------------------------------------------------------------------- -// wxFileDropTarget -// ---------------------------------------------------------------------------- - -wxFileDropTarget::wxFileDropTarget() -{ - SetDataObject(new wxFileDataObject); -} - -wxDragResult wxFileDropTarget::OnData(wxCoord x, wxCoord y, wxDragResult def) -{ - if ( !GetData() ) - return wxDragNone; - - wxFileDataObject *dobj = (wxFileDataObject *)m_dataObject; - return OnDropFiles( x, y, dobj->GetFilenames() ) ? def : wxDragNone; -} - -#endif // wxUSE_DRAG_AND_DROP - -#endif // wxUSE_DATAOBJ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/dobjcmn.cpp +// Purpose: implementation of data object methods common to all platforms +// Author: Vadim Zeitlin, Robert Roebling +// Modified by: +// Created: 19.10.99 +// RCS-ID: $Id: dobjcmn.cpp 49036 2007-10-04 10:10:06Z SC $ +// Copyright: (c) wxWidgets Team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DATAOBJ + +#include "wx/dataobj.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" +#endif + +// ---------------------------------------------------------------------------- +// lists +// ---------------------------------------------------------------------------- + +#include "wx/listimpl.cpp" + +WX_DEFINE_LIST(wxSimpleDataObjectList) + +// ---------------------------------------------------------------------------- +// globals +// ---------------------------------------------------------------------------- + +static wxDataFormat dataFormatInvalid; +WXDLLEXPORT const wxDataFormat& wxFormatInvalid = dataFormatInvalid; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxDataObjectBase +// ---------------------------------------------------------------------------- + +wxDataObjectBase::~wxDataObjectBase() +{ +} + +bool wxDataObjectBase::IsSupported(const wxDataFormat& format, + Direction dir) const +{ + size_t nFormatCount = GetFormatCount( dir ); + if ( nFormatCount == 1 ) + { + return format == GetPreferredFormat( dir ); + } + else + { + wxDataFormat *formats = new wxDataFormat[nFormatCount]; + GetAllFormats( formats, dir ); + + size_t n; + for ( n = 0; n < nFormatCount; n++ ) + { + if ( formats[n] == format ) + break; + } + + delete [] formats; + + // found? + return n < nFormatCount; + } +} + +// ---------------------------------------------------------------------------- +// wxDataObjectComposite +// ---------------------------------------------------------------------------- + +wxDataObjectComposite::wxDataObjectComposite() +{ + m_preferred = 0; + m_receivedFormat = wxFormatInvalid; +} + +wxDataObjectComposite::~wxDataObjectComposite() +{ + WX_CLEAR_LIST( wxSimpleDataObjectList, m_dataObjects ); +} + +wxDataObjectSimple * +wxDataObjectComposite::GetObject(const wxDataFormat& format) const +{ + wxSimpleDataObjectList::compatibility_iterator node = m_dataObjects.GetFirst(); + while ( node ) + { + wxDataObjectSimple *dataObj = node->GetData(); + + if ( dataObj->GetFormat() == format ) + { + return dataObj; + } + + node = node->GetNext(); + } + + return (wxDataObjectSimple *)NULL; +} + +void wxDataObjectComposite::Add(wxDataObjectSimple *dataObject, bool preferred) +{ + if ( preferred ) + m_preferred = m_dataObjects.GetCount(); + + m_dataObjects.Append( dataObject ); +} + +wxDataFormat wxDataObjectComposite::GetReceivedFormat() const +{ + return m_receivedFormat; +} + +wxDataFormat +wxDataObjectComposite::GetPreferredFormat(Direction WXUNUSED(dir)) const +{ + wxSimpleDataObjectList::compatibility_iterator node = m_dataObjects.Item( m_preferred ); + + wxCHECK_MSG( node, wxFormatInvalid, wxT("no preferred format") ); + + wxDataObjectSimple* dataObj = node->GetData(); + + return dataObj->GetFormat(); +} + +#if defined(__WXMSW__) + +size_t wxDataObjectComposite::GetBufferOffset( const wxDataFormat& format ) +{ + wxDataObjectSimple *dataObj = GetObject(format); + + wxCHECK_MSG( dataObj, 0, + wxT("unsupported format in wxDataObjectComposite")); + + return dataObj->GetBufferOffset( format ); +} + + +const void* wxDataObjectComposite::GetSizeFromBuffer( const void* buffer, + size_t* size, + const wxDataFormat& format ) +{ + wxDataObjectSimple *dataObj = GetObject(format); + + wxCHECK_MSG( dataObj, NULL, + wxT("unsupported format in wxDataObjectComposite")); + + return dataObj->GetSizeFromBuffer( buffer, size, format ); +} + + +void* wxDataObjectComposite::SetSizeInBuffer( void* buffer, size_t size, + const wxDataFormat& format ) +{ + wxDataObjectSimple *dataObj = GetObject( format ); + + wxCHECK_MSG( dataObj, NULL, + wxT("unsupported format in wxDataObjectComposite")); + + return dataObj->SetSizeInBuffer( buffer, size, format ); +} + +#endif + +size_t wxDataObjectComposite::GetFormatCount(Direction WXUNUSED(dir)) const +{ + // TODO what about the Get/Set only formats? + return m_dataObjects.GetCount(); +} + +void wxDataObjectComposite::GetAllFormats(wxDataFormat *formats, + Direction WXUNUSED(dir)) const +{ + size_t n = 0; + wxSimpleDataObjectList::compatibility_iterator node; + for ( node = m_dataObjects.GetFirst(); node; node = node->GetNext() ) + { + // TODO if ( !outputOnlyToo ) && this one counts ... + formats[n++] = node->GetData()->GetFormat(); + } +} + +size_t wxDataObjectComposite::GetDataSize(const wxDataFormat& format) const +{ + wxDataObjectSimple *dataObj = GetObject(format); + + wxCHECK_MSG( dataObj, 0, + wxT("unsupported format in wxDataObjectComposite")); + + return dataObj->GetDataSize(); +} + +bool wxDataObjectComposite::GetDataHere(const wxDataFormat& format, + void *buf) const +{ + wxDataObjectSimple *dataObj = GetObject( format ); + + wxCHECK_MSG( dataObj, false, + wxT("unsupported format in wxDataObjectComposite")); + + return dataObj->GetDataHere( buf ); +} + +bool wxDataObjectComposite::SetData(const wxDataFormat& format, + size_t len, + const void *buf) +{ + wxDataObjectSimple *dataObj = GetObject( format ); + + wxCHECK_MSG( dataObj, false, + wxT("unsupported format in wxDataObjectComposite")); + + m_receivedFormat = format; + return dataObj->SetData( len, buf ); +} + +// ---------------------------------------------------------------------------- +// wxTextDataObject +// ---------------------------------------------------------------------------- + +#if defined(__WXGTK20__) && wxUSE_UNICODE + +static inline wxMBConv& GetConv(const wxDataFormat& format) +{ + // use UTF8 for wxDF_UNICODETEXT and UCS4 for wxDF_TEXT + return format == wxDF_UNICODETEXT ? wxConvUTF8 : wxConvLibc; +} + +size_t wxTextDataObject::GetDataSize(const wxDataFormat& format) const +{ + wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); + + return buffer ? strlen( buffer ) : 0; +} + +bool wxTextDataObject::GetDataHere(const wxDataFormat& format, void *buf) const +{ + if ( !buf ) + return false; + + wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); + if ( !buffer ) + return false; + + memcpy( (char*) buf, buffer, GetDataSize(format) ); + // strcpy( (char*) buf, buffer ); + + return true; +} + +bool wxTextDataObject::SetData(const wxDataFormat& format, + size_t WXUNUSED(len), const void *buf) +{ + if ( buf == NULL ) + return false; + + wxWCharBuffer buffer = GetConv(format).cMB2WX( (const char*)buf ); + + SetText( buffer ); + + return true; +} + +#elif wxUSE_UNICODE && defined(__WXMAC__) + +static wxMBConvUTF16 sUTF16Converter; + +static inline wxMBConv& GetConv(const wxDataFormat& format) +{ + return + format == wxDF_UNICODETEXT + ? (wxMBConv&) sUTF16Converter + : (wxMBConv&) wxConvLocal; +} + +size_t wxTextDataObject::GetDataSize(const wxDataFormat& format) const +{ + wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); + if ( !buffer ) + return 0; + + size_t len = GetConv(format).WC2MB( NULL, GetText().c_str(), 0 ); + return len; +} + +bool wxTextDataObject::GetDataHere(const wxDataFormat& format, void *buf) const +{ + if ( buf == NULL ) + return false; + + wxCharBuffer buffer = GetConv(format).cWX2MB( GetText().c_str() ); + if ( !buffer ) + return false; + + size_t len = GetConv(format).WC2MB( NULL, GetText().c_str(), 0 ); + memcpy( (char*)buf, (const char*)buffer, len ); + + return true; +} + +bool wxTextDataObject::SetData(const wxDataFormat& format, + size_t WXUNUSED(len), const void *buf) +{ + if ( buf == NULL ) + return false; + + wxWCharBuffer buffer = GetConv(format).cMB2WX( (const char*)buf ); + + SetText( buffer ); + + return true; +} + +#else + +size_t wxTextDataObject::GetDataSize() const +{ + return GetTextLength() * sizeof(wxChar); +} + +bool wxTextDataObject::GetDataHere(void *buf) const +{ + wxStrcpy( (wxChar*)buf, GetText().c_str() ); + + return true; +} + +bool wxTextDataObject::SetData(size_t WXUNUSED(len), const void *buf) +{ + SetText( wxString((const wxChar*)buf) ); + + return true; +} + +#endif + +// ---------------------------------------------------------------------------- +// wxFileDataObjectBase +// ---------------------------------------------------------------------------- + +// VZ: I don't need this in MSW finally, so if it is needed in wxGTK, it should +// be moved to gtk/dataobj.cpp +#if 0 + +wxString wxFileDataObjectBase::GetFilenames() const +{ + wxString str; + size_t count = m_filenames.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + str << m_filenames[n] << wxT('\0'); + } + + return str; +} + +void wxFileDataObjectBase::SetFilenames(const wxChar* filenames) +{ + m_filenames.Empty(); + + wxString current; + for ( const wxChar *pc = filenames; ; pc++ ) + { + if ( *pc ) + { + current += *pc; + } + else + { + if ( !current ) + { + // 2 consecutive NULs - this is the end of the string + break; + } + + m_filenames.Add(current); + current.Empty(); + } + } +} + +#endif + +// ---------------------------------------------------------------------------- +// wxCustomDataObject +// ---------------------------------------------------------------------------- + +wxCustomDataObject::wxCustomDataObject(const wxDataFormat& format) + : wxDataObjectSimple(format) +{ + m_data = NULL; + m_size = 0; +} + +wxCustomDataObject::~wxCustomDataObject() +{ + Free(); +} + +void wxCustomDataObject::TakeData(size_t size, void *data) +{ + Free(); + + m_size = size; + m_data = data; +} + +void *wxCustomDataObject::Alloc(size_t size) +{ + return (void *)new char[size]; +} + +void wxCustomDataObject::Free() +{ + delete [] (char*)m_data; + m_size = 0; + m_data = (void*)NULL; +} + +size_t wxCustomDataObject::GetDataSize() const +{ + return GetSize(); +} + +bool wxCustomDataObject::GetDataHere(void *buf) const +{ + if ( buf == NULL ) + return false; + + void *data = GetData(); + if ( data == NULL ) + return false; + + memcpy( buf, data, GetSize() ); + + return true; +} + +bool wxCustomDataObject::SetData(size_t size, const void *buf) +{ + Free(); + + m_data = Alloc(size); + if ( m_data == NULL ) + return false; + + m_size = size; + memcpy( m_data, buf, m_size ); + + return true; +} + +// ============================================================================ +// some common dnd related code +// ============================================================================ + +#if wxUSE_DRAG_AND_DROP + +#include "wx/dnd.h" + +// ---------------------------------------------------------------------------- +// wxTextDropTarget +// ---------------------------------------------------------------------------- + +// NB: we can't use "new" in ctor initializer lists because this provokes an +// internal compiler error with VC++ 5.0 (hey, even gcc compiles this!), +// so use SetDataObject() instead + +wxTextDropTarget::wxTextDropTarget() +{ + SetDataObject(new wxTextDataObject); +} + +wxDragResult wxTextDropTarget::OnData(wxCoord x, wxCoord y, wxDragResult def) +{ + if ( !GetData() ) + return wxDragNone; + + wxTextDataObject *dobj = (wxTextDataObject *)m_dataObject; + return OnDropText( x, y, dobj->GetText() ) ? def : wxDragNone; +} + +// ---------------------------------------------------------------------------- +// wxFileDropTarget +// ---------------------------------------------------------------------------- + +wxFileDropTarget::wxFileDropTarget() +{ + SetDataObject(new wxFileDataObject); +} + +wxDragResult wxFileDropTarget::OnData(wxCoord x, wxCoord y, wxDragResult def) +{ + if ( !GetData() ) + return wxDragNone; + + wxFileDataObject *dobj = (wxFileDataObject *)m_dataObject; + return OnDropFiles( x, y, dobj->GetFilenames() ) ? def : wxDragNone; +} + +#endif // wxUSE_DRAG_AND_DROP + +#endif // wxUSE_DATAOBJ diff --git a/Source/3rd Party/wx/src/common/docmdi.cpp b/Source/3rd Party/wx/src/common/docmdi.cpp index 5dd6e9939..d63628f69 100644 --- a/Source/3rd Party/wx/src/common/docmdi.cpp +++ b/Source/3rd Party/wx/src/common/docmdi.cpp @@ -1,206 +1,206 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: docmdi.cpp -// Purpose: Frame classes for MDI document/view applications -// Author: Julian Smart -// Modified by: -// Created: 01/02/97 -// RCS-ID: $Id: docmdi.cpp 66911 2011-02-16 21:31:33Z JS $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_MDI_ARCHITECTURE - -#include "wx/docmdi.h" - -/* - * Docview MDI parent frame - */ - -IMPLEMENT_CLASS(wxDocMDIParentFrame, wxMDIParentFrame) - -BEGIN_EVENT_TABLE(wxDocMDIParentFrame, wxMDIParentFrame) - EVT_MENU(wxID_EXIT, wxDocMDIParentFrame::OnExit) - EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocMDIParentFrame::OnMRUFile) - EVT_CLOSE(wxDocMDIParentFrame::OnCloseWindow) -END_EVENT_TABLE() - -wxDocMDIParentFrame::wxDocMDIParentFrame() -{ - Init(); -} - -wxDocMDIParentFrame::wxDocMDIParentFrame(wxDocManager *manager, wxFrame *frame, wxWindowID id, const wxString& title, - const wxPoint& pos, const wxSize& size, long style, const wxString& name) -{ - Init(); - Create(manager, frame, id, title, pos, size, style, name); -} - -bool wxDocMDIParentFrame::Create(wxDocManager *manager, wxFrame *frame, wxWindowID id, const wxString& title, - const wxPoint& pos, const wxSize& size, long style, const wxString& name) -{ - m_docManager = manager; - return wxMDIParentFrame::Create(frame, id, title, pos, size, style, name); -} - -void wxDocMDIParentFrame::OnExit(wxCommandEvent& WXUNUSED(event)) -{ - Close(); -} - -void wxDocMDIParentFrame::Init() -{ - m_docManager = NULL; -} - -void wxDocMDIParentFrame::OnMRUFile(wxCommandEvent& event) -{ - wxString f(m_docManager->GetHistoryFile(event.GetId() - wxID_FILE1)); - if (!f.empty()) - (void)m_docManager->CreateDocument(f, wxDOC_SILENT); -} - -// Extend event processing to search the view's event table -bool wxDocMDIParentFrame::ProcessEvent(wxEvent& event) -{ - // Try the document manager, then do default processing - if (!m_docManager || !m_docManager->ProcessEvent(event)) - return wxEvtHandler::ProcessEvent(event); - else - return true; -} - -void wxDocMDIParentFrame::OnCloseWindow(wxCloseEvent& event) -{ - if ( m_docManager && !m_docManager->Clear(!event.CanVeto()) ) - { - // The user decided not to close finally, abort. - event.Veto(); - } - else - { - this->Destroy(); - } -} - -/* - * Default document child frame for MDI children - */ - -IMPLEMENT_CLASS(wxDocMDIChildFrame, wxMDIChildFrame) - -BEGIN_EVENT_TABLE(wxDocMDIChildFrame, wxMDIChildFrame) - EVT_ACTIVATE(wxDocMDIChildFrame::OnActivate) - EVT_CLOSE(wxDocMDIChildFrame::OnCloseWindow) -END_EVENT_TABLE() - -void wxDocMDIChildFrame::Init() -{ - m_childDocument = (wxDocument*) NULL; - m_childView = (wxView*) NULL; -} - -wxDocMDIChildFrame::wxDocMDIChildFrame() -{ - Init(); -} - -wxDocMDIChildFrame::wxDocMDIChildFrame(wxDocument *doc, wxView *view, wxMDIParentFrame *frame, wxWindowID id, - const wxString& title, const wxPoint& pos, const wxSize& size, long style, const wxString& name) -{ - Init(); - Create(doc, view, frame, id, title, pos, size, style, name); -} - -bool wxDocMDIChildFrame::Create(wxDocument *doc, wxView *view, wxMDIParentFrame *frame, wxWindowID id, - const wxString& title, const wxPoint& pos, const wxSize& size, long style, const wxString& name) -{ - m_childDocument = doc; - m_childView = view; - if (wxMDIChildFrame::Create(frame, id, title, pos, size, style, name)) - { - if (view) - view->SetFrame(this); - return true; - } - - return false; -} - -wxDocMDIChildFrame::~wxDocMDIChildFrame(void) -{ - m_childView = (wxView *) NULL; -} - -// Extend event processing to search the view's event table -bool wxDocMDIChildFrame::ProcessEvent(wxEvent& event) -{ - static wxEvent *ActiveEvent = NULL; - - // Break recursion loops - if (ActiveEvent == &event) - return false; - - ActiveEvent = &event; - - bool ret; - if ( !m_childView || ! m_childView->ProcessEvent(event) ) - { - // Only hand up to the parent if it's a menu command - if (!event.IsKindOf(CLASSINFO(wxCommandEvent)) || !GetParent() || !GetParent()->ProcessEvent(event)) - ret = wxEvtHandler::ProcessEvent(event); - else - ret = true; - } - else - ret = true; - - ActiveEvent = NULL; - return ret; -} - -void wxDocMDIChildFrame::OnActivate(wxActivateEvent& event) -{ - wxMDIChildFrame::OnActivate(event); - - if (event.GetActive() && m_childView) - m_childView->Activate(event.GetActive()); -} - -void wxDocMDIChildFrame::OnCloseWindow(wxCloseEvent& event) -{ - // Close view but don't delete the frame while doing so! - // ...since it will be deleted by wxWidgets if we return true. - if (m_childView) - { - bool ans = event.CanVeto() - ? m_childView->Close(false) // false means don't delete associated window - : true; // Must delete. - - if (ans) - { - m_childView->Activate(false); - delete m_childView; - m_childView = (wxView *) NULL; - m_childDocument = (wxDocument *) NULL; - - this->Destroy(); - } - else - event.Veto(); - } - else - event.Veto(); -} - -#endif - // wxUSE_DOC_VIEW_ARCHITECTURE - +///////////////////////////////////////////////////////////////////////////// +// Name: docmdi.cpp +// Purpose: Frame classes for MDI document/view applications +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id: docmdi.cpp 66911 2011-02-16 21:31:33Z JS $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_MDI_ARCHITECTURE + +#include "wx/docmdi.h" + +/* + * Docview MDI parent frame + */ + +IMPLEMENT_CLASS(wxDocMDIParentFrame, wxMDIParentFrame) + +BEGIN_EVENT_TABLE(wxDocMDIParentFrame, wxMDIParentFrame) + EVT_MENU(wxID_EXIT, wxDocMDIParentFrame::OnExit) + EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocMDIParentFrame::OnMRUFile) + EVT_CLOSE(wxDocMDIParentFrame::OnCloseWindow) +END_EVENT_TABLE() + +wxDocMDIParentFrame::wxDocMDIParentFrame() +{ + Init(); +} + +wxDocMDIParentFrame::wxDocMDIParentFrame(wxDocManager *manager, wxFrame *frame, wxWindowID id, const wxString& title, + const wxPoint& pos, const wxSize& size, long style, const wxString& name) +{ + Init(); + Create(manager, frame, id, title, pos, size, style, name); +} + +bool wxDocMDIParentFrame::Create(wxDocManager *manager, wxFrame *frame, wxWindowID id, const wxString& title, + const wxPoint& pos, const wxSize& size, long style, const wxString& name) +{ + m_docManager = manager; + return wxMDIParentFrame::Create(frame, id, title, pos, size, style, name); +} + +void wxDocMDIParentFrame::OnExit(wxCommandEvent& WXUNUSED(event)) +{ + Close(); +} + +void wxDocMDIParentFrame::Init() +{ + m_docManager = NULL; +} + +void wxDocMDIParentFrame::OnMRUFile(wxCommandEvent& event) +{ + wxString f(m_docManager->GetHistoryFile(event.GetId() - wxID_FILE1)); + if (!f.empty()) + (void)m_docManager->CreateDocument(f, wxDOC_SILENT); +} + +// Extend event processing to search the view's event table +bool wxDocMDIParentFrame::ProcessEvent(wxEvent& event) +{ + // Try the document manager, then do default processing + if (!m_docManager || !m_docManager->ProcessEvent(event)) + return wxEvtHandler::ProcessEvent(event); + else + return true; +} + +void wxDocMDIParentFrame::OnCloseWindow(wxCloseEvent& event) +{ + if ( m_docManager && !m_docManager->Clear(!event.CanVeto()) ) + { + // The user decided not to close finally, abort. + event.Veto(); + } + else + { + this->Destroy(); + } +} + +/* + * Default document child frame for MDI children + */ + +IMPLEMENT_CLASS(wxDocMDIChildFrame, wxMDIChildFrame) + +BEGIN_EVENT_TABLE(wxDocMDIChildFrame, wxMDIChildFrame) + EVT_ACTIVATE(wxDocMDIChildFrame::OnActivate) + EVT_CLOSE(wxDocMDIChildFrame::OnCloseWindow) +END_EVENT_TABLE() + +void wxDocMDIChildFrame::Init() +{ + m_childDocument = (wxDocument*) NULL; + m_childView = (wxView*) NULL; +} + +wxDocMDIChildFrame::wxDocMDIChildFrame() +{ + Init(); +} + +wxDocMDIChildFrame::wxDocMDIChildFrame(wxDocument *doc, wxView *view, wxMDIParentFrame *frame, wxWindowID id, + const wxString& title, const wxPoint& pos, const wxSize& size, long style, const wxString& name) +{ + Init(); + Create(doc, view, frame, id, title, pos, size, style, name); +} + +bool wxDocMDIChildFrame::Create(wxDocument *doc, wxView *view, wxMDIParentFrame *frame, wxWindowID id, + const wxString& title, const wxPoint& pos, const wxSize& size, long style, const wxString& name) +{ + m_childDocument = doc; + m_childView = view; + if (wxMDIChildFrame::Create(frame, id, title, pos, size, style, name)) + { + if (view) + view->SetFrame(this); + return true; + } + + return false; +} + +wxDocMDIChildFrame::~wxDocMDIChildFrame(void) +{ + m_childView = (wxView *) NULL; +} + +// Extend event processing to search the view's event table +bool wxDocMDIChildFrame::ProcessEvent(wxEvent& event) +{ + static wxEvent *ActiveEvent = NULL; + + // Break recursion loops + if (ActiveEvent == &event) + return false; + + ActiveEvent = &event; + + bool ret; + if ( !m_childView || ! m_childView->ProcessEvent(event) ) + { + // Only hand up to the parent if it's a menu command + if (!event.IsKindOf(CLASSINFO(wxCommandEvent)) || !GetParent() || !GetParent()->ProcessEvent(event)) + ret = wxEvtHandler::ProcessEvent(event); + else + ret = true; + } + else + ret = true; + + ActiveEvent = NULL; + return ret; +} + +void wxDocMDIChildFrame::OnActivate(wxActivateEvent& event) +{ + wxMDIChildFrame::OnActivate(event); + + if (event.GetActive() && m_childView) + m_childView->Activate(event.GetActive()); +} + +void wxDocMDIChildFrame::OnCloseWindow(wxCloseEvent& event) +{ + // Close view but don't delete the frame while doing so! + // ...since it will be deleted by wxWidgets if we return true. + if (m_childView) + { + bool ans = event.CanVeto() + ? m_childView->Close(false) // false means don't delete associated window + : true; // Must delete. + + if (ans) + { + m_childView->Activate(false); + delete m_childView; + m_childView = (wxView *) NULL; + m_childDocument = (wxDocument *) NULL; + + this->Destroy(); + } + else + event.Veto(); + } + else + event.Veto(); +} + +#endif + // wxUSE_DOC_VIEW_ARCHITECTURE + diff --git a/Source/3rd Party/wx/src/common/docview.cpp b/Source/3rd Party/wx/src/common/docview.cpp index cc09b1613..be1393f86 100644 --- a/Source/3rd Party/wx/src/common/docview.cpp +++ b/Source/3rd Party/wx/src/common/docview.cpp @@ -1,2491 +1,2491 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/docview.cpp -// Purpose: Document/view classes -// Author: Julian Smart -// Modified by: -// Created: 01/02/97 -// RCS-ID: $Id: docview.cpp 66911 2011-02-16 21:31:33Z JS $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DOC_VIEW_ARCHITECTURE - -#include "wx/docview.h" - -#ifndef WX_PRECOMP - #include "wx/list.h" - #include "wx/string.h" - #include "wx/utils.h" - #include "wx/app.h" - #include "wx/dc.h" - #include "wx/dialog.h" - #include "wx/menu.h" - #include "wx/filedlg.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/msgdlg.h" - #include "wx/mdi.h" - #include "wx/choicdlg.h" -#endif - -#include "wx/ffile.h" - -#ifdef __WXMAC__ - #include "wx/filename.h" -#endif - -#if wxUSE_PRINTING_ARCHITECTURE - #include "wx/prntbase.h" - #include "wx/printdlg.h" -#endif - -#include "wx/confbase.h" -#include "wx/file.h" -#include "wx/cmdproc.h" -#include "wx/tokenzr.h" - -#include -#include - -#if wxUSE_STD_IOSTREAM - #include "wx/ioswrap.h" - #if wxUSE_IOSTREAMH - #include - #else - #include - #endif -#else - #include "wx/wfstream.h" -#endif - -// ---------------------------------------------------------------------------- -// wxWidgets macros -// ---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxDocument, wxEvtHandler) -IMPLEMENT_ABSTRACT_CLASS(wxView, wxEvtHandler) -IMPLEMENT_ABSTRACT_CLASS(wxDocTemplate, wxObject) -IMPLEMENT_DYNAMIC_CLASS(wxDocManager, wxEvtHandler) -IMPLEMENT_CLASS(wxDocChildFrame, wxFrame) -IMPLEMENT_CLASS(wxDocParentFrame, wxFrame) - -#if wxUSE_PRINTING_ARCHITECTURE - IMPLEMENT_DYNAMIC_CLASS(wxDocPrintout, wxPrintout) -#endif - -IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject) - -// ---------------------------------------------------------------------------- -// function prototypes -// ---------------------------------------------------------------------------- - -static wxWindow* wxFindSuitableParent(void); - -// ---------------------------------------------------------------------------- -// local constants -// ---------------------------------------------------------------------------- - -static const wxChar *s_MRUEntryFormat = wxT("&%d %s"); - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// local functions -// ---------------------------------------------------------------------------- - -static wxString FindExtension(const wxChar *path) -{ - wxString ext; - wxSplitPath(path, NULL, NULL, &ext); - - // VZ: extensions are considered not case sensitive - is this really a good - // idea? - return ext.MakeLower(); -} - -// ---------------------------------------------------------------------------- -// Definition of wxDocument -// ---------------------------------------------------------------------------- - -wxDocument::wxDocument(wxDocument *parent) -{ - m_documentModified = false; - m_documentParent = parent; - m_documentTemplate = (wxDocTemplate *) NULL; - m_commandProcessor = (wxCommandProcessor*) NULL; - m_savedYet = false; -} - -bool wxDocument::DeleteContents() -{ - return true; -} - -wxDocument::~wxDocument() -{ - DeleteContents(); - - if (m_commandProcessor) - delete m_commandProcessor; - - if (GetDocumentManager()) - GetDocumentManager()->RemoveDocument(this); - - // Not safe to do here, since it'll invoke virtual view functions - // expecting to see valid derived objects: and by the time we get here, - // we've called destructors higher up. - //DeleteAllViews(); -} - -bool wxDocument::Close() -{ - if (OnSaveModified()) - return OnCloseDocument(); - else - return false; -} - -bool wxDocument::OnCloseDocument() -{ - // Tell all views that we're about to close - NotifyClosing(); - DeleteContents(); - Modify(false); - return true; -} - -// Note that this implicitly deletes the document when the last view is -// deleted. -bool wxDocument::DeleteAllViews() -{ - wxDocManager* manager = GetDocumentManager(); - - // first check if all views agree to be closed - const wxList::iterator end = m_documentViews.end(); - for ( wxList::iterator i = m_documentViews.begin(); i != end; ++i ) - { - wxView *view = (wxView *)*i; - if ( !view->Close() ) - return false; - } - - // all views agreed to close, now do close them - if ( m_documentViews.empty() ) - { - // normally the document would be implicitly deleted when the last view - // is, but if don't have any views, do it here instead - if ( manager && manager->GetDocuments().Member(this) ) - delete this; - } - else // have views - { - // as we delete elements we iterate over, don't use the usual "from - // begin to end" loop - for ( ;; ) - { - wxView *view = (wxView *)*m_documentViews.begin(); - - bool isLastOne = m_documentViews.size() == 1; - - // this always deletes the node implicitly and if this is the last - // view also deletes this object itself (also implicitly, great), - // so we can't test for m_documentViews.empty() after calling this! - delete view; - - if ( isLastOne ) - break; - } - } - - return true; -} - -wxView *wxDocument::GetFirstView() const -{ - if (m_documentViews.GetCount() == 0) - return (wxView *) NULL; - return (wxView *)m_documentViews.GetFirst()->GetData(); -} - -wxDocManager *wxDocument::GetDocumentManager() const -{ - return (m_documentTemplate ? m_documentTemplate->GetDocumentManager() : (wxDocManager*) NULL); -} - -bool wxDocument::OnNewDocument() -{ - if (!OnSaveModified()) - return false; - - if (OnCloseDocument()==false) return false; - DeleteContents(); - Modify(false); - SetDocumentSaved(false); - - wxString name; - GetDocumentManager()->MakeDefaultName(name); - SetTitle(name); - SetFilename(name, true); - - return true; -} - -bool wxDocument::Save() -{ - if (!IsModified() && m_savedYet) - return true; - - if ( m_documentFile.empty() || !m_savedYet ) - return SaveAs(); - - return OnSaveDocument(m_documentFile); -} - -bool wxDocument::SaveAs() -{ - wxDocTemplate *docTemplate = GetDocumentTemplate(); - if (!docTemplate) - return false; - -#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) - wxString filter = docTemplate->GetDescription() + wxT(" (") + docTemplate->GetFileFilter() + wxT(")|") + docTemplate->GetFileFilter(); - - // Now see if there are some other template with identical view and document - // classes, whose filters may also be used. - - if (docTemplate->GetViewClassInfo() && docTemplate->GetDocClassInfo()) - { - wxList::compatibility_iterator node = docTemplate->GetDocumentManager()->GetTemplates().GetFirst(); - while (node) - { - wxDocTemplate *t = (wxDocTemplate*) node->GetData(); - - if (t->IsVisible() && t != docTemplate && - t->GetViewClassInfo() == docTemplate->GetViewClassInfo() && - t->GetDocClassInfo() == docTemplate->GetDocClassInfo()) - { - // add a '|' to separate this filter from the previous one - if ( !filter.empty() ) - filter << wxT('|'); - - filter << t->GetDescription() << wxT(" (") << t->GetFileFilter() << wxT(") |") - << t->GetFileFilter(); - } - - node = node->GetNext(); - } - } -#else - wxString filter = docTemplate->GetFileFilter() ; -#endif - wxString defaultDir = docTemplate->GetDirectory(); - if (defaultDir.IsEmpty()) - defaultDir = wxPathOnly(GetFilename()); - - wxString tmp = wxFileSelector(_("Save as"), - defaultDir, - wxFileNameFromPath(GetFilename()), - docTemplate->GetDefaultExtension(), - filter, - wxFD_SAVE | wxFD_OVERWRITE_PROMPT, - GetDocumentWindow()); - - if (tmp.empty()) - return false; - - wxString fileName(tmp); - wxString path, name, ext; - wxSplitPath(fileName, & path, & name, & ext); - - if (ext.empty()) - { - fileName += wxT("."); - fileName += docTemplate->GetDefaultExtension(); - } - - SetFilename(fileName); - SetTitle(wxFileNameFromPath(fileName)); - - // Notify the views that the filename has changed - wxList::compatibility_iterator node = m_documentViews.GetFirst(); - while (node) - { - wxView *view = (wxView *)node->GetData(); - view->OnChangeFilename(); - node = node->GetNext(); - } - - // Files that were not saved correctly are not added to the FileHistory. - if (!OnSaveDocument(m_documentFile)) - return false; - - // A file that doesn't use the default extension of its document template cannot be opened - // via the FileHistory, so we do not add it. - if (docTemplate->FileMatchesTemplate(fileName)) - { - GetDocumentManager()->AddFileToHistory(fileName); - } - else - { - // The user will probably not be able to open the file again, so - // we could warn about the wrong file-extension here. - } - return true; -} - -bool wxDocument::OnSaveDocument(const wxString& file) -{ - if ( !file ) - return false; - - if ( !DoSaveDocument(file) ) - return false; - - Modify(false); - SetFilename(file); - SetDocumentSaved(true); -#ifdef __WXMAC__ - wxFileName fn(file) ; - fn.MacSetDefaultTypeAndCreator() ; -#endif - return true; -} - -bool wxDocument::OnOpenDocument(const wxString& file) -{ - if (!OnSaveModified()) - return false; - - if ( !DoOpenDocument(file) ) - return false; - - SetFilename(file, true); - Modify(false); - m_savedYet = true; - - UpdateAllViews(); - - return true; -} - -#if wxUSE_STD_IOSTREAM -wxSTD istream& wxDocument::LoadObject(wxSTD istream& stream) -#else -wxInputStream& wxDocument::LoadObject(wxInputStream& stream) -#endif -{ - return stream; -} - -#if wxUSE_STD_IOSTREAM -wxSTD ostream& wxDocument::SaveObject(wxSTD ostream& stream) -#else -wxOutputStream& wxDocument::SaveObject(wxOutputStream& stream) -#endif -{ - return stream; -} - -bool wxDocument::Revert() -{ - return false; -} - - -// Get title, or filename if no title, else unnamed -bool wxDocument::GetPrintableName(wxString& buf) const -{ - if (!m_documentTitle.empty()) - { - buf = m_documentTitle; - return true; - } - else if (!m_documentFile.empty()) - { - buf = wxFileNameFromPath(m_documentFile); - return true; - } - else - { - buf = _("unnamed"); - return true; - } -} - -wxWindow *wxDocument::GetDocumentWindow() const -{ - wxView *view = GetFirstView(); - if (view) - return view->GetFrame(); - else - return wxTheApp->GetTopWindow(); -} - -wxCommandProcessor *wxDocument::OnCreateCommandProcessor() -{ - return new wxCommandProcessor; -} - -// true if safe to close -bool wxDocument::OnSaveModified() -{ - if (IsModified()) - { - wxString title; - GetPrintableName(title); - - wxString msgTitle; - if (!wxTheApp->GetAppName().empty()) - msgTitle = wxTheApp->GetAppName(); - else - msgTitle = wxString(_("Warning")); - - wxString prompt; - prompt.Printf(_("Do you want to save changes to document %s?"), - (const wxChar *)title); - int res = wxMessageBox(prompt, msgTitle, - wxYES_NO|wxCANCEL|wxICON_QUESTION, - GetDocumentWindow()); - if (res == wxNO) - { - Modify(false); - return true; - } - else if (res == wxYES) - return Save(); - else if (res == wxCANCEL) - return false; - } - return true; -} - -bool wxDocument::Draw(wxDC& WXUNUSED(context)) -{ - return true; -} - -bool wxDocument::AddView(wxView *view) -{ - if (!m_documentViews.Member(view)) - { - m_documentViews.Append(view); - OnChangedViewList(); - } - return true; -} - -bool wxDocument::RemoveView(wxView *view) -{ - (void)m_documentViews.DeleteObject(view); - OnChangedViewList(); - return true; -} - -bool wxDocument::OnCreate(const wxString& WXUNUSED(path), long flags) -{ - if (GetDocumentTemplate()->CreateView(this, flags)) - return true; - else - return false; -} - -// Called after a view is added or removed. -// The default implementation deletes the document if -// there are no more views. -void wxDocument::OnChangedViewList() -{ - if (m_documentViews.GetCount() == 0) - { - if (OnSaveModified()) - { - delete this; - } - } -} - -void wxDocument::UpdateAllViews(wxView *sender, wxObject *hint) -{ - wxList::compatibility_iterator node = m_documentViews.GetFirst(); - while (node) - { - wxView *view = (wxView *)node->GetData(); - if (view != sender) - view->OnUpdate(sender, hint); - node = node->GetNext(); - } -} - -void wxDocument::NotifyClosing() -{ - wxList::compatibility_iterator node = m_documentViews.GetFirst(); - while (node) - { - wxView *view = (wxView *)node->GetData(); - view->OnClosingDocument(); - node = node->GetNext(); - } -} - -void wxDocument::SetFilename(const wxString& filename, bool notifyViews) -{ - m_documentFile = filename; - if ( notifyViews ) - { - // Notify the views that the filename has changed - wxList::compatibility_iterator node = m_documentViews.GetFirst(); - while (node) - { - wxView *view = (wxView *)node->GetData(); - view->OnChangeFilename(); - node = node->GetNext(); - } - } -} - -bool wxDocument::DoSaveDocument(const wxString& file) -{ - wxString msgTitle; - if (!wxTheApp->GetAppName().empty()) - msgTitle = wxTheApp->GetAppName(); - else - msgTitle = wxString(_("File error")); - -#if wxUSE_STD_IOSTREAM - wxSTD ofstream store(file.mb_str(), wxSTD ios::binary); - if (store.fail() || store.bad()) -#else - wxFileOutputStream store(file); - if (store.GetLastError() != wxSTREAM_NO_ERROR) -#endif - { - (void)wxMessageBox(_("Sorry, could not open this file for saving."), msgTitle, wxOK | wxICON_EXCLAMATION, - GetDocumentWindow()); - // Saving error - return false; - } - if (!SaveObject(store)) - { - (void)wxMessageBox(_("Sorry, could not save this file."), msgTitle, wxOK | wxICON_EXCLAMATION, - GetDocumentWindow()); - // Saving error - return false; - } - - return true; -} - -bool wxDocument::DoOpenDocument(const wxString& file) -{ -#if wxUSE_STD_IOSTREAM - wxSTD ifstream store(file.mb_str(), wxSTD ios::binary); - if (!store.fail() && !store.bad()) -#else - wxFileInputStream store(file); - if (store.GetLastError() == wxSTREAM_NO_ERROR) -#endif - { -#if wxUSE_STD_IOSTREAM - LoadObject(store); - if ( !!store || store.eof() ) -#else - int res = LoadObject(store).GetLastError(); - if ( res == wxSTREAM_NO_ERROR || res == wxSTREAM_EOF ) -#endif - return true; - } - - wxLogError(_("Sorry, could not open this file.")); - return false; -} - - -// ---------------------------------------------------------------------------- -// Document view -// ---------------------------------------------------------------------------- - -wxView::wxView() -{ - m_viewDocument = (wxDocument*) NULL; - - m_viewFrame = (wxFrame *) NULL; -} - -wxView::~wxView() -{ - if (m_viewDocument && GetDocumentManager()) - GetDocumentManager()->ActivateView(this, false); - if (m_viewDocument) - m_viewDocument->RemoveView(this); -} - -// Extend event processing to search the document's event table -bool wxView::ProcessEvent(wxEvent& event) -{ - if ( !GetDocument() || !GetDocument()->ProcessEvent(event) ) - return wxEvtHandler::ProcessEvent(event); - - return true; -} - -void wxView::OnActivateView(bool WXUNUSED(activate), wxView *WXUNUSED(activeView), wxView *WXUNUSED(deactiveView)) -{ -} - -void wxView::OnPrint(wxDC *dc, wxObject *WXUNUSED(info)) -{ - OnDraw(dc); -} - -void wxView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint)) -{ -} - -void wxView::OnChangeFilename() -{ - // GetFrame can return wxWindow rather than wxTopLevelWindow due to - // generic MDI implementation so use SetLabel rather than SetTitle. - // It should cause SetTitle() for top level windows. - wxWindow *win = GetFrame(); - if (!win) return; - - wxDocument *doc = GetDocument(); - if (!doc) return; - - wxString name; - doc->GetPrintableName(name); - win->SetLabel(name); -} - -void wxView::SetDocument(wxDocument *doc) -{ - m_viewDocument = doc; - if (doc) - doc->AddView(this); -} - -bool wxView::Close(bool deleteWindow) -{ - if (OnClose(deleteWindow)) - return true; - else - return false; -} - -void wxView::Activate(bool activate) -{ - if (GetDocument() && GetDocumentManager()) - { - OnActivateView(activate, this, GetDocumentManager()->GetCurrentView()); - GetDocumentManager()->ActivateView(this, activate); - } -} - -bool wxView::OnClose(bool WXUNUSED(deleteWindow)) -{ - return GetDocument() ? GetDocument()->Close() : true; -} - -#if wxUSE_PRINTING_ARCHITECTURE -wxPrintout *wxView::OnCreatePrintout() -{ - return new wxDocPrintout(this); -} -#endif // wxUSE_PRINTING_ARCHITECTURE - -// ---------------------------------------------------------------------------- -// wxDocTemplate -// ---------------------------------------------------------------------------- - -wxDocTemplate::wxDocTemplate(wxDocManager *manager, - const wxString& descr, - const wxString& filter, - const wxString& dir, - const wxString& ext, - const wxString& docTypeName, - const wxString& viewTypeName, - wxClassInfo *docClassInfo, - wxClassInfo *viewClassInfo, - long flags) -{ - m_documentManager = manager; - m_description = descr; - m_directory = dir; - m_defaultExt = ext; - m_fileFilter = filter; - m_flags = flags; - m_docTypeName = docTypeName; - m_viewTypeName = viewTypeName; - m_documentManager->AssociateTemplate(this); - - m_docClassInfo = docClassInfo; - m_viewClassInfo = viewClassInfo; -} - -wxDocTemplate::~wxDocTemplate() -{ - m_documentManager->DisassociateTemplate(this); -} - -// Tries to dynamically construct an object of the right class. -wxDocument *wxDocTemplate::CreateDocument(const wxString& path, long flags) -{ - wxDocument *doc = DoCreateDocument(); - if ( doc == NULL ) - return (wxDocument *) NULL; - - if (InitDocument(doc, path, flags)) - { - return doc; - } - else - { - return (wxDocument *) NULL; - } -} - -bool wxDocTemplate::InitDocument(wxDocument* doc, const wxString& path, long flags) -{ - doc->SetFilename(path); - doc->SetDocumentTemplate(this); - GetDocumentManager()->AddDocument(doc); - doc->SetCommandProcessor(doc->OnCreateCommandProcessor()); - - if (doc->OnCreate(path, flags)) - return true; - else - { - if (GetDocumentManager()->GetDocuments().Member(doc)) - doc->DeleteAllViews(); - return false; - } -} - -wxView *wxDocTemplate::CreateView(wxDocument *doc, long flags) -{ - wxView *view = DoCreateView(); - if ( view == NULL ) - return (wxView *) NULL; - - view->SetDocument(doc); - if (view->OnCreate(doc, flags)) - { - return view; - } - else - { - delete view; - return (wxView *) NULL; - } -} - -// The default (very primitive) format detection: check is the extension is -// that of the template -bool wxDocTemplate::FileMatchesTemplate(const wxString& path) -{ - wxStringTokenizer parser (GetFileFilter(), wxT(";")); - wxString anything = wxT ("*"); - while (parser.HasMoreTokens()) - { - wxString filter = parser.GetNextToken(); - wxString filterExt = FindExtension (filter); - if ( filter.IsSameAs (anything) || - filterExt.IsSameAs (anything) || - filterExt.IsSameAs (FindExtension (path)) ) - return true; - } - return GetDefaultExtension().IsSameAs(FindExtension(path)); -} - -wxDocument *wxDocTemplate::DoCreateDocument() -{ - if (!m_docClassInfo) - return (wxDocument *) NULL; - - return (wxDocument *)m_docClassInfo->CreateObject(); -} - -wxView *wxDocTemplate::DoCreateView() -{ - if (!m_viewClassInfo) - return (wxView *) NULL; - - return (wxView *)m_viewClassInfo->CreateObject(); -} - -// ---------------------------------------------------------------------------- -// wxDocManager -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxDocManager, wxEvtHandler) - EVT_MENU(wxID_OPEN, wxDocManager::OnFileOpen) - EVT_MENU(wxID_CLOSE, wxDocManager::OnFileClose) - EVT_MENU(wxID_CLOSE_ALL, wxDocManager::OnFileCloseAll) - EVT_MENU(wxID_REVERT, wxDocManager::OnFileRevert) - EVT_MENU(wxID_NEW, wxDocManager::OnFileNew) - EVT_MENU(wxID_SAVE, wxDocManager::OnFileSave) - EVT_MENU(wxID_SAVEAS, wxDocManager::OnFileSaveAs) - EVT_MENU(wxID_UNDO, wxDocManager::OnUndo) - EVT_MENU(wxID_REDO, wxDocManager::OnRedo) - - EVT_UPDATE_UI(wxID_OPEN, wxDocManager::OnUpdateFileOpen) - EVT_UPDATE_UI(wxID_CLOSE, wxDocManager::OnUpdateFileClose) - EVT_UPDATE_UI(wxID_CLOSE_ALL, wxDocManager::OnUpdateFileClose) - EVT_UPDATE_UI(wxID_REVERT, wxDocManager::OnUpdateFileRevert) - EVT_UPDATE_UI(wxID_NEW, wxDocManager::OnUpdateFileNew) - EVT_UPDATE_UI(wxID_SAVE, wxDocManager::OnUpdateFileSave) - EVT_UPDATE_UI(wxID_SAVEAS, wxDocManager::OnUpdateFileSaveAs) - EVT_UPDATE_UI(wxID_UNDO, wxDocManager::OnUpdateUndo) - EVT_UPDATE_UI(wxID_REDO, wxDocManager::OnUpdateRedo) - -#if wxUSE_PRINTING_ARCHITECTURE - EVT_MENU(wxID_PRINT, wxDocManager::OnPrint) - EVT_MENU(wxID_PREVIEW, wxDocManager::OnPreview) - - EVT_UPDATE_UI(wxID_PRINT, wxDocManager::OnUpdatePrint) - EVT_UPDATE_UI(wxID_PREVIEW, wxDocManager::OnUpdatePreview) -#endif -END_EVENT_TABLE() - -wxDocManager* wxDocManager::sm_docManager = (wxDocManager*) NULL; - -wxDocManager::wxDocManager(long flags, bool initialize) -{ - m_defaultDocumentNameCounter = 1; - m_flags = flags; - m_currentView = (wxView *) NULL; - m_maxDocsOpen = 10000; - m_fileHistory = (wxFileHistory *) NULL; - if (initialize) - Initialize(); - sm_docManager = this; -} - -wxDocManager::~wxDocManager() -{ - Clear(); - if (m_fileHistory) - delete m_fileHistory; - sm_docManager = (wxDocManager*) NULL; -} - -// closes the specified document -bool wxDocManager::CloseDocument(wxDocument* doc, bool force) -{ - if (doc->Close() || force) - { - // Implicitly deletes the document when - // the last view is deleted - doc->DeleteAllViews(); - - // Check we're really deleted - if (m_docs.Member(doc)) - delete doc; - - return true; - } - return false; -} - -bool wxDocManager::CloseDocuments(bool force) -{ - wxList::compatibility_iterator node = m_docs.GetFirst(); - while (node) - { - wxDocument *doc = (wxDocument *)node->GetData(); - wxList::compatibility_iterator next = node->GetNext(); - - if (!CloseDocument(doc, force)) - return false; - - // This assumes that documents are not connected in - // any way, i.e. deleting one document does NOT - // delete another. - node = next; - } - return true; -} - -bool wxDocManager::Clear(bool force) -{ - if (!CloseDocuments(force)) - return false; - - m_currentView = NULL; - - wxList::compatibility_iterator node = m_templates.GetFirst(); - while (node) - { - wxDocTemplate *templ = (wxDocTemplate*) node->GetData(); - wxList::compatibility_iterator next = node->GetNext(); - delete templ; - node = next; - } - return true; -} - -bool wxDocManager::Initialize() -{ - m_fileHistory = OnCreateFileHistory(); - return true; -} - -wxFileHistory *wxDocManager::OnCreateFileHistory() -{ - return new wxFileHistory; -} - -void wxDocManager::OnFileClose(wxCommandEvent& WXUNUSED(event)) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - return; - if (doc->Close()) - { - doc->DeleteAllViews(); - if (m_docs.Member(doc)) - delete doc; - } -} - -void wxDocManager::OnFileCloseAll(wxCommandEvent& WXUNUSED(event)) -{ - CloseDocuments(false); -} - -void wxDocManager::OnFileNew(wxCommandEvent& WXUNUSED(event)) -{ - CreateDocument( wxEmptyString, wxDOC_NEW ); -} - -void wxDocManager::OnFileOpen(wxCommandEvent& WXUNUSED(event)) -{ - if ( !CreateDocument( wxEmptyString, 0) ) - { - OnOpenFileFailure(); - } -} - -void wxDocManager::OnFileRevert(wxCommandEvent& WXUNUSED(event)) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - return; - doc->Revert(); -} - -void wxDocManager::OnFileSave(wxCommandEvent& WXUNUSED(event)) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - return; - doc->Save(); -} - -void wxDocManager::OnFileSaveAs(wxCommandEvent& WXUNUSED(event)) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - return; - doc->SaveAs(); -} - -void wxDocManager::OnPrint(wxCommandEvent& WXUNUSED(event)) -{ -#if wxUSE_PRINTING_ARCHITECTURE - wxView *view = GetCurrentView(); - if (!view) - return; - - wxPrintout *printout = view->OnCreatePrintout(); - if (printout) - { - wxPrinter printer; - printer.Print(view->GetFrame(), printout, true); - - delete printout; - } -#endif // wxUSE_PRINTING_ARCHITECTURE -} - -void wxDocManager::OnPreview(wxCommandEvent& WXUNUSED(event)) -{ -#if wxUSE_PRINTING_ARCHITECTURE - wxBusyCursor busy; - wxView *view = GetCurrentView(); - if (!view) - return; - - wxPrintout *printout = view->OnCreatePrintout(); - if (printout) - { - // Pass two printout objects: for preview, and possible printing. - wxPrintPreviewBase *preview = new wxPrintPreview(printout, view->OnCreatePrintout()); - if ( !preview->Ok() ) - { - delete preview; - wxMessageBox( _("Sorry, print preview needs a printer to be installed.") ); - return; - } - - wxPreviewFrame *frame = new wxPreviewFrame(preview, (wxFrame *)wxTheApp->GetTopWindow(), _("Print Preview"), - wxPoint(100, 100), wxSize(600, 650)); - frame->Centre(wxBOTH); - frame->Initialize(); - frame->Show(true); - } -#endif // wxUSE_PRINTING_ARCHITECTURE -} - -void wxDocManager::OnUndo(wxCommandEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - return; - if (doc->GetCommandProcessor()) - doc->GetCommandProcessor()->Undo(); - else - event.Skip(); -} - -void wxDocManager::OnRedo(wxCommandEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - return; - if (doc->GetCommandProcessor()) - doc->GetCommandProcessor()->Redo(); - else - event.Skip(); -} - -// Handlers for UI update commands - -void wxDocManager::OnUpdateFileOpen(wxUpdateUIEvent& event) -{ - event.Enable( true ); -} - -void wxDocManager::OnUpdateFileClose(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - event.Enable( (doc != (wxDocument*) NULL) ); -} - -void wxDocManager::OnUpdateFileRevert(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - event.Enable( (doc != (wxDocument*) NULL) ); -} - -void wxDocManager::OnUpdateFileNew(wxUpdateUIEvent& event) -{ - event.Enable( true ); -} - -void wxDocManager::OnUpdateFileSave(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - event.Enable( doc && doc->IsModified() ); -} - -void wxDocManager::OnUpdateFileSaveAs(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - event.Enable( (doc != (wxDocument*) NULL) ); -} - -void wxDocManager::OnUpdateUndo(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - event.Enable(false); - else if (!doc->GetCommandProcessor()) - event.Skip(); - else - { - event.Enable( doc->GetCommandProcessor()->CanUndo() ); - doc->GetCommandProcessor()->SetMenuStrings(); - } -} - -void wxDocManager::OnUpdateRedo(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - if (!doc) - event.Enable(false); - else if (!doc->GetCommandProcessor()) - event.Skip(); - else - { - event.Enable( doc->GetCommandProcessor()->CanRedo() ); - doc->GetCommandProcessor()->SetMenuStrings(); - } -} - -void wxDocManager::OnUpdatePrint(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - event.Enable( (doc != (wxDocument*) NULL) ); -} - -void wxDocManager::OnUpdatePreview(wxUpdateUIEvent& event) -{ - wxDocument *doc = GetCurrentDocument(); - event.Enable( (doc != (wxDocument*) NULL) ); -} - -wxView *wxDocManager::GetCurrentView() const -{ - if (m_currentView) - return m_currentView; - if (m_docs.GetCount() == 1) - { - wxDocument* doc = (wxDocument*) m_docs.GetFirst()->GetData(); - return doc->GetFirstView(); - } - return (wxView *) NULL; -} - -// Extend event processing to search the view's event table -bool wxDocManager::ProcessEvent(wxEvent& event) -{ - wxView* view = GetCurrentView(); - if (view) - { - if (view->ProcessEvent(event)) - return true; - } - return wxEvtHandler::ProcessEvent(event); -} - -wxDocument *wxDocManager::CreateDocument(const wxString& path, long flags) -{ - wxDocTemplate **templates = new wxDocTemplate *[m_templates.GetCount()]; - int n = 0; - - for (size_t i = 0; i < m_templates.GetCount(); i++) - { - wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Item(i)->GetData()); - if (temp->IsVisible()) - { - templates[n] = temp; - n ++; - } - } - if (n == 0) - { - delete[] templates; - return (wxDocument *) NULL; - } - - wxDocument* docToClose = NULL; - - // If we've reached the max number of docs, close the - // first one. - if ( (int)GetDocuments().GetCount() >= m_maxDocsOpen ) - { - wxDocument *doc = (wxDocument *)GetDocuments().GetFirst()->GetData(); - docToClose = doc; - } - - // New document: user chooses a template, unless there's only one. - if (flags & wxDOC_NEW) - { - if (n == 1) - { - if (docToClose) - { - if (!CloseDocument(docToClose, false)) - { - delete[] templates; - return NULL; - } - } - - wxDocTemplate *temp = templates[0]; - delete[] templates; - wxDocument *newDoc = temp->CreateDocument(path, flags); - - if (newDoc) - { - newDoc->SetDocumentName(temp->GetDocumentName()); - newDoc->SetDocumentTemplate(temp); - if (!newDoc->OnNewDocument() ) - { - // Document is implicitly deleted by DeleteAllViews - newDoc->DeleteAllViews(); - return NULL; - } - } - return newDoc; - } - - wxDocTemplate *temp = SelectDocumentType(templates, n); - delete[] templates; - if (temp) - { - if (docToClose) - { - if (!CloseDocument(docToClose, false)) - { - return NULL; - } - } - - wxDocument *newDoc = temp->CreateDocument(path, flags); - - if (newDoc) - { - newDoc->SetDocumentName(temp->GetDocumentName()); - newDoc->SetDocumentTemplate(temp); - if (!newDoc->OnNewDocument() ) - { - // Document is implicitly deleted by DeleteAllViews - newDoc->DeleteAllViews(); - return NULL; - } - } - return newDoc; - } - else - return (wxDocument *) NULL; - } - - // Existing document - wxDocTemplate *temp; - - wxString path2 = path; - - if (flags & wxDOC_SILENT) - { - temp = FindTemplateForPath(path2); - if (!temp) - { - // Since we do not add files with non-default extensions to the FileHistory this - // can only happen if the application changes the allowed templates in runtime. - (void)wxMessageBox(_("Sorry, the format for this file is unknown."), - _("Open File"), - wxOK | wxICON_EXCLAMATION, wxFindSuitableParent()); - } - } - else - temp = SelectDocumentPath(templates, n, path2, flags); - - delete[] templates; - - if (temp) - { - if (docToClose) - { - if (!CloseDocument(docToClose, false)) - { - return NULL; - } - } - - //see if this file is already open - for (size_t i = 0; i < GetDocuments().GetCount(); ++i) - { - wxDocument* currentDoc = (wxDocument*)(GetDocuments().Item(i)->GetData()); -#ifdef __WXMSW__ - //file paths are case-insensitive on Windows - if (path2.CmpNoCase(currentDoc->GetFilename()) == 0) -#else - if (path2.Cmp(currentDoc->GetFilename()) == 0) -#endif - { - //file already open. Just activate it and return - if (currentDoc->GetFirstView()) - { - ActivateView(currentDoc->GetFirstView(), true); - if (currentDoc->GetDocumentWindow()) - currentDoc->GetDocumentWindow()->SetFocus(); - return currentDoc; - } - } - } - - wxDocument *newDoc = temp->CreateDocument(path2, flags); - if (newDoc) - { - newDoc->SetDocumentName(temp->GetDocumentName()); - newDoc->SetDocumentTemplate(temp); - if (!newDoc->OnOpenDocument(path2)) - { - newDoc->DeleteAllViews(); - // delete newDoc; // Implicitly deleted by DeleteAllViews - return (wxDocument *) NULL; - } - // A file that doesn't use the default extension of its document - // template cannot be opened via the FileHistory, so we do not - // add it. - if (temp->FileMatchesTemplate(path2)) - AddFileToHistory(path2); - } - return newDoc; - } - - return (wxDocument *) NULL; -} - -wxView *wxDocManager::CreateView(wxDocument *doc, long flags) -{ - wxDocTemplate **templates = new wxDocTemplate *[m_templates.GetCount()]; - int n =0; - - for (size_t i = 0; i < m_templates.GetCount(); i++) - { - wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Item(i)->GetData()); - if (temp->IsVisible()) - { - if (temp->GetDocumentName() == doc->GetDocumentName()) - { - templates[n] = temp; - n ++; - } - } - } - if (n == 0) - { - delete[] templates; - return (wxView *) NULL; - } - if (n == 1) - { - wxDocTemplate *temp = templates[0]; - delete[] templates; - wxView *view = temp->CreateView(doc, flags); - if (view) - view->SetViewName(temp->GetViewName()); - return view; - } - - wxDocTemplate *temp = SelectViewType(templates, n); - delete[] templates; - if (temp) - { - wxView *view = temp->CreateView(doc, flags); - if (view) - view->SetViewName(temp->GetViewName()); - return view; - } - else - return (wxView *) NULL; -} - -// Not yet implemented -void wxDocManager::DeleteTemplate(wxDocTemplate *WXUNUSED(temp), long WXUNUSED(flags)) -{ -} - -// Not yet implemented -bool wxDocManager::FlushDoc(wxDocument *WXUNUSED(doc)) -{ - return false; -} - -wxDocument *wxDocManager::GetCurrentDocument() const -{ - wxView *view = GetCurrentView(); - if (view) - return view->GetDocument(); - else - return (wxDocument *) NULL; -} - -// Make a default document name -bool wxDocManager::MakeDefaultName(wxString& name) -{ - name.Printf(_("unnamed%d"), m_defaultDocumentNameCounter); - m_defaultDocumentNameCounter++; - - return true; -} - -// Make a frame title (override this to do something different) -// If docName is empty, a document is not currently active. -wxString wxDocManager::MakeFrameTitle(wxDocument* doc) -{ - wxString appName = wxTheApp->GetAppName(); - wxString title; - if (!doc) - title = appName; - else - { - wxString docName; - doc->GetPrintableName(docName); - title = docName + wxString(_(" - ")) + appName; - } - return title; -} - - -// Not yet implemented -wxDocTemplate *wxDocManager::MatchTemplate(const wxString& WXUNUSED(path)) -{ - return (wxDocTemplate *) NULL; -} - -// File history management -void wxDocManager::AddFileToHistory(const wxString& file) -{ - if (m_fileHistory) - m_fileHistory->AddFileToHistory(file); -} - -void wxDocManager::RemoveFileFromHistory(size_t i) -{ - if (m_fileHistory) - m_fileHistory->RemoveFileFromHistory(i); -} - -wxString wxDocManager::GetHistoryFile(size_t i) const -{ - wxString histFile; - - if (m_fileHistory) - histFile = m_fileHistory->GetHistoryFile(i); - - return histFile; -} - -void wxDocManager::FileHistoryUseMenu(wxMenu *menu) -{ - if (m_fileHistory) - m_fileHistory->UseMenu(menu); -} - -void wxDocManager::FileHistoryRemoveMenu(wxMenu *menu) -{ - if (m_fileHistory) - m_fileHistory->RemoveMenu(menu); -} - -#if wxUSE_CONFIG -void wxDocManager::FileHistoryLoad(wxConfigBase& config) -{ - if (m_fileHistory) - m_fileHistory->Load(config); -} - -void wxDocManager::FileHistorySave(wxConfigBase& config) -{ - if (m_fileHistory) - m_fileHistory->Save(config); -} -#endif - -void wxDocManager::FileHistoryAddFilesToMenu(wxMenu* menu) -{ - if (m_fileHistory) - m_fileHistory->AddFilesToMenu(menu); -} - -void wxDocManager::FileHistoryAddFilesToMenu() -{ - if (m_fileHistory) - m_fileHistory->AddFilesToMenu(); -} - -size_t wxDocManager::GetHistoryFilesCount() const -{ - return m_fileHistory ? m_fileHistory->GetCount() : 0; -} - - -// Find out the document template via matching in the document file format -// against that of the template -wxDocTemplate *wxDocManager::FindTemplateForPath(const wxString& path) -{ - wxDocTemplate *theTemplate = (wxDocTemplate *) NULL; - - // Find the template which this extension corresponds to - for (size_t i = 0; i < m_templates.GetCount(); i++) - { - wxDocTemplate *temp = (wxDocTemplate *)m_templates.Item(i)->GetData(); - if ( temp->FileMatchesTemplate(path) ) - { - theTemplate = temp; - break; - } - } - return theTemplate; -} - -// Try to get a more suitable parent frame than the top window, -// for selection dialogs. Otherwise you may get an unexpected -// window being activated when a dialog is shown. -static wxWindow* wxFindSuitableParent() -{ - wxWindow* parent = wxTheApp->GetTopWindow(); - - wxWindow* focusWindow = wxWindow::FindFocus(); - if (focusWindow) - { - while (focusWindow && - !focusWindow->IsKindOf(CLASSINFO(wxDialog)) && - !focusWindow->IsKindOf(CLASSINFO(wxFrame))) - - focusWindow = focusWindow->GetParent(); - - if (focusWindow) - parent = focusWindow; - } - return parent; -} - -// Prompts user to open a file, using file specs in templates. -// Must extend the file selector dialog or implement own; OR -// match the extension to the template extension. - -wxDocTemplate *wxDocManager::SelectDocumentPath(wxDocTemplate **templates, -#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) - int noTemplates, -#else - int WXUNUSED(noTemplates), -#endif - wxString& path, - long WXUNUSED(flags), - bool WXUNUSED(save)) -{ - // We can only have multiple filters in Windows and GTK -#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) - wxString descrBuf; - - int i; - for (i = 0; i < noTemplates; i++) - { - if (templates[i]->IsVisible()) - { - // add a '|' to separate this filter from the previous one - if ( !descrBuf.empty() ) - descrBuf << wxT('|'); - - descrBuf << templates[i]->GetDescription() - << wxT(" (") << templates[i]->GetFileFilter() << wxT(") |") - << templates[i]->GetFileFilter(); - } - } -#else - wxString descrBuf = wxT("*.*"); -#endif - - int FilterIndex = -1; - - wxWindow* parent = wxFindSuitableParent(); - - wxString pathTmp = wxFileSelectorEx(_("Select a file"), - m_lastDirectory, - wxEmptyString, - &FilterIndex, - descrBuf, - 0, - parent); - - wxDocTemplate *theTemplate = (wxDocTemplate *)NULL; - if (!pathTmp.empty()) - { - if (!wxFileExists(pathTmp)) - { - wxString msgTitle; - if (!wxTheApp->GetAppName().empty()) - msgTitle = wxTheApp->GetAppName(); - else - msgTitle = wxString(_("File error")); - - (void)wxMessageBox(_("Sorry, could not open this file."), msgTitle, wxOK | wxICON_EXCLAMATION, - parent); - - path = wxEmptyString; - return (wxDocTemplate *) NULL; - } - m_lastDirectory = wxPathOnly(pathTmp); - - path = pathTmp; - - // first choose the template using the extension, if this fails (i.e. - // wxFileSelectorEx() didn't fill it), then use the path - if ( FilterIndex != -1 ) - theTemplate = templates[FilterIndex]; - if ( !theTemplate ) - theTemplate = FindTemplateForPath(path); - if ( !theTemplate ) - { - // Since we do not add files with non-default extensions to the FileHistory this - // can only happen if the application changes the allowed templates in runtime. - (void)wxMessageBox(_("Sorry, the format for this file is unknown."), - _("Open File"), - wxOK | wxICON_EXCLAMATION, wxFindSuitableParent()); - } - } - else - { - path = wxEmptyString; - } - - return theTemplate; -} - -wxDocTemplate *wxDocManager::SelectDocumentType(wxDocTemplate **templates, - int noTemplates, bool sort) -{ - wxArrayString strings; - wxDocTemplate **data = new wxDocTemplate *[noTemplates]; - int i; - int n = 0; - - for (i = 0; i < noTemplates; i++) - { - if (templates[i]->IsVisible()) - { - int j; - bool want = true; - for (j = 0; j < n; j++) - { - //filter out NOT unique documents + view combinations - if ( templates[i]->m_docTypeName == data[j]->m_docTypeName && - templates[i]->m_viewTypeName == data[j]->m_viewTypeName - ) - want = false; - } - - if ( want ) - { - strings.Add(templates[i]->m_description); - - data[n] = templates[i]; - n ++; - } - } - } // for - - if (sort) - { - strings.Sort(); // ascending sort - // Yes, this will be slow, but template lists - // are typically short. - int j; - n = strings.Count(); - for (i = 0; i < n; i++) - { - for (j = 0; j < noTemplates; j++) - { - if (strings[i] == templates[j]->m_description) - data[i] = templates[j]; - } - } - } - - wxDocTemplate *theTemplate; - - switch ( n ) - { - case 0: - // no visible templates, hence nothing to choose from - theTemplate = NULL; - break; - - case 1: - // don't propose the user to choose if he heas no choice - theTemplate = data[0]; - break; - - default: - // propose the user to choose one of several - theTemplate = (wxDocTemplate *)wxGetSingleChoiceData - ( - _("Select a document template"), - _("Templates"), - strings, - (void **)data, - wxFindSuitableParent() - ); - } - - delete[] data; - - return theTemplate; -} - -wxDocTemplate *wxDocManager::SelectViewType(wxDocTemplate **templates, - int noTemplates, bool sort) -{ - wxArrayString strings; - wxDocTemplate **data = new wxDocTemplate *[noTemplates]; - int i; - int n = 0; - - for (i = 0; i < noTemplates; i++) - { - wxDocTemplate *templ = templates[i]; - if ( templ->IsVisible() && !templ->GetViewName().empty() ) - { - int j; - bool want = true; - for (j = 0; j < n; j++) - { - //filter out NOT unique views - if ( templates[i]->m_viewTypeName == data[j]->m_viewTypeName ) - want = false; - } - - if ( want ) - { - strings.Add(templ->m_viewTypeName); - data[n] = templ; - n ++; - } - } - } - - if (sort) - { - strings.Sort(); // ascending sort - // Yes, this will be slow, but template lists - // are typically short. - int j; - n = strings.Count(); - for (i = 0; i < n; i++) - { - for (j = 0; j < noTemplates; j++) - { - if (strings[i] == templates[j]->m_viewTypeName) - data[i] = templates[j]; - } - } - } - - wxDocTemplate *theTemplate; - - // the same logic as above - switch ( n ) - { - case 0: - theTemplate = (wxDocTemplate *)NULL; - break; - - case 1: - theTemplate = data[0]; - break; - - default: - theTemplate = (wxDocTemplate *)wxGetSingleChoiceData - ( - _("Select a document view"), - _("Views"), - strings, - (void **)data, - wxFindSuitableParent() - ); - - } - - delete[] data; - return theTemplate; -} - -void wxDocManager::AssociateTemplate(wxDocTemplate *temp) -{ - if (!m_templates.Member(temp)) - m_templates.Append(temp); -} - -void wxDocManager::DisassociateTemplate(wxDocTemplate *temp) -{ - m_templates.DeleteObject(temp); -} - -// Add and remove a document from the manager's list -void wxDocManager::AddDocument(wxDocument *doc) -{ - if (!m_docs.Member(doc)) - m_docs.Append(doc); -} - -void wxDocManager::RemoveDocument(wxDocument *doc) -{ - m_docs.DeleteObject(doc); -} - -// Views or windows should inform the document manager -// when a view is going in or out of focus -void wxDocManager::ActivateView(wxView *view, bool activate) -{ - if ( activate ) - { - m_currentView = view; - } - else // deactivate - { - if ( m_currentView == view ) - { - // don't keep stale pointer - m_currentView = (wxView *) NULL; - } - } -} - -// ---------------------------------------------------------------------------- -// Default document child frame -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxDocChildFrame, wxFrame) - EVT_ACTIVATE(wxDocChildFrame::OnActivate) - EVT_CLOSE(wxDocChildFrame::OnCloseWindow) -END_EVENT_TABLE() - -wxDocChildFrame::wxDocChildFrame(wxDocument *doc, - wxView *view, - wxFrame *frame, - wxWindowID id, - const wxString& title, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) - : wxFrame(frame, id, title, pos, size, style, name) -{ - m_childDocument = doc; - m_childView = view; - if (view) - view->SetFrame(this); -} - -// Extend event processing to search the view's event table -bool wxDocChildFrame::ProcessEvent(wxEvent& event) -{ - if (m_childView) - m_childView->Activate(true); - - if ( !m_childView || ! m_childView->ProcessEvent(event) ) - { - // Only hand up to the parent if it's a menu command - if (!event.IsKindOf(CLASSINFO(wxCommandEvent)) || !GetParent() || !GetParent()->ProcessEvent(event)) - return wxEvtHandler::ProcessEvent(event); - else - return true; - } - else - return true; -} - -void wxDocChildFrame::OnActivate(wxActivateEvent& event) -{ - wxFrame::OnActivate(event); - - if (m_childView) - m_childView->Activate(event.GetActive()); -} - -void wxDocChildFrame::OnCloseWindow(wxCloseEvent& event) -{ - if (m_childView) - { - bool ans = event.CanVeto() - ? m_childView->Close(false) // false means don't delete associated window - : true; // Must delete. - - if (ans) - { - m_childView->Activate(false); - delete m_childView; - m_childView = (wxView *) NULL; - m_childDocument = (wxDocument *) NULL; - - this->Destroy(); - } - else - event.Veto(); - } - else - event.Veto(); -} - -// ---------------------------------------------------------------------------- -// Default parent frame -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxDocParentFrame, wxFrame) - EVT_MENU(wxID_EXIT, wxDocParentFrame::OnExit) - EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocParentFrame::OnMRUFile) - EVT_CLOSE(wxDocParentFrame::OnCloseWindow) -END_EVENT_TABLE() - -wxDocParentFrame::wxDocParentFrame() -{ - m_docManager = NULL; -} - -wxDocParentFrame::wxDocParentFrame(wxDocManager *manager, - wxFrame *frame, - wxWindowID id, - const wxString& title, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) - : wxFrame(frame, id, title, pos, size, style, name) -{ - m_docManager = manager; -} - -bool wxDocParentFrame::Create(wxDocManager *manager, - wxFrame *frame, - wxWindowID id, - const wxString& title, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - m_docManager = manager; - return base_type::Create(frame, id, title, pos, size, style, name); -} - -void wxDocParentFrame::OnExit(wxCommandEvent& WXUNUSED(event)) -{ - Close(); -} - -void wxDocParentFrame::OnMRUFile(wxCommandEvent& event) -{ - int n = event.GetId() - wxID_FILE1; // the index in MRU list - wxString filename(m_docManager->GetHistoryFile(n)); - if ( !filename.empty() ) - { - // verify that the file exists before doing anything else - if ( wxFile::Exists(filename) ) - { - // try to open it - if (!m_docManager->CreateDocument(filename, wxDOC_SILENT)) - { - // remove the file from the MRU list. The user should already be notified. - m_docManager->RemoveFileFromHistory(n); - - wxLogError(_("The file '%s' couldn't be opened.\nIt has been removed from the most recently used files list."), - filename.c_str()); - } - } - else - { - // remove the bogus filename from the MRU list and notify the user - // about it - m_docManager->RemoveFileFromHistory(n); - - wxLogError(_("The file '%s' doesn't exist and couldn't be opened.\nIt has been removed from the most recently used files list."), - filename.c_str()); - } - } -} - -// Extend event processing to search the view's event table -bool wxDocParentFrame::ProcessEvent(wxEvent& event) -{ - // Try the document manager, then do default processing - if (!m_docManager || !m_docManager->ProcessEvent(event)) - return wxEvtHandler::ProcessEvent(event); - else - return true; -} - -// Define the behaviour for the frame closing -// - must delete all frames except for the main one. -void wxDocParentFrame::OnCloseWindow(wxCloseEvent& event) -{ - if ( m_docManager && !m_docManager->Clear(!event.CanVeto()) ) - { - // The user decided not to close finally, abort. - event.Veto(); - } - else - { - this->Destroy(); - } -} - -#if wxUSE_PRINTING_ARCHITECTURE - -wxDocPrintout::wxDocPrintout(wxView *view, const wxString& title) - : wxPrintout(title) -{ - m_printoutView = view; -} - -bool wxDocPrintout::OnPrintPage(int WXUNUSED(page)) -{ - wxDC *dc = GetDC(); - - // Get the logical pixels per inch of screen and printer - int ppiScreenX, ppiScreenY; - GetPPIScreen(&ppiScreenX, &ppiScreenY); - wxUnusedVar(ppiScreenY); - int ppiPrinterX, ppiPrinterY; - GetPPIPrinter(&ppiPrinterX, &ppiPrinterY); - wxUnusedVar(ppiPrinterY); - - // This scales the DC so that the printout roughly represents the - // the screen scaling. The text point size _should_ be the right size - // but in fact is too small for some reason. This is a detail that will - // need to be addressed at some point but can be fudged for the - // moment. - float scale = (float)((float)ppiPrinterX/(float)ppiScreenX); - - // Now we have to check in case our real page size is reduced - // (e.g. because we're drawing to a print preview memory DC) - int pageWidth, pageHeight; - int w, h; - dc->GetSize(&w, &h); - GetPageSizePixels(&pageWidth, &pageHeight); - wxUnusedVar(pageHeight); - - // If printer pageWidth == current DC width, then this doesn't - // change. But w might be the preview bitmap width, so scale down. - float overallScale = scale * (float)(w/(float)pageWidth); - dc->SetUserScale(overallScale, overallScale); - - if (m_printoutView) - { - m_printoutView->OnDraw(dc); - } - return true; -} - -bool wxDocPrintout::HasPage(int pageNum) -{ - return (pageNum == 1); -} - -bool wxDocPrintout::OnBeginDocument(int startPage, int endPage) -{ - if (!wxPrintout::OnBeginDocument(startPage, endPage)) - return false; - - return true; -} - -void wxDocPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo) -{ - *minPage = 1; - *maxPage = 1; - *selPageFrom = 1; - *selPageTo = 1; -} - -#endif // wxUSE_PRINTING_ARCHITECTURE - -// ---------------------------------------------------------------------------- -// File history processor -// ---------------------------------------------------------------------------- - -static inline wxChar* MYcopystring(const wxString& s) -{ - wxChar* copy = new wxChar[s.length() + 1]; - return wxStrcpy(copy, s.c_str()); -} - -static inline wxChar* MYcopystring(const wxChar* s) -{ - wxChar* copy = new wxChar[wxStrlen(s) + 1]; - return wxStrcpy(copy, s); -} - -wxFileHistory::wxFileHistory(size_t maxFiles, wxWindowID idBase) -{ - m_fileMaxFiles = maxFiles; - m_idBase = idBase; - m_fileHistoryN = 0; - m_fileHistory = new wxChar *[m_fileMaxFiles]; -} - -wxFileHistory::~wxFileHistory() -{ - size_t i; - for (i = 0; i < m_fileHistoryN; i++) - delete[] m_fileHistory[i]; - delete[] m_fileHistory; -} - -// File history management -void wxFileHistory::AddFileToHistory(const wxString& file) -{ - size_t i; - - // Check we don't already have this file - for (i = 0; i < m_fileHistoryN; i++) - { -#if defined( __WXMSW__ ) // Add any other OSes with case insensitive file names - wxString testString; - if ( m_fileHistory[i] ) - testString = m_fileHistory[i]; - if ( m_fileHistory[i] && ( file.Lower() == testString.Lower() ) ) -#else - if ( m_fileHistory[i] && ( file == m_fileHistory[i] ) ) -#endif - { - // we do have it, move it to the top of the history - RemoveFileFromHistory (i); - AddFileToHistory (file); - return; - } - } - - // if we already have a full history, delete the one at the end - if ( m_fileMaxFiles == m_fileHistoryN ) - { - RemoveFileFromHistory (m_fileHistoryN - 1); - AddFileToHistory (file); - return; - } - - // Add to the project file history: - // Move existing files (if any) down so we can insert file at beginning. - if (m_fileHistoryN < m_fileMaxFiles) - { - wxList::compatibility_iterator node = m_fileMenus.GetFirst(); - while (node) - { - wxMenu* menu = (wxMenu*) node->GetData(); - if ( m_fileHistoryN == 0 && menu->GetMenuItemCount() ) - { - menu->AppendSeparator(); - } - menu->Append(m_idBase+m_fileHistoryN, _("[EMPTY]")); - node = node->GetNext(); - } - m_fileHistoryN ++; - } - // Shuffle filenames down - for (i = (m_fileHistoryN-1); i > 0; i--) - { - m_fileHistory[i] = m_fileHistory[i-1]; - } - m_fileHistory[0] = MYcopystring(file); - - // this is the directory of the last opened file - wxString pathCurrent; - wxSplitPath( m_fileHistory[0], &pathCurrent, NULL, NULL ); - for (i = 0; i < m_fileHistoryN; i++) - { - if ( m_fileHistory[i] ) - { - // if in same directory just show the filename; otherwise the full - // path - wxString pathInMenu, path, filename, ext; - wxSplitPath( m_fileHistory[i], &path, &filename, &ext ); - if ( path == pathCurrent ) - { - pathInMenu = filename; - if ( !ext.empty() ) - pathInMenu = pathInMenu + wxFILE_SEP_EXT + ext; - } - else - { - // absolute path; could also set relative path - pathInMenu = m_fileHistory[i]; - } - - // we need to quote '&' characters which are used for mnemonics - pathInMenu.Replace(_T("&"), _T("&&")); - wxString buf; - buf.Printf(s_MRUEntryFormat, i + 1, pathInMenu.c_str()); - wxList::compatibility_iterator node = m_fileMenus.GetFirst(); - while (node) - { - wxMenu* menu = (wxMenu*) node->GetData(); - menu->SetLabel(m_idBase + i, buf); - node = node->GetNext(); - } - } - } -} - -void wxFileHistory::RemoveFileFromHistory(size_t i) -{ - wxCHECK_RET( i < m_fileHistoryN, - wxT("invalid index in wxFileHistory::RemoveFileFromHistory") ); - - // delete the element from the array (could use memmove() too...) - delete [] m_fileHistory[i]; - - size_t j; - for ( j = i; j < m_fileHistoryN - 1; j++ ) - { - m_fileHistory[j] = m_fileHistory[j + 1]; - } - - wxList::compatibility_iterator node = m_fileMenus.GetFirst(); - while ( node ) - { - wxMenu* menu = (wxMenu*) node->GetData(); - - // shuffle filenames up - wxString buf; - for ( j = i; j < m_fileHistoryN - 1; j++ ) - { - buf.Printf(s_MRUEntryFormat, j + 1, m_fileHistory[j]); - menu->SetLabel(m_idBase + j, buf); - } - - node = node->GetNext(); - - // delete the last menu item which is unused now - wxWindowID lastItemId = m_idBase + wx_truncate_cast(wxWindowID, m_fileHistoryN) - 1; - if (menu->FindItem(lastItemId)) - { - menu->Delete(lastItemId); - } - - // delete the last separator too if no more files are left - if ( m_fileHistoryN == 1 ) - { - wxMenuItemList::compatibility_iterator nodeLast = menu->GetMenuItems().GetLast(); - if ( nodeLast ) - { - wxMenuItem *menuItem = nodeLast->GetData(); - if ( menuItem->IsSeparator() ) - { - menu->Delete(menuItem); - } - //else: should we search backwards for the last separator? - } - //else: menu is empty somehow - } - } - - m_fileHistoryN--; -} - -wxString wxFileHistory::GetHistoryFile(size_t i) const -{ - wxString s; - if ( i < m_fileHistoryN ) - { - s = m_fileHistory[i]; - } - else - { - wxFAIL_MSG( wxT("bad index in wxFileHistory::GetHistoryFile") ); - } - - return s; -} - -void wxFileHistory::UseMenu(wxMenu *menu) -{ - if (!m_fileMenus.Member(menu)) - m_fileMenus.Append(menu); -} - -void wxFileHistory::RemoveMenu(wxMenu *menu) -{ - m_fileMenus.DeleteObject(menu); -} - -#if wxUSE_CONFIG -void wxFileHistory::Load(wxConfigBase& config) -{ - m_fileHistoryN = 0; - wxString buf; - buf.Printf(wxT("file%d"), (int)m_fileHistoryN+1); - wxString historyFile; - while ((m_fileHistoryN < m_fileMaxFiles) && config.Read(buf, &historyFile) && (!historyFile.empty())) - { - m_fileHistory[m_fileHistoryN] = MYcopystring((const wxChar*) historyFile); - m_fileHistoryN ++; - buf.Printf(wxT("file%d"), (int)m_fileHistoryN+1); - historyFile = wxEmptyString; - } - AddFilesToMenu(); -} - -void wxFileHistory::Save(wxConfigBase& config) -{ - size_t i; - for (i = 0; i < m_fileMaxFiles; i++) - { - wxString buf; - buf.Printf(wxT("file%d"), (int)i+1); - if (i < m_fileHistoryN) - config.Write(buf, wxString(m_fileHistory[i])); - else - config.Write(buf, wxEmptyString); - } -} -#endif // wxUSE_CONFIG - -void wxFileHistory::AddFilesToMenu() -{ - if (m_fileHistoryN > 0) - { - wxList::compatibility_iterator node = m_fileMenus.GetFirst(); - while (node) - { - wxMenu* menu = (wxMenu*) node->GetData(); - if (menu->GetMenuItemCount()) - { - menu->AppendSeparator(); - } - - size_t i; - for (i = 0; i < m_fileHistoryN; i++) - { - if (m_fileHistory[i]) - { - wxString buf; - buf.Printf(s_MRUEntryFormat, i+1, m_fileHistory[i]); - menu->Append(m_idBase+i, buf); - } - } - node = node->GetNext(); - } - } -} - -void wxFileHistory::AddFilesToMenu(wxMenu* menu) -{ - if (m_fileHistoryN > 0) - { - if (menu->GetMenuItemCount()) - { - menu->AppendSeparator(); - } - - size_t i; - for (i = 0; i < m_fileHistoryN; i++) - { - if (m_fileHistory[i]) - { - wxString buf; - buf.Printf(s_MRUEntryFormat, i+1, m_fileHistory[i]); - menu->Append(m_idBase+i, buf); - } - } - } -} - -// ---------------------------------------------------------------------------- -// Permits compatibility with existing file formats and functions that -// manipulate files directly -// ---------------------------------------------------------------------------- - -#if wxUSE_STD_IOSTREAM - -bool wxTransferFileToStream(const wxString& filename, wxSTD ostream& stream) -{ - wxFFile file(filename, _T("rb")); - if ( !file.IsOpened() ) - return false; - - char buf[4096]; - - size_t nRead; - do - { - nRead = file.Read(buf, WXSIZEOF(buf)); - if ( file.Error() ) - return false; - - stream.write(buf, nRead); - if ( !stream ) - return false; - } - while ( !file.Eof() ); - - return true; -} - -bool wxTransferStreamToFile(wxSTD istream& stream, const wxString& filename) -{ - wxFFile file(filename, _T("wb")); - if ( !file.IsOpened() ) - return false; - - char buf[4096]; - do - { - stream.read(buf, WXSIZEOF(buf)); - if ( !stream.bad() ) // fail may be set on EOF, don't use operator!() - { - if ( !file.Write(buf, stream.gcount()) ) - return false; - } - } - while ( !stream.eof() ); - - return true; -} - -#else // !wxUSE_STD_IOSTREAM - -bool wxTransferFileToStream(const wxString& filename, wxOutputStream& stream) -{ - wxFFile file(filename, _T("rb")); - if ( !file.IsOpened() ) - return false; - - char buf[4096]; - - size_t nRead; - do - { - nRead = file.Read(buf, WXSIZEOF(buf)); - if ( file.Error() ) - return false; - - stream.Write(buf, nRead); - if ( !stream ) - return false; - } - while ( !file.Eof() ); - - return true; -} - -bool wxTransferStreamToFile(wxInputStream& stream, const wxString& filename) -{ - wxFFile file(filename, _T("wb")); - if ( !file.IsOpened() ) - return false; - - char buf[4096]; - for ( ;; ) - { - stream.Read(buf, WXSIZEOF(buf)); - - const size_t nRead = stream.LastRead(); - if ( !nRead ) - { - if ( stream.Eof() ) - break; - - return false; - } - - if ( !file.Write(buf, nRead) ) - return false; - } - - return true; -} - -#endif // wxUSE_STD_IOSTREAM/!wxUSE_STD_IOSTREAM - -#endif // wxUSE_DOC_VIEW_ARCHITECTURE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/docview.cpp +// Purpose: Document/view classes +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id: docview.cpp 66911 2011-02-16 21:31:33Z JS $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DOC_VIEW_ARCHITECTURE + +#include "wx/docview.h" + +#ifndef WX_PRECOMP + #include "wx/list.h" + #include "wx/string.h" + #include "wx/utils.h" + #include "wx/app.h" + #include "wx/dc.h" + #include "wx/dialog.h" + #include "wx/menu.h" + #include "wx/filedlg.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/msgdlg.h" + #include "wx/mdi.h" + #include "wx/choicdlg.h" +#endif + +#include "wx/ffile.h" + +#ifdef __WXMAC__ + #include "wx/filename.h" +#endif + +#if wxUSE_PRINTING_ARCHITECTURE + #include "wx/prntbase.h" + #include "wx/printdlg.h" +#endif + +#include "wx/confbase.h" +#include "wx/file.h" +#include "wx/cmdproc.h" +#include "wx/tokenzr.h" + +#include +#include + +#if wxUSE_STD_IOSTREAM + #include "wx/ioswrap.h" + #if wxUSE_IOSTREAMH + #include + #else + #include + #endif +#else + #include "wx/wfstream.h" +#endif + +// ---------------------------------------------------------------------------- +// wxWidgets macros +// ---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxDocument, wxEvtHandler) +IMPLEMENT_ABSTRACT_CLASS(wxView, wxEvtHandler) +IMPLEMENT_ABSTRACT_CLASS(wxDocTemplate, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxDocManager, wxEvtHandler) +IMPLEMENT_CLASS(wxDocChildFrame, wxFrame) +IMPLEMENT_CLASS(wxDocParentFrame, wxFrame) + +#if wxUSE_PRINTING_ARCHITECTURE + IMPLEMENT_DYNAMIC_CLASS(wxDocPrintout, wxPrintout) +#endif + +IMPLEMENT_DYNAMIC_CLASS(wxFileHistory, wxObject) + +// ---------------------------------------------------------------------------- +// function prototypes +// ---------------------------------------------------------------------------- + +static wxWindow* wxFindSuitableParent(void); + +// ---------------------------------------------------------------------------- +// local constants +// ---------------------------------------------------------------------------- + +static const wxChar *s_MRUEntryFormat = wxT("&%d %s"); + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// local functions +// ---------------------------------------------------------------------------- + +static wxString FindExtension(const wxChar *path) +{ + wxString ext; + wxSplitPath(path, NULL, NULL, &ext); + + // VZ: extensions are considered not case sensitive - is this really a good + // idea? + return ext.MakeLower(); +} + +// ---------------------------------------------------------------------------- +// Definition of wxDocument +// ---------------------------------------------------------------------------- + +wxDocument::wxDocument(wxDocument *parent) +{ + m_documentModified = false; + m_documentParent = parent; + m_documentTemplate = (wxDocTemplate *) NULL; + m_commandProcessor = (wxCommandProcessor*) NULL; + m_savedYet = false; +} + +bool wxDocument::DeleteContents() +{ + return true; +} + +wxDocument::~wxDocument() +{ + DeleteContents(); + + if (m_commandProcessor) + delete m_commandProcessor; + + if (GetDocumentManager()) + GetDocumentManager()->RemoveDocument(this); + + // Not safe to do here, since it'll invoke virtual view functions + // expecting to see valid derived objects: and by the time we get here, + // we've called destructors higher up. + //DeleteAllViews(); +} + +bool wxDocument::Close() +{ + if (OnSaveModified()) + return OnCloseDocument(); + else + return false; +} + +bool wxDocument::OnCloseDocument() +{ + // Tell all views that we're about to close + NotifyClosing(); + DeleteContents(); + Modify(false); + return true; +} + +// Note that this implicitly deletes the document when the last view is +// deleted. +bool wxDocument::DeleteAllViews() +{ + wxDocManager* manager = GetDocumentManager(); + + // first check if all views agree to be closed + const wxList::iterator end = m_documentViews.end(); + for ( wxList::iterator i = m_documentViews.begin(); i != end; ++i ) + { + wxView *view = (wxView *)*i; + if ( !view->Close() ) + return false; + } + + // all views agreed to close, now do close them + if ( m_documentViews.empty() ) + { + // normally the document would be implicitly deleted when the last view + // is, but if don't have any views, do it here instead + if ( manager && manager->GetDocuments().Member(this) ) + delete this; + } + else // have views + { + // as we delete elements we iterate over, don't use the usual "from + // begin to end" loop + for ( ;; ) + { + wxView *view = (wxView *)*m_documentViews.begin(); + + bool isLastOne = m_documentViews.size() == 1; + + // this always deletes the node implicitly and if this is the last + // view also deletes this object itself (also implicitly, great), + // so we can't test for m_documentViews.empty() after calling this! + delete view; + + if ( isLastOne ) + break; + } + } + + return true; +} + +wxView *wxDocument::GetFirstView() const +{ + if (m_documentViews.GetCount() == 0) + return (wxView *) NULL; + return (wxView *)m_documentViews.GetFirst()->GetData(); +} + +wxDocManager *wxDocument::GetDocumentManager() const +{ + return (m_documentTemplate ? m_documentTemplate->GetDocumentManager() : (wxDocManager*) NULL); +} + +bool wxDocument::OnNewDocument() +{ + if (!OnSaveModified()) + return false; + + if (OnCloseDocument()==false) return false; + DeleteContents(); + Modify(false); + SetDocumentSaved(false); + + wxString name; + GetDocumentManager()->MakeDefaultName(name); + SetTitle(name); + SetFilename(name, true); + + return true; +} + +bool wxDocument::Save() +{ + if (!IsModified() && m_savedYet) + return true; + + if ( m_documentFile.empty() || !m_savedYet ) + return SaveAs(); + + return OnSaveDocument(m_documentFile); +} + +bool wxDocument::SaveAs() +{ + wxDocTemplate *docTemplate = GetDocumentTemplate(); + if (!docTemplate) + return false; + +#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) + wxString filter = docTemplate->GetDescription() + wxT(" (") + docTemplate->GetFileFilter() + wxT(")|") + docTemplate->GetFileFilter(); + + // Now see if there are some other template with identical view and document + // classes, whose filters may also be used. + + if (docTemplate->GetViewClassInfo() && docTemplate->GetDocClassInfo()) + { + wxList::compatibility_iterator node = docTemplate->GetDocumentManager()->GetTemplates().GetFirst(); + while (node) + { + wxDocTemplate *t = (wxDocTemplate*) node->GetData(); + + if (t->IsVisible() && t != docTemplate && + t->GetViewClassInfo() == docTemplate->GetViewClassInfo() && + t->GetDocClassInfo() == docTemplate->GetDocClassInfo()) + { + // add a '|' to separate this filter from the previous one + if ( !filter.empty() ) + filter << wxT('|'); + + filter << t->GetDescription() << wxT(" (") << t->GetFileFilter() << wxT(") |") + << t->GetFileFilter(); + } + + node = node->GetNext(); + } + } +#else + wxString filter = docTemplate->GetFileFilter() ; +#endif + wxString defaultDir = docTemplate->GetDirectory(); + if (defaultDir.IsEmpty()) + defaultDir = wxPathOnly(GetFilename()); + + wxString tmp = wxFileSelector(_("Save as"), + defaultDir, + wxFileNameFromPath(GetFilename()), + docTemplate->GetDefaultExtension(), + filter, + wxFD_SAVE | wxFD_OVERWRITE_PROMPT, + GetDocumentWindow()); + + if (tmp.empty()) + return false; + + wxString fileName(tmp); + wxString path, name, ext; + wxSplitPath(fileName, & path, & name, & ext); + + if (ext.empty()) + { + fileName += wxT("."); + fileName += docTemplate->GetDefaultExtension(); + } + + SetFilename(fileName); + SetTitle(wxFileNameFromPath(fileName)); + + // Notify the views that the filename has changed + wxList::compatibility_iterator node = m_documentViews.GetFirst(); + while (node) + { + wxView *view = (wxView *)node->GetData(); + view->OnChangeFilename(); + node = node->GetNext(); + } + + // Files that were not saved correctly are not added to the FileHistory. + if (!OnSaveDocument(m_documentFile)) + return false; + + // A file that doesn't use the default extension of its document template cannot be opened + // via the FileHistory, so we do not add it. + if (docTemplate->FileMatchesTemplate(fileName)) + { + GetDocumentManager()->AddFileToHistory(fileName); + } + else + { + // The user will probably not be able to open the file again, so + // we could warn about the wrong file-extension here. + } + return true; +} + +bool wxDocument::OnSaveDocument(const wxString& file) +{ + if ( !file ) + return false; + + if ( !DoSaveDocument(file) ) + return false; + + Modify(false); + SetFilename(file); + SetDocumentSaved(true); +#ifdef __WXMAC__ + wxFileName fn(file) ; + fn.MacSetDefaultTypeAndCreator() ; +#endif + return true; +} + +bool wxDocument::OnOpenDocument(const wxString& file) +{ + if (!OnSaveModified()) + return false; + + if ( !DoOpenDocument(file) ) + return false; + + SetFilename(file, true); + Modify(false); + m_savedYet = true; + + UpdateAllViews(); + + return true; +} + +#if wxUSE_STD_IOSTREAM +wxSTD istream& wxDocument::LoadObject(wxSTD istream& stream) +#else +wxInputStream& wxDocument::LoadObject(wxInputStream& stream) +#endif +{ + return stream; +} + +#if wxUSE_STD_IOSTREAM +wxSTD ostream& wxDocument::SaveObject(wxSTD ostream& stream) +#else +wxOutputStream& wxDocument::SaveObject(wxOutputStream& stream) +#endif +{ + return stream; +} + +bool wxDocument::Revert() +{ + return false; +} + + +// Get title, or filename if no title, else unnamed +bool wxDocument::GetPrintableName(wxString& buf) const +{ + if (!m_documentTitle.empty()) + { + buf = m_documentTitle; + return true; + } + else if (!m_documentFile.empty()) + { + buf = wxFileNameFromPath(m_documentFile); + return true; + } + else + { + buf = _("unnamed"); + return true; + } +} + +wxWindow *wxDocument::GetDocumentWindow() const +{ + wxView *view = GetFirstView(); + if (view) + return view->GetFrame(); + else + return wxTheApp->GetTopWindow(); +} + +wxCommandProcessor *wxDocument::OnCreateCommandProcessor() +{ + return new wxCommandProcessor; +} + +// true if safe to close +bool wxDocument::OnSaveModified() +{ + if (IsModified()) + { + wxString title; + GetPrintableName(title); + + wxString msgTitle; + if (!wxTheApp->GetAppName().empty()) + msgTitle = wxTheApp->GetAppName(); + else + msgTitle = wxString(_("Warning")); + + wxString prompt; + prompt.Printf(_("Do you want to save changes to document %s?"), + (const wxChar *)title); + int res = wxMessageBox(prompt, msgTitle, + wxYES_NO|wxCANCEL|wxICON_QUESTION, + GetDocumentWindow()); + if (res == wxNO) + { + Modify(false); + return true; + } + else if (res == wxYES) + return Save(); + else if (res == wxCANCEL) + return false; + } + return true; +} + +bool wxDocument::Draw(wxDC& WXUNUSED(context)) +{ + return true; +} + +bool wxDocument::AddView(wxView *view) +{ + if (!m_documentViews.Member(view)) + { + m_documentViews.Append(view); + OnChangedViewList(); + } + return true; +} + +bool wxDocument::RemoveView(wxView *view) +{ + (void)m_documentViews.DeleteObject(view); + OnChangedViewList(); + return true; +} + +bool wxDocument::OnCreate(const wxString& WXUNUSED(path), long flags) +{ + if (GetDocumentTemplate()->CreateView(this, flags)) + return true; + else + return false; +} + +// Called after a view is added or removed. +// The default implementation deletes the document if +// there are no more views. +void wxDocument::OnChangedViewList() +{ + if (m_documentViews.GetCount() == 0) + { + if (OnSaveModified()) + { + delete this; + } + } +} + +void wxDocument::UpdateAllViews(wxView *sender, wxObject *hint) +{ + wxList::compatibility_iterator node = m_documentViews.GetFirst(); + while (node) + { + wxView *view = (wxView *)node->GetData(); + if (view != sender) + view->OnUpdate(sender, hint); + node = node->GetNext(); + } +} + +void wxDocument::NotifyClosing() +{ + wxList::compatibility_iterator node = m_documentViews.GetFirst(); + while (node) + { + wxView *view = (wxView *)node->GetData(); + view->OnClosingDocument(); + node = node->GetNext(); + } +} + +void wxDocument::SetFilename(const wxString& filename, bool notifyViews) +{ + m_documentFile = filename; + if ( notifyViews ) + { + // Notify the views that the filename has changed + wxList::compatibility_iterator node = m_documentViews.GetFirst(); + while (node) + { + wxView *view = (wxView *)node->GetData(); + view->OnChangeFilename(); + node = node->GetNext(); + } + } +} + +bool wxDocument::DoSaveDocument(const wxString& file) +{ + wxString msgTitle; + if (!wxTheApp->GetAppName().empty()) + msgTitle = wxTheApp->GetAppName(); + else + msgTitle = wxString(_("File error")); + +#if wxUSE_STD_IOSTREAM + wxSTD ofstream store(file.mb_str(), wxSTD ios::binary); + if (store.fail() || store.bad()) +#else + wxFileOutputStream store(file); + if (store.GetLastError() != wxSTREAM_NO_ERROR) +#endif + { + (void)wxMessageBox(_("Sorry, could not open this file for saving."), msgTitle, wxOK | wxICON_EXCLAMATION, + GetDocumentWindow()); + // Saving error + return false; + } + if (!SaveObject(store)) + { + (void)wxMessageBox(_("Sorry, could not save this file."), msgTitle, wxOK | wxICON_EXCLAMATION, + GetDocumentWindow()); + // Saving error + return false; + } + + return true; +} + +bool wxDocument::DoOpenDocument(const wxString& file) +{ +#if wxUSE_STD_IOSTREAM + wxSTD ifstream store(file.mb_str(), wxSTD ios::binary); + if (!store.fail() && !store.bad()) +#else + wxFileInputStream store(file); + if (store.GetLastError() == wxSTREAM_NO_ERROR) +#endif + { +#if wxUSE_STD_IOSTREAM + LoadObject(store); + if ( !!store || store.eof() ) +#else + int res = LoadObject(store).GetLastError(); + if ( res == wxSTREAM_NO_ERROR || res == wxSTREAM_EOF ) +#endif + return true; + } + + wxLogError(_("Sorry, could not open this file.")); + return false; +} + + +// ---------------------------------------------------------------------------- +// Document view +// ---------------------------------------------------------------------------- + +wxView::wxView() +{ + m_viewDocument = (wxDocument*) NULL; + + m_viewFrame = (wxFrame *) NULL; +} + +wxView::~wxView() +{ + if (m_viewDocument && GetDocumentManager()) + GetDocumentManager()->ActivateView(this, false); + if (m_viewDocument) + m_viewDocument->RemoveView(this); +} + +// Extend event processing to search the document's event table +bool wxView::ProcessEvent(wxEvent& event) +{ + if ( !GetDocument() || !GetDocument()->ProcessEvent(event) ) + return wxEvtHandler::ProcessEvent(event); + + return true; +} + +void wxView::OnActivateView(bool WXUNUSED(activate), wxView *WXUNUSED(activeView), wxView *WXUNUSED(deactiveView)) +{ +} + +void wxView::OnPrint(wxDC *dc, wxObject *WXUNUSED(info)) +{ + OnDraw(dc); +} + +void wxView::OnUpdate(wxView *WXUNUSED(sender), wxObject *WXUNUSED(hint)) +{ +} + +void wxView::OnChangeFilename() +{ + // GetFrame can return wxWindow rather than wxTopLevelWindow due to + // generic MDI implementation so use SetLabel rather than SetTitle. + // It should cause SetTitle() for top level windows. + wxWindow *win = GetFrame(); + if (!win) return; + + wxDocument *doc = GetDocument(); + if (!doc) return; + + wxString name; + doc->GetPrintableName(name); + win->SetLabel(name); +} + +void wxView::SetDocument(wxDocument *doc) +{ + m_viewDocument = doc; + if (doc) + doc->AddView(this); +} + +bool wxView::Close(bool deleteWindow) +{ + if (OnClose(deleteWindow)) + return true; + else + return false; +} + +void wxView::Activate(bool activate) +{ + if (GetDocument() && GetDocumentManager()) + { + OnActivateView(activate, this, GetDocumentManager()->GetCurrentView()); + GetDocumentManager()->ActivateView(this, activate); + } +} + +bool wxView::OnClose(bool WXUNUSED(deleteWindow)) +{ + return GetDocument() ? GetDocument()->Close() : true; +} + +#if wxUSE_PRINTING_ARCHITECTURE +wxPrintout *wxView::OnCreatePrintout() +{ + return new wxDocPrintout(this); +} +#endif // wxUSE_PRINTING_ARCHITECTURE + +// ---------------------------------------------------------------------------- +// wxDocTemplate +// ---------------------------------------------------------------------------- + +wxDocTemplate::wxDocTemplate(wxDocManager *manager, + const wxString& descr, + const wxString& filter, + const wxString& dir, + const wxString& ext, + const wxString& docTypeName, + const wxString& viewTypeName, + wxClassInfo *docClassInfo, + wxClassInfo *viewClassInfo, + long flags) +{ + m_documentManager = manager; + m_description = descr; + m_directory = dir; + m_defaultExt = ext; + m_fileFilter = filter; + m_flags = flags; + m_docTypeName = docTypeName; + m_viewTypeName = viewTypeName; + m_documentManager->AssociateTemplate(this); + + m_docClassInfo = docClassInfo; + m_viewClassInfo = viewClassInfo; +} + +wxDocTemplate::~wxDocTemplate() +{ + m_documentManager->DisassociateTemplate(this); +} + +// Tries to dynamically construct an object of the right class. +wxDocument *wxDocTemplate::CreateDocument(const wxString& path, long flags) +{ + wxDocument *doc = DoCreateDocument(); + if ( doc == NULL ) + return (wxDocument *) NULL; + + if (InitDocument(doc, path, flags)) + { + return doc; + } + else + { + return (wxDocument *) NULL; + } +} + +bool wxDocTemplate::InitDocument(wxDocument* doc, const wxString& path, long flags) +{ + doc->SetFilename(path); + doc->SetDocumentTemplate(this); + GetDocumentManager()->AddDocument(doc); + doc->SetCommandProcessor(doc->OnCreateCommandProcessor()); + + if (doc->OnCreate(path, flags)) + return true; + else + { + if (GetDocumentManager()->GetDocuments().Member(doc)) + doc->DeleteAllViews(); + return false; + } +} + +wxView *wxDocTemplate::CreateView(wxDocument *doc, long flags) +{ + wxView *view = DoCreateView(); + if ( view == NULL ) + return (wxView *) NULL; + + view->SetDocument(doc); + if (view->OnCreate(doc, flags)) + { + return view; + } + else + { + delete view; + return (wxView *) NULL; + } +} + +// The default (very primitive) format detection: check is the extension is +// that of the template +bool wxDocTemplate::FileMatchesTemplate(const wxString& path) +{ + wxStringTokenizer parser (GetFileFilter(), wxT(";")); + wxString anything = wxT ("*"); + while (parser.HasMoreTokens()) + { + wxString filter = parser.GetNextToken(); + wxString filterExt = FindExtension (filter); + if ( filter.IsSameAs (anything) || + filterExt.IsSameAs (anything) || + filterExt.IsSameAs (FindExtension (path)) ) + return true; + } + return GetDefaultExtension().IsSameAs(FindExtension(path)); +} + +wxDocument *wxDocTemplate::DoCreateDocument() +{ + if (!m_docClassInfo) + return (wxDocument *) NULL; + + return (wxDocument *)m_docClassInfo->CreateObject(); +} + +wxView *wxDocTemplate::DoCreateView() +{ + if (!m_viewClassInfo) + return (wxView *) NULL; + + return (wxView *)m_viewClassInfo->CreateObject(); +} + +// ---------------------------------------------------------------------------- +// wxDocManager +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxDocManager, wxEvtHandler) + EVT_MENU(wxID_OPEN, wxDocManager::OnFileOpen) + EVT_MENU(wxID_CLOSE, wxDocManager::OnFileClose) + EVT_MENU(wxID_CLOSE_ALL, wxDocManager::OnFileCloseAll) + EVT_MENU(wxID_REVERT, wxDocManager::OnFileRevert) + EVT_MENU(wxID_NEW, wxDocManager::OnFileNew) + EVT_MENU(wxID_SAVE, wxDocManager::OnFileSave) + EVT_MENU(wxID_SAVEAS, wxDocManager::OnFileSaveAs) + EVT_MENU(wxID_UNDO, wxDocManager::OnUndo) + EVT_MENU(wxID_REDO, wxDocManager::OnRedo) + + EVT_UPDATE_UI(wxID_OPEN, wxDocManager::OnUpdateFileOpen) + EVT_UPDATE_UI(wxID_CLOSE, wxDocManager::OnUpdateFileClose) + EVT_UPDATE_UI(wxID_CLOSE_ALL, wxDocManager::OnUpdateFileClose) + EVT_UPDATE_UI(wxID_REVERT, wxDocManager::OnUpdateFileRevert) + EVT_UPDATE_UI(wxID_NEW, wxDocManager::OnUpdateFileNew) + EVT_UPDATE_UI(wxID_SAVE, wxDocManager::OnUpdateFileSave) + EVT_UPDATE_UI(wxID_SAVEAS, wxDocManager::OnUpdateFileSaveAs) + EVT_UPDATE_UI(wxID_UNDO, wxDocManager::OnUpdateUndo) + EVT_UPDATE_UI(wxID_REDO, wxDocManager::OnUpdateRedo) + +#if wxUSE_PRINTING_ARCHITECTURE + EVT_MENU(wxID_PRINT, wxDocManager::OnPrint) + EVT_MENU(wxID_PREVIEW, wxDocManager::OnPreview) + + EVT_UPDATE_UI(wxID_PRINT, wxDocManager::OnUpdatePrint) + EVT_UPDATE_UI(wxID_PREVIEW, wxDocManager::OnUpdatePreview) +#endif +END_EVENT_TABLE() + +wxDocManager* wxDocManager::sm_docManager = (wxDocManager*) NULL; + +wxDocManager::wxDocManager(long flags, bool initialize) +{ + m_defaultDocumentNameCounter = 1; + m_flags = flags; + m_currentView = (wxView *) NULL; + m_maxDocsOpen = 10000; + m_fileHistory = (wxFileHistory *) NULL; + if (initialize) + Initialize(); + sm_docManager = this; +} + +wxDocManager::~wxDocManager() +{ + Clear(); + if (m_fileHistory) + delete m_fileHistory; + sm_docManager = (wxDocManager*) NULL; +} + +// closes the specified document +bool wxDocManager::CloseDocument(wxDocument* doc, bool force) +{ + if (doc->Close() || force) + { + // Implicitly deletes the document when + // the last view is deleted + doc->DeleteAllViews(); + + // Check we're really deleted + if (m_docs.Member(doc)) + delete doc; + + return true; + } + return false; +} + +bool wxDocManager::CloseDocuments(bool force) +{ + wxList::compatibility_iterator node = m_docs.GetFirst(); + while (node) + { + wxDocument *doc = (wxDocument *)node->GetData(); + wxList::compatibility_iterator next = node->GetNext(); + + if (!CloseDocument(doc, force)) + return false; + + // This assumes that documents are not connected in + // any way, i.e. deleting one document does NOT + // delete another. + node = next; + } + return true; +} + +bool wxDocManager::Clear(bool force) +{ + if (!CloseDocuments(force)) + return false; + + m_currentView = NULL; + + wxList::compatibility_iterator node = m_templates.GetFirst(); + while (node) + { + wxDocTemplate *templ = (wxDocTemplate*) node->GetData(); + wxList::compatibility_iterator next = node->GetNext(); + delete templ; + node = next; + } + return true; +} + +bool wxDocManager::Initialize() +{ + m_fileHistory = OnCreateFileHistory(); + return true; +} + +wxFileHistory *wxDocManager::OnCreateFileHistory() +{ + return new wxFileHistory; +} + +void wxDocManager::OnFileClose(wxCommandEvent& WXUNUSED(event)) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + return; + if (doc->Close()) + { + doc->DeleteAllViews(); + if (m_docs.Member(doc)) + delete doc; + } +} + +void wxDocManager::OnFileCloseAll(wxCommandEvent& WXUNUSED(event)) +{ + CloseDocuments(false); +} + +void wxDocManager::OnFileNew(wxCommandEvent& WXUNUSED(event)) +{ + CreateDocument( wxEmptyString, wxDOC_NEW ); +} + +void wxDocManager::OnFileOpen(wxCommandEvent& WXUNUSED(event)) +{ + if ( !CreateDocument( wxEmptyString, 0) ) + { + OnOpenFileFailure(); + } +} + +void wxDocManager::OnFileRevert(wxCommandEvent& WXUNUSED(event)) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + return; + doc->Revert(); +} + +void wxDocManager::OnFileSave(wxCommandEvent& WXUNUSED(event)) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + return; + doc->Save(); +} + +void wxDocManager::OnFileSaveAs(wxCommandEvent& WXUNUSED(event)) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + return; + doc->SaveAs(); +} + +void wxDocManager::OnPrint(wxCommandEvent& WXUNUSED(event)) +{ +#if wxUSE_PRINTING_ARCHITECTURE + wxView *view = GetCurrentView(); + if (!view) + return; + + wxPrintout *printout = view->OnCreatePrintout(); + if (printout) + { + wxPrinter printer; + printer.Print(view->GetFrame(), printout, true); + + delete printout; + } +#endif // wxUSE_PRINTING_ARCHITECTURE +} + +void wxDocManager::OnPreview(wxCommandEvent& WXUNUSED(event)) +{ +#if wxUSE_PRINTING_ARCHITECTURE + wxBusyCursor busy; + wxView *view = GetCurrentView(); + if (!view) + return; + + wxPrintout *printout = view->OnCreatePrintout(); + if (printout) + { + // Pass two printout objects: for preview, and possible printing. + wxPrintPreviewBase *preview = new wxPrintPreview(printout, view->OnCreatePrintout()); + if ( !preview->Ok() ) + { + delete preview; + wxMessageBox( _("Sorry, print preview needs a printer to be installed.") ); + return; + } + + wxPreviewFrame *frame = new wxPreviewFrame(preview, (wxFrame *)wxTheApp->GetTopWindow(), _("Print Preview"), + wxPoint(100, 100), wxSize(600, 650)); + frame->Centre(wxBOTH); + frame->Initialize(); + frame->Show(true); + } +#endif // wxUSE_PRINTING_ARCHITECTURE +} + +void wxDocManager::OnUndo(wxCommandEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + return; + if (doc->GetCommandProcessor()) + doc->GetCommandProcessor()->Undo(); + else + event.Skip(); +} + +void wxDocManager::OnRedo(wxCommandEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + return; + if (doc->GetCommandProcessor()) + doc->GetCommandProcessor()->Redo(); + else + event.Skip(); +} + +// Handlers for UI update commands + +void wxDocManager::OnUpdateFileOpen(wxUpdateUIEvent& event) +{ + event.Enable( true ); +} + +void wxDocManager::OnUpdateFileClose(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + event.Enable( (doc != (wxDocument*) NULL) ); +} + +void wxDocManager::OnUpdateFileRevert(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + event.Enable( (doc != (wxDocument*) NULL) ); +} + +void wxDocManager::OnUpdateFileNew(wxUpdateUIEvent& event) +{ + event.Enable( true ); +} + +void wxDocManager::OnUpdateFileSave(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + event.Enable( doc && doc->IsModified() ); +} + +void wxDocManager::OnUpdateFileSaveAs(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + event.Enable( (doc != (wxDocument*) NULL) ); +} + +void wxDocManager::OnUpdateUndo(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + event.Enable(false); + else if (!doc->GetCommandProcessor()) + event.Skip(); + else + { + event.Enable( doc->GetCommandProcessor()->CanUndo() ); + doc->GetCommandProcessor()->SetMenuStrings(); + } +} + +void wxDocManager::OnUpdateRedo(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + if (!doc) + event.Enable(false); + else if (!doc->GetCommandProcessor()) + event.Skip(); + else + { + event.Enable( doc->GetCommandProcessor()->CanRedo() ); + doc->GetCommandProcessor()->SetMenuStrings(); + } +} + +void wxDocManager::OnUpdatePrint(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + event.Enable( (doc != (wxDocument*) NULL) ); +} + +void wxDocManager::OnUpdatePreview(wxUpdateUIEvent& event) +{ + wxDocument *doc = GetCurrentDocument(); + event.Enable( (doc != (wxDocument*) NULL) ); +} + +wxView *wxDocManager::GetCurrentView() const +{ + if (m_currentView) + return m_currentView; + if (m_docs.GetCount() == 1) + { + wxDocument* doc = (wxDocument*) m_docs.GetFirst()->GetData(); + return doc->GetFirstView(); + } + return (wxView *) NULL; +} + +// Extend event processing to search the view's event table +bool wxDocManager::ProcessEvent(wxEvent& event) +{ + wxView* view = GetCurrentView(); + if (view) + { + if (view->ProcessEvent(event)) + return true; + } + return wxEvtHandler::ProcessEvent(event); +} + +wxDocument *wxDocManager::CreateDocument(const wxString& path, long flags) +{ + wxDocTemplate **templates = new wxDocTemplate *[m_templates.GetCount()]; + int n = 0; + + for (size_t i = 0; i < m_templates.GetCount(); i++) + { + wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Item(i)->GetData()); + if (temp->IsVisible()) + { + templates[n] = temp; + n ++; + } + } + if (n == 0) + { + delete[] templates; + return (wxDocument *) NULL; + } + + wxDocument* docToClose = NULL; + + // If we've reached the max number of docs, close the + // first one. + if ( (int)GetDocuments().GetCount() >= m_maxDocsOpen ) + { + wxDocument *doc = (wxDocument *)GetDocuments().GetFirst()->GetData(); + docToClose = doc; + } + + // New document: user chooses a template, unless there's only one. + if (flags & wxDOC_NEW) + { + if (n == 1) + { + if (docToClose) + { + if (!CloseDocument(docToClose, false)) + { + delete[] templates; + return NULL; + } + } + + wxDocTemplate *temp = templates[0]; + delete[] templates; + wxDocument *newDoc = temp->CreateDocument(path, flags); + + if (newDoc) + { + newDoc->SetDocumentName(temp->GetDocumentName()); + newDoc->SetDocumentTemplate(temp); + if (!newDoc->OnNewDocument() ) + { + // Document is implicitly deleted by DeleteAllViews + newDoc->DeleteAllViews(); + return NULL; + } + } + return newDoc; + } + + wxDocTemplate *temp = SelectDocumentType(templates, n); + delete[] templates; + if (temp) + { + if (docToClose) + { + if (!CloseDocument(docToClose, false)) + { + return NULL; + } + } + + wxDocument *newDoc = temp->CreateDocument(path, flags); + + if (newDoc) + { + newDoc->SetDocumentName(temp->GetDocumentName()); + newDoc->SetDocumentTemplate(temp); + if (!newDoc->OnNewDocument() ) + { + // Document is implicitly deleted by DeleteAllViews + newDoc->DeleteAllViews(); + return NULL; + } + } + return newDoc; + } + else + return (wxDocument *) NULL; + } + + // Existing document + wxDocTemplate *temp; + + wxString path2 = path; + + if (flags & wxDOC_SILENT) + { + temp = FindTemplateForPath(path2); + if (!temp) + { + // Since we do not add files with non-default extensions to the FileHistory this + // can only happen if the application changes the allowed templates in runtime. + (void)wxMessageBox(_("Sorry, the format for this file is unknown."), + _("Open File"), + wxOK | wxICON_EXCLAMATION, wxFindSuitableParent()); + } + } + else + temp = SelectDocumentPath(templates, n, path2, flags); + + delete[] templates; + + if (temp) + { + if (docToClose) + { + if (!CloseDocument(docToClose, false)) + { + return NULL; + } + } + + //see if this file is already open + for (size_t i = 0; i < GetDocuments().GetCount(); ++i) + { + wxDocument* currentDoc = (wxDocument*)(GetDocuments().Item(i)->GetData()); +#ifdef __WXMSW__ + //file paths are case-insensitive on Windows + if (path2.CmpNoCase(currentDoc->GetFilename()) == 0) +#else + if (path2.Cmp(currentDoc->GetFilename()) == 0) +#endif + { + //file already open. Just activate it and return + if (currentDoc->GetFirstView()) + { + ActivateView(currentDoc->GetFirstView(), true); + if (currentDoc->GetDocumentWindow()) + currentDoc->GetDocumentWindow()->SetFocus(); + return currentDoc; + } + } + } + + wxDocument *newDoc = temp->CreateDocument(path2, flags); + if (newDoc) + { + newDoc->SetDocumentName(temp->GetDocumentName()); + newDoc->SetDocumentTemplate(temp); + if (!newDoc->OnOpenDocument(path2)) + { + newDoc->DeleteAllViews(); + // delete newDoc; // Implicitly deleted by DeleteAllViews + return (wxDocument *) NULL; + } + // A file that doesn't use the default extension of its document + // template cannot be opened via the FileHistory, so we do not + // add it. + if (temp->FileMatchesTemplate(path2)) + AddFileToHistory(path2); + } + return newDoc; + } + + return (wxDocument *) NULL; +} + +wxView *wxDocManager::CreateView(wxDocument *doc, long flags) +{ + wxDocTemplate **templates = new wxDocTemplate *[m_templates.GetCount()]; + int n =0; + + for (size_t i = 0; i < m_templates.GetCount(); i++) + { + wxDocTemplate *temp = (wxDocTemplate *)(m_templates.Item(i)->GetData()); + if (temp->IsVisible()) + { + if (temp->GetDocumentName() == doc->GetDocumentName()) + { + templates[n] = temp; + n ++; + } + } + } + if (n == 0) + { + delete[] templates; + return (wxView *) NULL; + } + if (n == 1) + { + wxDocTemplate *temp = templates[0]; + delete[] templates; + wxView *view = temp->CreateView(doc, flags); + if (view) + view->SetViewName(temp->GetViewName()); + return view; + } + + wxDocTemplate *temp = SelectViewType(templates, n); + delete[] templates; + if (temp) + { + wxView *view = temp->CreateView(doc, flags); + if (view) + view->SetViewName(temp->GetViewName()); + return view; + } + else + return (wxView *) NULL; +} + +// Not yet implemented +void wxDocManager::DeleteTemplate(wxDocTemplate *WXUNUSED(temp), long WXUNUSED(flags)) +{ +} + +// Not yet implemented +bool wxDocManager::FlushDoc(wxDocument *WXUNUSED(doc)) +{ + return false; +} + +wxDocument *wxDocManager::GetCurrentDocument() const +{ + wxView *view = GetCurrentView(); + if (view) + return view->GetDocument(); + else + return (wxDocument *) NULL; +} + +// Make a default document name +bool wxDocManager::MakeDefaultName(wxString& name) +{ + name.Printf(_("unnamed%d"), m_defaultDocumentNameCounter); + m_defaultDocumentNameCounter++; + + return true; +} + +// Make a frame title (override this to do something different) +// If docName is empty, a document is not currently active. +wxString wxDocManager::MakeFrameTitle(wxDocument* doc) +{ + wxString appName = wxTheApp->GetAppName(); + wxString title; + if (!doc) + title = appName; + else + { + wxString docName; + doc->GetPrintableName(docName); + title = docName + wxString(_(" - ")) + appName; + } + return title; +} + + +// Not yet implemented +wxDocTemplate *wxDocManager::MatchTemplate(const wxString& WXUNUSED(path)) +{ + return (wxDocTemplate *) NULL; +} + +// File history management +void wxDocManager::AddFileToHistory(const wxString& file) +{ + if (m_fileHistory) + m_fileHistory->AddFileToHistory(file); +} + +void wxDocManager::RemoveFileFromHistory(size_t i) +{ + if (m_fileHistory) + m_fileHistory->RemoveFileFromHistory(i); +} + +wxString wxDocManager::GetHistoryFile(size_t i) const +{ + wxString histFile; + + if (m_fileHistory) + histFile = m_fileHistory->GetHistoryFile(i); + + return histFile; +} + +void wxDocManager::FileHistoryUseMenu(wxMenu *menu) +{ + if (m_fileHistory) + m_fileHistory->UseMenu(menu); +} + +void wxDocManager::FileHistoryRemoveMenu(wxMenu *menu) +{ + if (m_fileHistory) + m_fileHistory->RemoveMenu(menu); +} + +#if wxUSE_CONFIG +void wxDocManager::FileHistoryLoad(wxConfigBase& config) +{ + if (m_fileHistory) + m_fileHistory->Load(config); +} + +void wxDocManager::FileHistorySave(wxConfigBase& config) +{ + if (m_fileHistory) + m_fileHistory->Save(config); +} +#endif + +void wxDocManager::FileHistoryAddFilesToMenu(wxMenu* menu) +{ + if (m_fileHistory) + m_fileHistory->AddFilesToMenu(menu); +} + +void wxDocManager::FileHistoryAddFilesToMenu() +{ + if (m_fileHistory) + m_fileHistory->AddFilesToMenu(); +} + +size_t wxDocManager::GetHistoryFilesCount() const +{ + return m_fileHistory ? m_fileHistory->GetCount() : 0; +} + + +// Find out the document template via matching in the document file format +// against that of the template +wxDocTemplate *wxDocManager::FindTemplateForPath(const wxString& path) +{ + wxDocTemplate *theTemplate = (wxDocTemplate *) NULL; + + // Find the template which this extension corresponds to + for (size_t i = 0; i < m_templates.GetCount(); i++) + { + wxDocTemplate *temp = (wxDocTemplate *)m_templates.Item(i)->GetData(); + if ( temp->FileMatchesTemplate(path) ) + { + theTemplate = temp; + break; + } + } + return theTemplate; +} + +// Try to get a more suitable parent frame than the top window, +// for selection dialogs. Otherwise you may get an unexpected +// window being activated when a dialog is shown. +static wxWindow* wxFindSuitableParent() +{ + wxWindow* parent = wxTheApp->GetTopWindow(); + + wxWindow* focusWindow = wxWindow::FindFocus(); + if (focusWindow) + { + while (focusWindow && + !focusWindow->IsKindOf(CLASSINFO(wxDialog)) && + !focusWindow->IsKindOf(CLASSINFO(wxFrame))) + + focusWindow = focusWindow->GetParent(); + + if (focusWindow) + parent = focusWindow; + } + return parent; +} + +// Prompts user to open a file, using file specs in templates. +// Must extend the file selector dialog or implement own; OR +// match the extension to the template extension. + +wxDocTemplate *wxDocManager::SelectDocumentPath(wxDocTemplate **templates, +#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) + int noTemplates, +#else + int WXUNUSED(noTemplates), +#endif + wxString& path, + long WXUNUSED(flags), + bool WXUNUSED(save)) +{ + // We can only have multiple filters in Windows and GTK +#if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXMAC__) + wxString descrBuf; + + int i; + for (i = 0; i < noTemplates; i++) + { + if (templates[i]->IsVisible()) + { + // add a '|' to separate this filter from the previous one + if ( !descrBuf.empty() ) + descrBuf << wxT('|'); + + descrBuf << templates[i]->GetDescription() + << wxT(" (") << templates[i]->GetFileFilter() << wxT(") |") + << templates[i]->GetFileFilter(); + } + } +#else + wxString descrBuf = wxT("*.*"); +#endif + + int FilterIndex = -1; + + wxWindow* parent = wxFindSuitableParent(); + + wxString pathTmp = wxFileSelectorEx(_("Select a file"), + m_lastDirectory, + wxEmptyString, + &FilterIndex, + descrBuf, + 0, + parent); + + wxDocTemplate *theTemplate = (wxDocTemplate *)NULL; + if (!pathTmp.empty()) + { + if (!wxFileExists(pathTmp)) + { + wxString msgTitle; + if (!wxTheApp->GetAppName().empty()) + msgTitle = wxTheApp->GetAppName(); + else + msgTitle = wxString(_("File error")); + + (void)wxMessageBox(_("Sorry, could not open this file."), msgTitle, wxOK | wxICON_EXCLAMATION, + parent); + + path = wxEmptyString; + return (wxDocTemplate *) NULL; + } + m_lastDirectory = wxPathOnly(pathTmp); + + path = pathTmp; + + // first choose the template using the extension, if this fails (i.e. + // wxFileSelectorEx() didn't fill it), then use the path + if ( FilterIndex != -1 ) + theTemplate = templates[FilterIndex]; + if ( !theTemplate ) + theTemplate = FindTemplateForPath(path); + if ( !theTemplate ) + { + // Since we do not add files with non-default extensions to the FileHistory this + // can only happen if the application changes the allowed templates in runtime. + (void)wxMessageBox(_("Sorry, the format for this file is unknown."), + _("Open File"), + wxOK | wxICON_EXCLAMATION, wxFindSuitableParent()); + } + } + else + { + path = wxEmptyString; + } + + return theTemplate; +} + +wxDocTemplate *wxDocManager::SelectDocumentType(wxDocTemplate **templates, + int noTemplates, bool sort) +{ + wxArrayString strings; + wxDocTemplate **data = new wxDocTemplate *[noTemplates]; + int i; + int n = 0; + + for (i = 0; i < noTemplates; i++) + { + if (templates[i]->IsVisible()) + { + int j; + bool want = true; + for (j = 0; j < n; j++) + { + //filter out NOT unique documents + view combinations + if ( templates[i]->m_docTypeName == data[j]->m_docTypeName && + templates[i]->m_viewTypeName == data[j]->m_viewTypeName + ) + want = false; + } + + if ( want ) + { + strings.Add(templates[i]->m_description); + + data[n] = templates[i]; + n ++; + } + } + } // for + + if (sort) + { + strings.Sort(); // ascending sort + // Yes, this will be slow, but template lists + // are typically short. + int j; + n = strings.Count(); + for (i = 0; i < n; i++) + { + for (j = 0; j < noTemplates; j++) + { + if (strings[i] == templates[j]->m_description) + data[i] = templates[j]; + } + } + } + + wxDocTemplate *theTemplate; + + switch ( n ) + { + case 0: + // no visible templates, hence nothing to choose from + theTemplate = NULL; + break; + + case 1: + // don't propose the user to choose if he heas no choice + theTemplate = data[0]; + break; + + default: + // propose the user to choose one of several + theTemplate = (wxDocTemplate *)wxGetSingleChoiceData + ( + _("Select a document template"), + _("Templates"), + strings, + (void **)data, + wxFindSuitableParent() + ); + } + + delete[] data; + + return theTemplate; +} + +wxDocTemplate *wxDocManager::SelectViewType(wxDocTemplate **templates, + int noTemplates, bool sort) +{ + wxArrayString strings; + wxDocTemplate **data = new wxDocTemplate *[noTemplates]; + int i; + int n = 0; + + for (i = 0; i < noTemplates; i++) + { + wxDocTemplate *templ = templates[i]; + if ( templ->IsVisible() && !templ->GetViewName().empty() ) + { + int j; + bool want = true; + for (j = 0; j < n; j++) + { + //filter out NOT unique views + if ( templates[i]->m_viewTypeName == data[j]->m_viewTypeName ) + want = false; + } + + if ( want ) + { + strings.Add(templ->m_viewTypeName); + data[n] = templ; + n ++; + } + } + } + + if (sort) + { + strings.Sort(); // ascending sort + // Yes, this will be slow, but template lists + // are typically short. + int j; + n = strings.Count(); + for (i = 0; i < n; i++) + { + for (j = 0; j < noTemplates; j++) + { + if (strings[i] == templates[j]->m_viewTypeName) + data[i] = templates[j]; + } + } + } + + wxDocTemplate *theTemplate; + + // the same logic as above + switch ( n ) + { + case 0: + theTemplate = (wxDocTemplate *)NULL; + break; + + case 1: + theTemplate = data[0]; + break; + + default: + theTemplate = (wxDocTemplate *)wxGetSingleChoiceData + ( + _("Select a document view"), + _("Views"), + strings, + (void **)data, + wxFindSuitableParent() + ); + + } + + delete[] data; + return theTemplate; +} + +void wxDocManager::AssociateTemplate(wxDocTemplate *temp) +{ + if (!m_templates.Member(temp)) + m_templates.Append(temp); +} + +void wxDocManager::DisassociateTemplate(wxDocTemplate *temp) +{ + m_templates.DeleteObject(temp); +} + +// Add and remove a document from the manager's list +void wxDocManager::AddDocument(wxDocument *doc) +{ + if (!m_docs.Member(doc)) + m_docs.Append(doc); +} + +void wxDocManager::RemoveDocument(wxDocument *doc) +{ + m_docs.DeleteObject(doc); +} + +// Views or windows should inform the document manager +// when a view is going in or out of focus +void wxDocManager::ActivateView(wxView *view, bool activate) +{ + if ( activate ) + { + m_currentView = view; + } + else // deactivate + { + if ( m_currentView == view ) + { + // don't keep stale pointer + m_currentView = (wxView *) NULL; + } + } +} + +// ---------------------------------------------------------------------------- +// Default document child frame +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxDocChildFrame, wxFrame) + EVT_ACTIVATE(wxDocChildFrame::OnActivate) + EVT_CLOSE(wxDocChildFrame::OnCloseWindow) +END_EVENT_TABLE() + +wxDocChildFrame::wxDocChildFrame(wxDocument *doc, + wxView *view, + wxFrame *frame, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) + : wxFrame(frame, id, title, pos, size, style, name) +{ + m_childDocument = doc; + m_childView = view; + if (view) + view->SetFrame(this); +} + +// Extend event processing to search the view's event table +bool wxDocChildFrame::ProcessEvent(wxEvent& event) +{ + if (m_childView) + m_childView->Activate(true); + + if ( !m_childView || ! m_childView->ProcessEvent(event) ) + { + // Only hand up to the parent if it's a menu command + if (!event.IsKindOf(CLASSINFO(wxCommandEvent)) || !GetParent() || !GetParent()->ProcessEvent(event)) + return wxEvtHandler::ProcessEvent(event); + else + return true; + } + else + return true; +} + +void wxDocChildFrame::OnActivate(wxActivateEvent& event) +{ + wxFrame::OnActivate(event); + + if (m_childView) + m_childView->Activate(event.GetActive()); +} + +void wxDocChildFrame::OnCloseWindow(wxCloseEvent& event) +{ + if (m_childView) + { + bool ans = event.CanVeto() + ? m_childView->Close(false) // false means don't delete associated window + : true; // Must delete. + + if (ans) + { + m_childView->Activate(false); + delete m_childView; + m_childView = (wxView *) NULL; + m_childDocument = (wxDocument *) NULL; + + this->Destroy(); + } + else + event.Veto(); + } + else + event.Veto(); +} + +// ---------------------------------------------------------------------------- +// Default parent frame +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxDocParentFrame, wxFrame) + EVT_MENU(wxID_EXIT, wxDocParentFrame::OnExit) + EVT_MENU_RANGE(wxID_FILE1, wxID_FILE9, wxDocParentFrame::OnMRUFile) + EVT_CLOSE(wxDocParentFrame::OnCloseWindow) +END_EVENT_TABLE() + +wxDocParentFrame::wxDocParentFrame() +{ + m_docManager = NULL; +} + +wxDocParentFrame::wxDocParentFrame(wxDocManager *manager, + wxFrame *frame, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) + : wxFrame(frame, id, title, pos, size, style, name) +{ + m_docManager = manager; +} + +bool wxDocParentFrame::Create(wxDocManager *manager, + wxFrame *frame, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + m_docManager = manager; + return base_type::Create(frame, id, title, pos, size, style, name); +} + +void wxDocParentFrame::OnExit(wxCommandEvent& WXUNUSED(event)) +{ + Close(); +} + +void wxDocParentFrame::OnMRUFile(wxCommandEvent& event) +{ + int n = event.GetId() - wxID_FILE1; // the index in MRU list + wxString filename(m_docManager->GetHistoryFile(n)); + if ( !filename.empty() ) + { + // verify that the file exists before doing anything else + if ( wxFile::Exists(filename) ) + { + // try to open it + if (!m_docManager->CreateDocument(filename, wxDOC_SILENT)) + { + // remove the file from the MRU list. The user should already be notified. + m_docManager->RemoveFileFromHistory(n); + + wxLogError(_("The file '%s' couldn't be opened.\nIt has been removed from the most recently used files list."), + filename.c_str()); + } + } + else + { + // remove the bogus filename from the MRU list and notify the user + // about it + m_docManager->RemoveFileFromHistory(n); + + wxLogError(_("The file '%s' doesn't exist and couldn't be opened.\nIt has been removed from the most recently used files list."), + filename.c_str()); + } + } +} + +// Extend event processing to search the view's event table +bool wxDocParentFrame::ProcessEvent(wxEvent& event) +{ + // Try the document manager, then do default processing + if (!m_docManager || !m_docManager->ProcessEvent(event)) + return wxEvtHandler::ProcessEvent(event); + else + return true; +} + +// Define the behaviour for the frame closing +// - must delete all frames except for the main one. +void wxDocParentFrame::OnCloseWindow(wxCloseEvent& event) +{ + if ( m_docManager && !m_docManager->Clear(!event.CanVeto()) ) + { + // The user decided not to close finally, abort. + event.Veto(); + } + else + { + this->Destroy(); + } +} + +#if wxUSE_PRINTING_ARCHITECTURE + +wxDocPrintout::wxDocPrintout(wxView *view, const wxString& title) + : wxPrintout(title) +{ + m_printoutView = view; +} + +bool wxDocPrintout::OnPrintPage(int WXUNUSED(page)) +{ + wxDC *dc = GetDC(); + + // Get the logical pixels per inch of screen and printer + int ppiScreenX, ppiScreenY; + GetPPIScreen(&ppiScreenX, &ppiScreenY); + wxUnusedVar(ppiScreenY); + int ppiPrinterX, ppiPrinterY; + GetPPIPrinter(&ppiPrinterX, &ppiPrinterY); + wxUnusedVar(ppiPrinterY); + + // This scales the DC so that the printout roughly represents the + // the screen scaling. The text point size _should_ be the right size + // but in fact is too small for some reason. This is a detail that will + // need to be addressed at some point but can be fudged for the + // moment. + float scale = (float)((float)ppiPrinterX/(float)ppiScreenX); + + // Now we have to check in case our real page size is reduced + // (e.g. because we're drawing to a print preview memory DC) + int pageWidth, pageHeight; + int w, h; + dc->GetSize(&w, &h); + GetPageSizePixels(&pageWidth, &pageHeight); + wxUnusedVar(pageHeight); + + // If printer pageWidth == current DC width, then this doesn't + // change. But w might be the preview bitmap width, so scale down. + float overallScale = scale * (float)(w/(float)pageWidth); + dc->SetUserScale(overallScale, overallScale); + + if (m_printoutView) + { + m_printoutView->OnDraw(dc); + } + return true; +} + +bool wxDocPrintout::HasPage(int pageNum) +{ + return (pageNum == 1); +} + +bool wxDocPrintout::OnBeginDocument(int startPage, int endPage) +{ + if (!wxPrintout::OnBeginDocument(startPage, endPage)) + return false; + + return true; +} + +void wxDocPrintout::GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo) +{ + *minPage = 1; + *maxPage = 1; + *selPageFrom = 1; + *selPageTo = 1; +} + +#endif // wxUSE_PRINTING_ARCHITECTURE + +// ---------------------------------------------------------------------------- +// File history processor +// ---------------------------------------------------------------------------- + +static inline wxChar* MYcopystring(const wxString& s) +{ + wxChar* copy = new wxChar[s.length() + 1]; + return wxStrcpy(copy, s.c_str()); +} + +static inline wxChar* MYcopystring(const wxChar* s) +{ + wxChar* copy = new wxChar[wxStrlen(s) + 1]; + return wxStrcpy(copy, s); +} + +wxFileHistory::wxFileHistory(size_t maxFiles, wxWindowID idBase) +{ + m_fileMaxFiles = maxFiles; + m_idBase = idBase; + m_fileHistoryN = 0; + m_fileHistory = new wxChar *[m_fileMaxFiles]; +} + +wxFileHistory::~wxFileHistory() +{ + size_t i; + for (i = 0; i < m_fileHistoryN; i++) + delete[] m_fileHistory[i]; + delete[] m_fileHistory; +} + +// File history management +void wxFileHistory::AddFileToHistory(const wxString& file) +{ + size_t i; + + // Check we don't already have this file + for (i = 0; i < m_fileHistoryN; i++) + { +#if defined( __WXMSW__ ) // Add any other OSes with case insensitive file names + wxString testString; + if ( m_fileHistory[i] ) + testString = m_fileHistory[i]; + if ( m_fileHistory[i] && ( file.Lower() == testString.Lower() ) ) +#else + if ( m_fileHistory[i] && ( file == m_fileHistory[i] ) ) +#endif + { + // we do have it, move it to the top of the history + RemoveFileFromHistory (i); + AddFileToHistory (file); + return; + } + } + + // if we already have a full history, delete the one at the end + if ( m_fileMaxFiles == m_fileHistoryN ) + { + RemoveFileFromHistory (m_fileHistoryN - 1); + AddFileToHistory (file); + return; + } + + // Add to the project file history: + // Move existing files (if any) down so we can insert file at beginning. + if (m_fileHistoryN < m_fileMaxFiles) + { + wxList::compatibility_iterator node = m_fileMenus.GetFirst(); + while (node) + { + wxMenu* menu = (wxMenu*) node->GetData(); + if ( m_fileHistoryN == 0 && menu->GetMenuItemCount() ) + { + menu->AppendSeparator(); + } + menu->Append(m_idBase+m_fileHistoryN, _("[EMPTY]")); + node = node->GetNext(); + } + m_fileHistoryN ++; + } + // Shuffle filenames down + for (i = (m_fileHistoryN-1); i > 0; i--) + { + m_fileHistory[i] = m_fileHistory[i-1]; + } + m_fileHistory[0] = MYcopystring(file); + + // this is the directory of the last opened file + wxString pathCurrent; + wxSplitPath( m_fileHistory[0], &pathCurrent, NULL, NULL ); + for (i = 0; i < m_fileHistoryN; i++) + { + if ( m_fileHistory[i] ) + { + // if in same directory just show the filename; otherwise the full + // path + wxString pathInMenu, path, filename, ext; + wxSplitPath( m_fileHistory[i], &path, &filename, &ext ); + if ( path == pathCurrent ) + { + pathInMenu = filename; + if ( !ext.empty() ) + pathInMenu = pathInMenu + wxFILE_SEP_EXT + ext; + } + else + { + // absolute path; could also set relative path + pathInMenu = m_fileHistory[i]; + } + + // we need to quote '&' characters which are used for mnemonics + pathInMenu.Replace(_T("&"), _T("&&")); + wxString buf; + buf.Printf(s_MRUEntryFormat, i + 1, pathInMenu.c_str()); + wxList::compatibility_iterator node = m_fileMenus.GetFirst(); + while (node) + { + wxMenu* menu = (wxMenu*) node->GetData(); + menu->SetLabel(m_idBase + i, buf); + node = node->GetNext(); + } + } + } +} + +void wxFileHistory::RemoveFileFromHistory(size_t i) +{ + wxCHECK_RET( i < m_fileHistoryN, + wxT("invalid index in wxFileHistory::RemoveFileFromHistory") ); + + // delete the element from the array (could use memmove() too...) + delete [] m_fileHistory[i]; + + size_t j; + for ( j = i; j < m_fileHistoryN - 1; j++ ) + { + m_fileHistory[j] = m_fileHistory[j + 1]; + } + + wxList::compatibility_iterator node = m_fileMenus.GetFirst(); + while ( node ) + { + wxMenu* menu = (wxMenu*) node->GetData(); + + // shuffle filenames up + wxString buf; + for ( j = i; j < m_fileHistoryN - 1; j++ ) + { + buf.Printf(s_MRUEntryFormat, j + 1, m_fileHistory[j]); + menu->SetLabel(m_idBase + j, buf); + } + + node = node->GetNext(); + + // delete the last menu item which is unused now + wxWindowID lastItemId = m_idBase + wx_truncate_cast(wxWindowID, m_fileHistoryN) - 1; + if (menu->FindItem(lastItemId)) + { + menu->Delete(lastItemId); + } + + // delete the last separator too if no more files are left + if ( m_fileHistoryN == 1 ) + { + wxMenuItemList::compatibility_iterator nodeLast = menu->GetMenuItems().GetLast(); + if ( nodeLast ) + { + wxMenuItem *menuItem = nodeLast->GetData(); + if ( menuItem->IsSeparator() ) + { + menu->Delete(menuItem); + } + //else: should we search backwards for the last separator? + } + //else: menu is empty somehow + } + } + + m_fileHistoryN--; +} + +wxString wxFileHistory::GetHistoryFile(size_t i) const +{ + wxString s; + if ( i < m_fileHistoryN ) + { + s = m_fileHistory[i]; + } + else + { + wxFAIL_MSG( wxT("bad index in wxFileHistory::GetHistoryFile") ); + } + + return s; +} + +void wxFileHistory::UseMenu(wxMenu *menu) +{ + if (!m_fileMenus.Member(menu)) + m_fileMenus.Append(menu); +} + +void wxFileHistory::RemoveMenu(wxMenu *menu) +{ + m_fileMenus.DeleteObject(menu); +} + +#if wxUSE_CONFIG +void wxFileHistory::Load(wxConfigBase& config) +{ + m_fileHistoryN = 0; + wxString buf; + buf.Printf(wxT("file%d"), (int)m_fileHistoryN+1); + wxString historyFile; + while ((m_fileHistoryN < m_fileMaxFiles) && config.Read(buf, &historyFile) && (!historyFile.empty())) + { + m_fileHistory[m_fileHistoryN] = MYcopystring((const wxChar*) historyFile); + m_fileHistoryN ++; + buf.Printf(wxT("file%d"), (int)m_fileHistoryN+1); + historyFile = wxEmptyString; + } + AddFilesToMenu(); +} + +void wxFileHistory::Save(wxConfigBase& config) +{ + size_t i; + for (i = 0; i < m_fileMaxFiles; i++) + { + wxString buf; + buf.Printf(wxT("file%d"), (int)i+1); + if (i < m_fileHistoryN) + config.Write(buf, wxString(m_fileHistory[i])); + else + config.Write(buf, wxEmptyString); + } +} +#endif // wxUSE_CONFIG + +void wxFileHistory::AddFilesToMenu() +{ + if (m_fileHistoryN > 0) + { + wxList::compatibility_iterator node = m_fileMenus.GetFirst(); + while (node) + { + wxMenu* menu = (wxMenu*) node->GetData(); + if (menu->GetMenuItemCount()) + { + menu->AppendSeparator(); + } + + size_t i; + for (i = 0; i < m_fileHistoryN; i++) + { + if (m_fileHistory[i]) + { + wxString buf; + buf.Printf(s_MRUEntryFormat, i+1, m_fileHistory[i]); + menu->Append(m_idBase+i, buf); + } + } + node = node->GetNext(); + } + } +} + +void wxFileHistory::AddFilesToMenu(wxMenu* menu) +{ + if (m_fileHistoryN > 0) + { + if (menu->GetMenuItemCount()) + { + menu->AppendSeparator(); + } + + size_t i; + for (i = 0; i < m_fileHistoryN; i++) + { + if (m_fileHistory[i]) + { + wxString buf; + buf.Printf(s_MRUEntryFormat, i+1, m_fileHistory[i]); + menu->Append(m_idBase+i, buf); + } + } + } +} + +// ---------------------------------------------------------------------------- +// Permits compatibility with existing file formats and functions that +// manipulate files directly +// ---------------------------------------------------------------------------- + +#if wxUSE_STD_IOSTREAM + +bool wxTransferFileToStream(const wxString& filename, wxSTD ostream& stream) +{ + wxFFile file(filename, _T("rb")); + if ( !file.IsOpened() ) + return false; + + char buf[4096]; + + size_t nRead; + do + { + nRead = file.Read(buf, WXSIZEOF(buf)); + if ( file.Error() ) + return false; + + stream.write(buf, nRead); + if ( !stream ) + return false; + } + while ( !file.Eof() ); + + return true; +} + +bool wxTransferStreamToFile(wxSTD istream& stream, const wxString& filename) +{ + wxFFile file(filename, _T("wb")); + if ( !file.IsOpened() ) + return false; + + char buf[4096]; + do + { + stream.read(buf, WXSIZEOF(buf)); + if ( !stream.bad() ) // fail may be set on EOF, don't use operator!() + { + if ( !file.Write(buf, stream.gcount()) ) + return false; + } + } + while ( !stream.eof() ); + + return true; +} + +#else // !wxUSE_STD_IOSTREAM + +bool wxTransferFileToStream(const wxString& filename, wxOutputStream& stream) +{ + wxFFile file(filename, _T("rb")); + if ( !file.IsOpened() ) + return false; + + char buf[4096]; + + size_t nRead; + do + { + nRead = file.Read(buf, WXSIZEOF(buf)); + if ( file.Error() ) + return false; + + stream.Write(buf, nRead); + if ( !stream ) + return false; + } + while ( !file.Eof() ); + + return true; +} + +bool wxTransferStreamToFile(wxInputStream& stream, const wxString& filename) +{ + wxFFile file(filename, _T("wb")); + if ( !file.IsOpened() ) + return false; + + char buf[4096]; + for ( ;; ) + { + stream.Read(buf, WXSIZEOF(buf)); + + const size_t nRead = stream.LastRead(); + if ( !nRead ) + { + if ( stream.Eof() ) + break; + + return false; + } + + if ( !file.Write(buf, nRead) ) + return false; + } + + return true; +} + +#endif // wxUSE_STD_IOSTREAM/!wxUSE_STD_IOSTREAM + +#endif // wxUSE_DOC_VIEW_ARCHITECTURE diff --git a/Source/3rd Party/wx/src/common/dpycmn.cpp b/Source/3rd Party/wx/src/common/dpycmn.cpp index 5d8d3e706..4cc0e4435 100644 --- a/Source/3rd Party/wx/src/common/dpycmn.cpp +++ b/Source/3rd Party/wx/src/common/dpycmn.cpp @@ -1,269 +1,269 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/dpycmn.cpp -// Purpose: wxDisplay and wxDisplayImplSingle implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 01.03.03 -// RCS-ID: $Id: dpycmn.cpp 41548 2006-10-02 05:38:05Z PC $ -// Copyright: (c) 2003-2006 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/gdicmn.h" - #include "wx/window.h" - #include "wx/module.h" -#endif //WX_PRECOMP - -#include "wx/display.h" -#include "wx/display_impl.h" - -#if wxUSE_DISPLAY - -#include "wx/arrimpl.cpp" -WX_DEFINE_OBJARRAY(wxArrayVideoModes) - -const wxVideoMode wxDefaultVideoMode; - -#endif // wxUSE_DISPLAY - -// ---------------------------------------------------------------------------- -// globals -// ---------------------------------------------------------------------------- - -// the factory object used by wxDisplay -// -// created on demand and destroyed by wxDisplayModule -static wxDisplayFactory *gs_factory = NULL; - -// ---------------------------------------------------------------------------- -// wxDisplayImplSingle: trivial implementation working for main display only -// ---------------------------------------------------------------------------- - -class WXDLLEXPORT wxDisplayImplSingle : public wxDisplayImpl -{ -public: - wxDisplayImplSingle() : wxDisplayImpl(0) { } - - virtual wxRect GetGeometry() const - { - wxRect r; - wxDisplaySize(&r.width, &r.height); - return r; - } - - virtual wxRect GetClientArea() const { return wxGetClientDisplayRect(); } - - virtual wxString GetName() const { return wxString(); } - -#if wxUSE_DISPLAY - // no video modes support for us, provide just the stubs - - virtual wxArrayVideoModes GetModes(const wxVideoMode& WXUNUSED(mode)) const - { - return wxArrayVideoModes(); - } - - virtual wxVideoMode GetCurrentMode() const { return wxVideoMode(); } - - virtual bool ChangeMode(const wxVideoMode& WXUNUSED(mode)) { return false; } -#endif // wxUSE_DISPLAY - - - DECLARE_NO_COPY_CLASS(wxDisplayImplSingle) -}; - -// ---------------------------------------------------------------------------- -// wxDisplayModule is used to cleanup gs_factory -// ---------------------------------------------------------------------------- - -class wxDisplayModule : public wxModule -{ -public: - virtual bool OnInit() { return true; } - virtual void OnExit() - { - if ( gs_factory ) - { - delete gs_factory; - gs_factory = NULL; - } - } - - DECLARE_DYNAMIC_CLASS(wxDisplayModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxDisplayModule, wxModule) - -// ============================================================================ -// wxDisplay implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// ctor/dtor -// ---------------------------------------------------------------------------- - -wxDisplay::wxDisplay(unsigned n) -{ - wxASSERT_MSG( n < GetCount(), - wxT("An invalid index was passed to wxDisplay") ); - - m_impl = Factory().CreateDisplay(n); -} - -wxDisplay::~wxDisplay() -{ - delete m_impl; -} - -// ---------------------------------------------------------------------------- -// static functions forwarded to wxDisplayFactory -// ---------------------------------------------------------------------------- - -/* static */ unsigned wxDisplay::GetCount() -{ - return Factory().GetCount(); -} - -/* static */ int wxDisplay::GetFromPoint(const wxPoint& pt) -{ - return Factory().GetFromPoint(pt); -} - -/* static */ int wxDisplay::GetFromWindow(wxWindow *window) -{ - wxCHECK_MSG( window, wxNOT_FOUND, _T("invalid window") ); - - return Factory().GetFromWindow(window); -} - -// ---------------------------------------------------------------------------- -// functions forwarded to wxDisplayImpl -// ---------------------------------------------------------------------------- - -wxRect wxDisplay::GetGeometry() const -{ - wxCHECK_MSG( IsOk(), wxRect(), _T("invalid wxDisplay object") ); - - return m_impl->GetGeometry(); -} - -wxRect wxDisplay::GetClientArea() const -{ - wxCHECK_MSG( IsOk(), wxRect(), _T("invalid wxDisplay object") ); - - return m_impl->GetClientArea(); -} - -wxString wxDisplay::GetName() const -{ - wxCHECK_MSG( IsOk(), wxString(), _T("invalid wxDisplay object") ); - - return m_impl->GetName(); -} - -bool wxDisplay::IsPrimary() const -{ - return m_impl && m_impl->GetIndex() == 0; -} - -#if wxUSE_DISPLAY - -wxArrayVideoModes wxDisplay::GetModes(const wxVideoMode& mode) const -{ - wxCHECK_MSG( IsOk(), wxArrayVideoModes(), _T("invalid wxDisplay object") ); - - return m_impl->GetModes(mode); -} - -wxVideoMode wxDisplay::GetCurrentMode() const -{ - wxCHECK_MSG( IsOk(), wxVideoMode(), _T("invalid wxDisplay object") ); - - return m_impl->GetCurrentMode(); -} - -bool wxDisplay::ChangeMode(const wxVideoMode& mode) -{ - wxCHECK_MSG( IsOk(), false, _T("invalid wxDisplay object") ); - - return m_impl->ChangeMode(mode); -} - -#endif // wxUSE_DIRECTDRAW - -// ---------------------------------------------------------------------------- -// static functions implementation -// ---------------------------------------------------------------------------- - -// if wxUSE_DISPLAY == 1 this is implemented in port-specific code -#if !wxUSE_DISPLAY - -/* static */ wxDisplayFactory *wxDisplay::CreateFactory() -{ - return new wxDisplayFactorySingle; -} - -#endif // !wxUSE_DISPLAY - -/* static */ wxDisplayFactory& wxDisplay::Factory() -{ - if ( !gs_factory ) - { - gs_factory = CreateFactory(); - } - - return *gs_factory; -} - -// ============================================================================ -// wxDisplayFactory implementation -// ============================================================================ - -int wxDisplayFactory::GetFromWindow(wxWindow *window) -{ - // consider that the window belongs to the display containing its centre - const wxRect r(window->GetRect()); - return GetFromPoint(wxPoint(r.x + r.width/2, r.y + r.height/2)); -} - -// ============================================================================ -// wxDisplayFactorySingle implementation -// ============================================================================ - -/* static */ -wxDisplayImpl *wxDisplayFactorySingle::CreateDisplay(unsigned n) -{ - // we recognize the main display only - return n != 0 ? NULL : new wxDisplayImplSingle; -} - -int wxDisplayFactorySingle::GetFromPoint(const wxPoint& pt) -{ - if ( pt.x >= 0 && pt.y >= 0 ) - { - int w, h; - wxDisplaySize(&w, &h); - - if ( pt.x < w && pt.y < h ) - return 0; - } - - // the point is outside of the screen - return wxNOT_FOUND; -} +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/dpycmn.cpp +// Purpose: wxDisplay and wxDisplayImplSingle implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 01.03.03 +// RCS-ID: $Id: dpycmn.cpp 41548 2006-10-02 05:38:05Z PC $ +// Copyright: (c) 2003-2006 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/gdicmn.h" + #include "wx/window.h" + #include "wx/module.h" +#endif //WX_PRECOMP + +#include "wx/display.h" +#include "wx/display_impl.h" + +#if wxUSE_DISPLAY + +#include "wx/arrimpl.cpp" +WX_DEFINE_OBJARRAY(wxArrayVideoModes) + +const wxVideoMode wxDefaultVideoMode; + +#endif // wxUSE_DISPLAY + +// ---------------------------------------------------------------------------- +// globals +// ---------------------------------------------------------------------------- + +// the factory object used by wxDisplay +// +// created on demand and destroyed by wxDisplayModule +static wxDisplayFactory *gs_factory = NULL; + +// ---------------------------------------------------------------------------- +// wxDisplayImplSingle: trivial implementation working for main display only +// ---------------------------------------------------------------------------- + +class WXDLLEXPORT wxDisplayImplSingle : public wxDisplayImpl +{ +public: + wxDisplayImplSingle() : wxDisplayImpl(0) { } + + virtual wxRect GetGeometry() const + { + wxRect r; + wxDisplaySize(&r.width, &r.height); + return r; + } + + virtual wxRect GetClientArea() const { return wxGetClientDisplayRect(); } + + virtual wxString GetName() const { return wxString(); } + +#if wxUSE_DISPLAY + // no video modes support for us, provide just the stubs + + virtual wxArrayVideoModes GetModes(const wxVideoMode& WXUNUSED(mode)) const + { + return wxArrayVideoModes(); + } + + virtual wxVideoMode GetCurrentMode() const { return wxVideoMode(); } + + virtual bool ChangeMode(const wxVideoMode& WXUNUSED(mode)) { return false; } +#endif // wxUSE_DISPLAY + + + DECLARE_NO_COPY_CLASS(wxDisplayImplSingle) +}; + +// ---------------------------------------------------------------------------- +// wxDisplayModule is used to cleanup gs_factory +// ---------------------------------------------------------------------------- + +class wxDisplayModule : public wxModule +{ +public: + virtual bool OnInit() { return true; } + virtual void OnExit() + { + if ( gs_factory ) + { + delete gs_factory; + gs_factory = NULL; + } + } + + DECLARE_DYNAMIC_CLASS(wxDisplayModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxDisplayModule, wxModule) + +// ============================================================================ +// wxDisplay implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// ctor/dtor +// ---------------------------------------------------------------------------- + +wxDisplay::wxDisplay(unsigned n) +{ + wxASSERT_MSG( n < GetCount(), + wxT("An invalid index was passed to wxDisplay") ); + + m_impl = Factory().CreateDisplay(n); +} + +wxDisplay::~wxDisplay() +{ + delete m_impl; +} + +// ---------------------------------------------------------------------------- +// static functions forwarded to wxDisplayFactory +// ---------------------------------------------------------------------------- + +/* static */ unsigned wxDisplay::GetCount() +{ + return Factory().GetCount(); +} + +/* static */ int wxDisplay::GetFromPoint(const wxPoint& pt) +{ + return Factory().GetFromPoint(pt); +} + +/* static */ int wxDisplay::GetFromWindow(wxWindow *window) +{ + wxCHECK_MSG( window, wxNOT_FOUND, _T("invalid window") ); + + return Factory().GetFromWindow(window); +} + +// ---------------------------------------------------------------------------- +// functions forwarded to wxDisplayImpl +// ---------------------------------------------------------------------------- + +wxRect wxDisplay::GetGeometry() const +{ + wxCHECK_MSG( IsOk(), wxRect(), _T("invalid wxDisplay object") ); + + return m_impl->GetGeometry(); +} + +wxRect wxDisplay::GetClientArea() const +{ + wxCHECK_MSG( IsOk(), wxRect(), _T("invalid wxDisplay object") ); + + return m_impl->GetClientArea(); +} + +wxString wxDisplay::GetName() const +{ + wxCHECK_MSG( IsOk(), wxString(), _T("invalid wxDisplay object") ); + + return m_impl->GetName(); +} + +bool wxDisplay::IsPrimary() const +{ + return m_impl && m_impl->GetIndex() == 0; +} + +#if wxUSE_DISPLAY + +wxArrayVideoModes wxDisplay::GetModes(const wxVideoMode& mode) const +{ + wxCHECK_MSG( IsOk(), wxArrayVideoModes(), _T("invalid wxDisplay object") ); + + return m_impl->GetModes(mode); +} + +wxVideoMode wxDisplay::GetCurrentMode() const +{ + wxCHECK_MSG( IsOk(), wxVideoMode(), _T("invalid wxDisplay object") ); + + return m_impl->GetCurrentMode(); +} + +bool wxDisplay::ChangeMode(const wxVideoMode& mode) +{ + wxCHECK_MSG( IsOk(), false, _T("invalid wxDisplay object") ); + + return m_impl->ChangeMode(mode); +} + +#endif // wxUSE_DIRECTDRAW + +// ---------------------------------------------------------------------------- +// static functions implementation +// ---------------------------------------------------------------------------- + +// if wxUSE_DISPLAY == 1 this is implemented in port-specific code +#if !wxUSE_DISPLAY + +/* static */ wxDisplayFactory *wxDisplay::CreateFactory() +{ + return new wxDisplayFactorySingle; +} + +#endif // !wxUSE_DISPLAY + +/* static */ wxDisplayFactory& wxDisplay::Factory() +{ + if ( !gs_factory ) + { + gs_factory = CreateFactory(); + } + + return *gs_factory; +} + +// ============================================================================ +// wxDisplayFactory implementation +// ============================================================================ + +int wxDisplayFactory::GetFromWindow(wxWindow *window) +{ + // consider that the window belongs to the display containing its centre + const wxRect r(window->GetRect()); + return GetFromPoint(wxPoint(r.x + r.width/2, r.y + r.height/2)); +} + +// ============================================================================ +// wxDisplayFactorySingle implementation +// ============================================================================ + +/* static */ +wxDisplayImpl *wxDisplayFactorySingle::CreateDisplay(unsigned n) +{ + // we recognize the main display only + return n != 0 ? NULL : new wxDisplayImplSingle; +} + +int wxDisplayFactorySingle::GetFromPoint(const wxPoint& pt) +{ + if ( pt.x >= 0 && pt.y >= 0 ) + { + int w, h; + wxDisplaySize(&w, &h); + + if ( pt.x < w && pt.y < h ) + return 0; + } + + // the point is outside of the screen + return wxNOT_FOUND; +} diff --git a/Source/3rd Party/wx/src/common/dseldlg.cpp b/Source/3rd Party/wx/src/common/dseldlg.cpp index 060dcf326..04944fc65 100644 --- a/Source/3rd Party/wx/src/common/dseldlg.cpp +++ b/Source/3rd Party/wx/src/common/dseldlg.cpp @@ -1,55 +1,55 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/dseldlg.cpp -// Purpose: implementation of ::wxDirSelector() -// Author: Paul Thiessen -// Modified by: -// Created: 20.02.01 -// RCS-ID: $Id: dseldlg.cpp 39613 2006-06-07 11:44:19Z ABX $ -// Copyright: (c) 2001 wxWidgets team -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DIRDLG - -#include "wx/dirdlg.h" - -#ifndef WX_PRECOMP -#endif //WX_PRECOMP - -// ============================================================================ -// implementation -// ============================================================================ - -wxString wxDirSelector(const wxString& message, - const wxString& defaultPath, - long style, - const wxPoint& pos, - wxWindow *parent) -{ - wxString path; - - wxDirDialog dirDialog(parent, message, defaultPath, style, pos); - if ( dirDialog.ShowModal() == wxID_OK ) - { - path = dirDialog.GetPath(); - } - - return path; -} - -#endif // wxUSE_DIRDLG +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/dseldlg.cpp +// Purpose: implementation of ::wxDirSelector() +// Author: Paul Thiessen +// Modified by: +// Created: 20.02.01 +// RCS-ID: $Id: dseldlg.cpp 39613 2006-06-07 11:44:19Z ABX $ +// Copyright: (c) 2001 wxWidgets team +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DIRDLG + +#include "wx/dirdlg.h" + +#ifndef WX_PRECOMP +#endif //WX_PRECOMP + +// ============================================================================ +// implementation +// ============================================================================ + +wxString wxDirSelector(const wxString& message, + const wxString& defaultPath, + long style, + const wxPoint& pos, + wxWindow *parent) +{ + wxString path; + + wxDirDialog dirDialog(parent, message, defaultPath, style, pos); + if ( dirDialog.ShowModal() == wxID_OK ) + { + path = dirDialog.GetPath(); + } + + return path; +} + +#endif // wxUSE_DIRDLG diff --git a/Source/3rd Party/wx/src/common/dummy.cpp b/Source/3rd Party/wx/src/common/dummy.cpp index 34719e674..db74ef7c6 100644 --- a/Source/3rd Party/wx/src/common/dummy.cpp +++ b/Source/3rd Party/wx/src/common/dummy.cpp @@ -1,32 +1,32 @@ -/* - * File: src/common/dummy.cpp - * Purpose: See below - * Author: Julian Smart - * Created: 1993 - * Updated: - * Copyright: (c) 1993, AIAI, University of Edinburgh - */ - -/* A dummy file to include wx.h. If precompiling wx.h, - * always start by compiling this and producing the PCH file. - * Then subsequent source files use the PCH file. - * - * If precompiling wx.h for wxWidgets and derived apps, - * link dummy.obj with your program. - * - * This will produce a big PCH file. - */ - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifdef __WXMSW__ - #include "wx/msw/msvcrt.h" -#endif - -#ifdef __VISAGECPP__ - char wxDummyChar = 0; -#endif +/* + * File: src/common/dummy.cpp + * Purpose: See below + * Author: Julian Smart + * Created: 1993 + * Updated: + * Copyright: (c) 1993, AIAI, University of Edinburgh + */ + +/* A dummy file to include wx.h. If precompiling wx.h, + * always start by compiling this and producing the PCH file. + * Then subsequent source files use the PCH file. + * + * If precompiling wx.h for wxWidgets and derived apps, + * link dummy.obj with your program. + * + * This will produce a big PCH file. + */ + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifdef __WXMSW__ + #include "wx/msw/msvcrt.h" +#endif + +#ifdef __VISAGECPP__ + char wxDummyChar = 0; +#endif diff --git a/Source/3rd Party/wx/src/common/dynarray.cpp b/Source/3rd Party/wx/src/common/dynarray.cpp index bdde0eafe..b5f2b4bc7 100644 --- a/Source/3rd Party/wx/src/common/dynarray.cpp +++ b/Source/3rd Party/wx/src/common/dynarray.cpp @@ -1,527 +1,527 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/dynarray.cpp -// Purpose: implementation of wxBaseArray class -// Author: Vadim Zeitlin -// Modified by: -// Created: 12.09.97 -// RCS-ID: $Id: dynarray.cpp 43030 2006-11-04 12:51:01Z VZ $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// headers -// ============================================================================ - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/dynarray.h" - #include "wx/intl.h" -#endif //WX_PRECOMP - -#include -#include // for memmove - -// we cast the value to long from which we cast it to void * in IndexForInsert: -// this can't work if the pointers are not big enough -wxCOMPILE_TIME_ASSERT( sizeof(wxUIntPtr) <= sizeof(void *), - wxArraySizeOfPtrLessSizeOfLong ); // < 32 symbols - -// ============================================================================ -// constants -// ============================================================================ - -// size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT) -#define ARRAY_MAXSIZE_INCREMENT 4096 - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxBaseArray - dynamic array of 'T's -// ---------------------------------------------------------------------------- - -#define _WX_DEFINE_BASEARRAY_COMMON(T, name) \ -/* searches the array for an item (forward or backwards) */ \ -int name::Index(T lItem, bool bFromEnd) const \ -{ \ - if ( bFromEnd ) { \ - if ( size() > 0 ) { \ - size_t n = size(); \ - do { \ - if ( (*this)[--n] == lItem ) \ - return n; \ - } \ - while ( n != 0 ); \ - } \ - } \ - else { \ - for( size_t n = 0; n < size(); n++ ) { \ - if( (*this)[n] == lItem ) \ - return n; \ - } \ - } \ - \ - return wxNOT_FOUND; \ -} \ - \ -/* add item assuming the array is sorted with fnCompare function */ \ -size_t name::Add(T lItem, CMPFUNC fnCompare) \ -{ \ - size_t idx = IndexForInsert(lItem, fnCompare); \ - Insert(lItem, idx); \ - return idx; \ -} - -#if wxUSE_STL - -#define _WX_DEFINE_BASEARRAY_NOCOMMON(T, name) \ -size_t name::IndexForInsert(T lItem, CMPFUNC fnCompare) const \ -{ \ - Predicate p((SCMPFUNC)fnCompare); \ - const_iterator it = std::lower_bound(begin(), end(), lItem, p); \ - return it - begin(); \ -} \ - \ -int name::Index(T lItem, CMPFUNC fnCompare) const \ -{ \ - Predicate p((SCMPFUNC)fnCompare); \ - const_iterator it = std::lower_bound(begin(), end(), lItem, p); \ - return (it != end() && !p(lItem, *it)) ? \ - (int)(it - begin()) : wxNOT_FOUND; \ -} \ - \ -void name::Shrink() \ -{ \ - name tmp(*this); \ - swap(tmp); \ -} - -#else // if !wxUSE_STL - -#define _WX_DEFINE_BASEARRAY_NOCOMMON(T, name) \ -/* ctor */ \ -name::name() \ -{ \ - m_nSize = \ - m_nCount = 0; \ - m_pItems = (T *)NULL; \ -} \ - \ -/* copy ctor */ \ -name::name(const name& src) \ -{ \ - m_nSize = /* not src.m_nSize to save memory */ \ - m_nCount = src.m_nCount; \ - \ - if ( m_nSize != 0 ) { \ - m_pItems = new T[m_nSize]; \ - /* only copy if allocation succeeded */ \ - if ( m_pItems ) { \ - memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(T)); \ - } \ - else { \ - m_nSize = 0; \ - } \ - } \ - else \ - m_pItems = (T *) NULL; \ -} \ - \ -/* assignment operator */ \ -name& name::operator=(const name& src) \ -{ \ - wxDELETEA(m_pItems); \ - \ - m_nSize = /* not src.m_nSize to save memory */ \ - m_nCount = src.m_nCount; \ - \ - if ( m_nSize != 0 ){ \ - m_pItems = new T[m_nSize]; \ - /* only copy if allocation succeeded */ \ - if ( m_pItems ) { \ - memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(T)); \ - } \ - else { \ - m_nSize = 0; \ - } \ - } \ - else \ - m_pItems = (T *) NULL; \ - \ - return *this; \ -} \ - \ -/* allocate new buffer of the given size and move our data to it */ \ -bool name::Realloc(size_t nSize) \ -{ \ - T *pNew = new T[nSize]; \ - /* only grow if allocation succeeded */ \ - if ( !pNew ) \ - return false; \ - \ - m_nSize = nSize; \ - /* copy data to new location */ \ - memcpy(pNew, m_pItems, m_nCount*sizeof(T)); \ - delete [] m_pItems; \ - m_pItems = pNew; \ - \ - return true; \ -} \ - \ -/* grow the array */ \ -void name::Grow(size_t nIncrement) \ -{ \ - /* only do it if no more place */ \ - if( (m_nCount == m_nSize) || ((m_nSize - m_nCount) < nIncrement) ) { \ - if( m_nSize == 0 ) { \ - /* was empty, determine initial size */ \ - size_t size = WX_ARRAY_DEFAULT_INITIAL_SIZE; \ - if (size < nIncrement) size = nIncrement; \ - /* allocate some memory */ \ - m_pItems = new T[size]; \ - /* only grow if allocation succeeded */ \ - if ( m_pItems ) { \ - m_nSize = size; \ - } \ - } \ - else \ - { \ - /* add at least 50% but not too much */ \ - size_t ndefIncrement = m_nSize < WX_ARRAY_DEFAULT_INITIAL_SIZE \ - ? WX_ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1; \ - if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT ) \ - ndefIncrement = ARRAY_MAXSIZE_INCREMENT; \ - if ( nIncrement < ndefIncrement ) \ - nIncrement = ndefIncrement; \ - Realloc(m_nSize + nIncrement); \ - } \ - } \ -} \ - \ -/* make sure that the array has at least count elements */ \ -void name::SetCount(size_t count, T defval) \ -{ \ - if ( m_nSize < count ) \ - { \ - /* need to realloc memory: don't overallocate it here as if */ \ - /* SetCount() is called, it probably means that the caller */ \ - /* knows in advance how many elements there will be in the */ \ - /* array and so it won't be necessary to realloc it later */ \ - if ( !Realloc(count) ) \ - { \ - /* out of memory -- what can we do? */ \ - return; \ - } \ - } \ - \ - /* add new elements if we extend the array */ \ - while ( m_nCount < count ) \ - { \ - m_pItems[m_nCount++] = defval; \ - } \ -} \ - \ -/* dtor */ \ -name::~name() \ -{ \ - wxDELETEA(m_pItems); \ -} \ - \ -/* clears the list */ \ -void name::Clear() \ -{ \ - m_nSize = \ - m_nCount = 0; \ - \ - wxDELETEA(m_pItems); \ -} \ - \ -/* minimizes the memory usage by freeing unused memory */ \ -void name::Shrink() \ -{ \ - /* only do it if we have some memory to free */ \ - if( m_nCount < m_nSize ) { \ - /* allocates exactly as much memory as we need */ \ - T *pNew = new T[m_nCount]; \ - /* only shrink if allocation succeeded */ \ - if ( pNew ) { \ - /* copy data to new location */ \ - memcpy(pNew, m_pItems, m_nCount*sizeof(T)); \ - delete [] m_pItems; \ - m_pItems = pNew; \ - \ - /* update the size of the new block */ \ - m_nSize = m_nCount; \ - } \ - /* else: don't do anything, better keep old memory block! */ \ - } \ -} \ - \ -/* add item at the end */ \ -void name::Add(T lItem, size_t nInsert) \ -{ \ - if (nInsert == 0) \ - return; \ - Grow(nInsert); \ - for (size_t i = 0; i < nInsert; i++) \ - m_pItems[m_nCount++] = lItem; \ -} \ - \ -/* add item at the given position */ \ -void name::Insert(T lItem, size_t nIndex, size_t nInsert) \ -{ \ - wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArray::Insert") ); \ - wxCHECK_RET( m_nCount <= m_nCount + nInsert, \ - wxT("array size overflow in wxArray::Insert") ); \ - \ - if (nInsert == 0) \ - return; \ - Grow(nInsert); \ - \ - memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], \ - (m_nCount - nIndex)*sizeof(T)); \ - for (size_t i = 0; i < nInsert; i++) \ - m_pItems[nIndex + i] = lItem; \ - m_nCount += nInsert; \ -} \ - \ -/* search for a place to insert item into sorted array (binary search) */ \ -size_t name::IndexForInsert(T lItem, CMPFUNC fnCompare) const \ -{ \ - size_t i, \ - lo = 0, \ - hi = m_nCount; \ - int res; \ - \ - while ( lo < hi ) { \ - i = (lo + hi)/2; \ - \ - res = (*fnCompare)((const void *)(wxUIntPtr)lItem, \ - (const void *)(wxUIntPtr)(m_pItems[i])); \ - if ( res < 0 ) \ - hi = i; \ - else if ( res > 0 ) \ - lo = i + 1; \ - else { \ - lo = i; \ - break; \ - } \ - } \ - \ - return lo; \ -} \ - \ -/* search for an item in a sorted array (binary search) */ \ -int name::Index(T lItem, CMPFUNC fnCompare) const \ -{ \ - size_t n = IndexForInsert(lItem, fnCompare); \ - \ - return (n >= m_nCount || \ - (*fnCompare)((const void *)(wxUIntPtr)lItem, \ - ((const void *)(wxUIntPtr)m_pItems[n]))) \ - ? wxNOT_FOUND \ - : (int)n; \ -} \ - \ -/* removes item from array (by index) */ \ -void name::RemoveAt(size_t nIndex, size_t nRemove) \ -{ \ - wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArray::RemoveAt") ); \ - wxCHECK_RET( nIndex + nRemove <= m_nCount, \ - wxT("removing too many elements in wxArray::RemoveAt") ); \ - \ - memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove], \ - (m_nCount - nIndex - nRemove)*sizeof(T)); \ - m_nCount -= nRemove; \ -} \ - \ -/* removes item from array (by value) */ \ -void name::Remove(T lItem) \ -{ \ - int iIndex = Index(lItem); \ - \ - wxCHECK_RET( iIndex != wxNOT_FOUND, \ - wxT("removing inexistent item in wxArray::Remove") ); \ - \ - RemoveAt((size_t)iIndex); \ -} \ - \ -/* sort array elements using passed comparaison function */ \ -void name::Sort(CMPFUNC fCmp) \ -{ \ - qsort(m_pItems, m_nCount, sizeof(T), fCmp); \ -} \ - \ -void name::assign(const_iterator first, const_iterator last) \ -{ \ - clear(); \ - reserve(last - first); \ - for(; first != last; ++first) \ - push_back(*first); \ -} \ - \ -void name::assign(size_type n, const_reference v) \ -{ \ - clear(); \ - reserve(n); \ - for( size_type i = 0; i < n; ++i ) \ - push_back(v); \ -} \ - \ -void name::insert(iterator it, const_iterator first, const_iterator last) \ -{ \ - size_t nInsert = last - first, nIndex = it - begin(); \ - if (nInsert == 0) \ - return; \ - Grow(nInsert); \ - \ - memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], \ - (m_nCount - nIndex)*sizeof(T)); \ - for (size_t i = 0; i < nInsert; ++i, ++it, ++first) \ - *it = *first; \ - m_nCount += nInsert; \ -} - -#endif - -#define _WX_DEFINE_BASEARRAY(T, name) \ - _WX_DEFINE_BASEARRAY_COMMON(T, name) \ - _WX_DEFINE_BASEARRAY_NOCOMMON(T, name) - -#ifdef __INTELC__ - #pragma warning(push) - #pragma warning(disable: 1684) - #pragma warning(disable: 1572) -#endif - -_WX_DEFINE_BASEARRAY(const void *, wxBaseArrayPtrVoid) -_WX_DEFINE_BASEARRAY(char, wxBaseArrayChar) -_WX_DEFINE_BASEARRAY(short, wxBaseArrayShort) -_WX_DEFINE_BASEARRAY(int, wxBaseArrayInt) -_WX_DEFINE_BASEARRAY(long, wxBaseArrayLong) -_WX_DEFINE_BASEARRAY(size_t, wxBaseArraySizeT) -_WX_DEFINE_BASEARRAY(double, wxBaseArrayDouble) - -#ifdef __INTELC__ - #pragma warning(pop) -#endif - -#if wxUSE_STL -#include "wx/arrstr.h" - -#include "wx/beforestd.h" -#include -#include "wx/afterstd.h" - -_WX_DEFINE_BASEARRAY(wxString, wxBaseArrayStringBase) - -// some compilers (Sun CC being the only known example) distinguish between -// extern "C" functions and the functions with C++ linkage and ptr_fun and -// wxStringCompareLess can't take wxStrcmp/wxStricmp directly as arguments in -// this case, we need the wrappers below to make this work -inline int wxStrcmpCppWrapper(const wxChar *p, const wxChar *q) -{ - return wxStrcmp(p, q); -} - -inline int wxStricmpCppWrapper(const wxChar *p, const wxChar *q) -{ - return wxStricmp(p, q); -} - -int wxArrayString::Index(const wxChar* sz, bool bCase, bool WXUNUSED(bFromEnd)) const -{ - wxArrayString::const_iterator it; - - if (bCase) - { - it = std::find_if(begin(), end(), - std::not1( - std::bind2nd( - std::ptr_fun(wxStrcmpCppWrapper), sz))); - } - else // !bCase - { - it = std::find_if(begin(), end(), - std::not1( - std::bind2nd( - std::ptr_fun(wxStricmpCppWrapper), sz))); - } - - return it == end() ? wxNOT_FOUND : it - begin(); -} - -template -class wxStringCompareLess -{ -public: - wxStringCompareLess(F f) : m_f(f) { } - bool operator()(const wxChar* s1, const wxChar* s2) - { return m_f(s1, s2) < 0; } - bool operator()(const wxString& s1, const wxString& s2) - { return m_f(s1, s2) < 0; } -private: - F m_f; -}; - -template -wxStringCompareLess wxStringCompare(F f) -{ - return wxStringCompareLess(f); -} - -void wxArrayString::Sort(CompareFunction function) -{ - std::sort(begin(), end(), wxStringCompare(function)); -} - -void wxArrayString::Sort(bool reverseOrder) -{ - if (reverseOrder) - { - std::sort(begin(), end(), std::greater()); - } - else - { - std::sort(begin(), end()); - } -} - -int wxSortedArrayString::Index(const wxChar* sz, bool bCase, bool WXUNUSED(bFromEnd)) const -{ - wxSortedArrayString::const_iterator it; - wxString s(sz); - - if (bCase) - it = std::lower_bound(begin(), end(), s, - wxStringCompare(wxStrcmpCppWrapper)); - else - it = std::lower_bound(begin(), end(), s, - wxStringCompare(wxStricmpCppWrapper)); - - if (it == end()) - return wxNOT_FOUND; - - if (bCase) - { - if (wxStrcmp(it->c_str(), sz) != 0) - return wxNOT_FOUND; - } - else - { - if (wxStricmp(it->c_str(), sz) != 0) - return wxNOT_FOUND; - } - - return it - begin(); -} - -#endif +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/dynarray.cpp +// Purpose: implementation of wxBaseArray class +// Author: Vadim Zeitlin +// Modified by: +// Created: 12.09.97 +// RCS-ID: $Id: dynarray.cpp 43030 2006-11-04 12:51:01Z VZ $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// headers +// ============================================================================ + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/intl.h" +#endif //WX_PRECOMP + +#include +#include // for memmove + +// we cast the value to long from which we cast it to void * in IndexForInsert: +// this can't work if the pointers are not big enough +wxCOMPILE_TIME_ASSERT( sizeof(wxUIntPtr) <= sizeof(void *), + wxArraySizeOfPtrLessSizeOfLong ); // < 32 symbols + +// ============================================================================ +// constants +// ============================================================================ + +// size increment = max(50% of current size, ARRAY_MAXSIZE_INCREMENT) +#define ARRAY_MAXSIZE_INCREMENT 4096 + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxBaseArray - dynamic array of 'T's +// ---------------------------------------------------------------------------- + +#define _WX_DEFINE_BASEARRAY_COMMON(T, name) \ +/* searches the array for an item (forward or backwards) */ \ +int name::Index(T lItem, bool bFromEnd) const \ +{ \ + if ( bFromEnd ) { \ + if ( size() > 0 ) { \ + size_t n = size(); \ + do { \ + if ( (*this)[--n] == lItem ) \ + return n; \ + } \ + while ( n != 0 ); \ + } \ + } \ + else { \ + for( size_t n = 0; n < size(); n++ ) { \ + if( (*this)[n] == lItem ) \ + return n; \ + } \ + } \ + \ + return wxNOT_FOUND; \ +} \ + \ +/* add item assuming the array is sorted with fnCompare function */ \ +size_t name::Add(T lItem, CMPFUNC fnCompare) \ +{ \ + size_t idx = IndexForInsert(lItem, fnCompare); \ + Insert(lItem, idx); \ + return idx; \ +} + +#if wxUSE_STL + +#define _WX_DEFINE_BASEARRAY_NOCOMMON(T, name) \ +size_t name::IndexForInsert(T lItem, CMPFUNC fnCompare) const \ +{ \ + Predicate p((SCMPFUNC)fnCompare); \ + const_iterator it = std::lower_bound(begin(), end(), lItem, p); \ + return it - begin(); \ +} \ + \ +int name::Index(T lItem, CMPFUNC fnCompare) const \ +{ \ + Predicate p((SCMPFUNC)fnCompare); \ + const_iterator it = std::lower_bound(begin(), end(), lItem, p); \ + return (it != end() && !p(lItem, *it)) ? \ + (int)(it - begin()) : wxNOT_FOUND; \ +} \ + \ +void name::Shrink() \ +{ \ + name tmp(*this); \ + swap(tmp); \ +} + +#else // if !wxUSE_STL + +#define _WX_DEFINE_BASEARRAY_NOCOMMON(T, name) \ +/* ctor */ \ +name::name() \ +{ \ + m_nSize = \ + m_nCount = 0; \ + m_pItems = (T *)NULL; \ +} \ + \ +/* copy ctor */ \ +name::name(const name& src) \ +{ \ + m_nSize = /* not src.m_nSize to save memory */ \ + m_nCount = src.m_nCount; \ + \ + if ( m_nSize != 0 ) { \ + m_pItems = new T[m_nSize]; \ + /* only copy if allocation succeeded */ \ + if ( m_pItems ) { \ + memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(T)); \ + } \ + else { \ + m_nSize = 0; \ + } \ + } \ + else \ + m_pItems = (T *) NULL; \ +} \ + \ +/* assignment operator */ \ +name& name::operator=(const name& src) \ +{ \ + wxDELETEA(m_pItems); \ + \ + m_nSize = /* not src.m_nSize to save memory */ \ + m_nCount = src.m_nCount; \ + \ + if ( m_nSize != 0 ){ \ + m_pItems = new T[m_nSize]; \ + /* only copy if allocation succeeded */ \ + if ( m_pItems ) { \ + memcpy(m_pItems, src.m_pItems, m_nCount*sizeof(T)); \ + } \ + else { \ + m_nSize = 0; \ + } \ + } \ + else \ + m_pItems = (T *) NULL; \ + \ + return *this; \ +} \ + \ +/* allocate new buffer of the given size and move our data to it */ \ +bool name::Realloc(size_t nSize) \ +{ \ + T *pNew = new T[nSize]; \ + /* only grow if allocation succeeded */ \ + if ( !pNew ) \ + return false; \ + \ + m_nSize = nSize; \ + /* copy data to new location */ \ + memcpy(pNew, m_pItems, m_nCount*sizeof(T)); \ + delete [] m_pItems; \ + m_pItems = pNew; \ + \ + return true; \ +} \ + \ +/* grow the array */ \ +void name::Grow(size_t nIncrement) \ +{ \ + /* only do it if no more place */ \ + if( (m_nCount == m_nSize) || ((m_nSize - m_nCount) < nIncrement) ) { \ + if( m_nSize == 0 ) { \ + /* was empty, determine initial size */ \ + size_t size = WX_ARRAY_DEFAULT_INITIAL_SIZE; \ + if (size < nIncrement) size = nIncrement; \ + /* allocate some memory */ \ + m_pItems = new T[size]; \ + /* only grow if allocation succeeded */ \ + if ( m_pItems ) { \ + m_nSize = size; \ + } \ + } \ + else \ + { \ + /* add at least 50% but not too much */ \ + size_t ndefIncrement = m_nSize < WX_ARRAY_DEFAULT_INITIAL_SIZE \ + ? WX_ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1; \ + if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT ) \ + ndefIncrement = ARRAY_MAXSIZE_INCREMENT; \ + if ( nIncrement < ndefIncrement ) \ + nIncrement = ndefIncrement; \ + Realloc(m_nSize + nIncrement); \ + } \ + } \ +} \ + \ +/* make sure that the array has at least count elements */ \ +void name::SetCount(size_t count, T defval) \ +{ \ + if ( m_nSize < count ) \ + { \ + /* need to realloc memory: don't overallocate it here as if */ \ + /* SetCount() is called, it probably means that the caller */ \ + /* knows in advance how many elements there will be in the */ \ + /* array and so it won't be necessary to realloc it later */ \ + if ( !Realloc(count) ) \ + { \ + /* out of memory -- what can we do? */ \ + return; \ + } \ + } \ + \ + /* add new elements if we extend the array */ \ + while ( m_nCount < count ) \ + { \ + m_pItems[m_nCount++] = defval; \ + } \ +} \ + \ +/* dtor */ \ +name::~name() \ +{ \ + wxDELETEA(m_pItems); \ +} \ + \ +/* clears the list */ \ +void name::Clear() \ +{ \ + m_nSize = \ + m_nCount = 0; \ + \ + wxDELETEA(m_pItems); \ +} \ + \ +/* minimizes the memory usage by freeing unused memory */ \ +void name::Shrink() \ +{ \ + /* only do it if we have some memory to free */ \ + if( m_nCount < m_nSize ) { \ + /* allocates exactly as much memory as we need */ \ + T *pNew = new T[m_nCount]; \ + /* only shrink if allocation succeeded */ \ + if ( pNew ) { \ + /* copy data to new location */ \ + memcpy(pNew, m_pItems, m_nCount*sizeof(T)); \ + delete [] m_pItems; \ + m_pItems = pNew; \ + \ + /* update the size of the new block */ \ + m_nSize = m_nCount; \ + } \ + /* else: don't do anything, better keep old memory block! */ \ + } \ +} \ + \ +/* add item at the end */ \ +void name::Add(T lItem, size_t nInsert) \ +{ \ + if (nInsert == 0) \ + return; \ + Grow(nInsert); \ + for (size_t i = 0; i < nInsert; i++) \ + m_pItems[m_nCount++] = lItem; \ +} \ + \ +/* add item at the given position */ \ +void name::Insert(T lItem, size_t nIndex, size_t nInsert) \ +{ \ + wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArray::Insert") ); \ + wxCHECK_RET( m_nCount <= m_nCount + nInsert, \ + wxT("array size overflow in wxArray::Insert") ); \ + \ + if (nInsert == 0) \ + return; \ + Grow(nInsert); \ + \ + memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], \ + (m_nCount - nIndex)*sizeof(T)); \ + for (size_t i = 0; i < nInsert; i++) \ + m_pItems[nIndex + i] = lItem; \ + m_nCount += nInsert; \ +} \ + \ +/* search for a place to insert item into sorted array (binary search) */ \ +size_t name::IndexForInsert(T lItem, CMPFUNC fnCompare) const \ +{ \ + size_t i, \ + lo = 0, \ + hi = m_nCount; \ + int res; \ + \ + while ( lo < hi ) { \ + i = (lo + hi)/2; \ + \ + res = (*fnCompare)((const void *)(wxUIntPtr)lItem, \ + (const void *)(wxUIntPtr)(m_pItems[i])); \ + if ( res < 0 ) \ + hi = i; \ + else if ( res > 0 ) \ + lo = i + 1; \ + else { \ + lo = i; \ + break; \ + } \ + } \ + \ + return lo; \ +} \ + \ +/* search for an item in a sorted array (binary search) */ \ +int name::Index(T lItem, CMPFUNC fnCompare) const \ +{ \ + size_t n = IndexForInsert(lItem, fnCompare); \ + \ + return (n >= m_nCount || \ + (*fnCompare)((const void *)(wxUIntPtr)lItem, \ + ((const void *)(wxUIntPtr)m_pItems[n]))) \ + ? wxNOT_FOUND \ + : (int)n; \ +} \ + \ +/* removes item from array (by index) */ \ +void name::RemoveAt(size_t nIndex, size_t nRemove) \ +{ \ + wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArray::RemoveAt") ); \ + wxCHECK_RET( nIndex + nRemove <= m_nCount, \ + wxT("removing too many elements in wxArray::RemoveAt") ); \ + \ + memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove], \ + (m_nCount - nIndex - nRemove)*sizeof(T)); \ + m_nCount -= nRemove; \ +} \ + \ +/* removes item from array (by value) */ \ +void name::Remove(T lItem) \ +{ \ + int iIndex = Index(lItem); \ + \ + wxCHECK_RET( iIndex != wxNOT_FOUND, \ + wxT("removing inexistent item in wxArray::Remove") ); \ + \ + RemoveAt((size_t)iIndex); \ +} \ + \ +/* sort array elements using passed comparaison function */ \ +void name::Sort(CMPFUNC fCmp) \ +{ \ + qsort(m_pItems, m_nCount, sizeof(T), fCmp); \ +} \ + \ +void name::assign(const_iterator first, const_iterator last) \ +{ \ + clear(); \ + reserve(last - first); \ + for(; first != last; ++first) \ + push_back(*first); \ +} \ + \ +void name::assign(size_type n, const_reference v) \ +{ \ + clear(); \ + reserve(n); \ + for( size_type i = 0; i < n; ++i ) \ + push_back(v); \ +} \ + \ +void name::insert(iterator it, const_iterator first, const_iterator last) \ +{ \ + size_t nInsert = last - first, nIndex = it - begin(); \ + if (nInsert == 0) \ + return; \ + Grow(nInsert); \ + \ + memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], \ + (m_nCount - nIndex)*sizeof(T)); \ + for (size_t i = 0; i < nInsert; ++i, ++it, ++first) \ + *it = *first; \ + m_nCount += nInsert; \ +} + +#endif + +#define _WX_DEFINE_BASEARRAY(T, name) \ + _WX_DEFINE_BASEARRAY_COMMON(T, name) \ + _WX_DEFINE_BASEARRAY_NOCOMMON(T, name) + +#ifdef __INTELC__ + #pragma warning(push) + #pragma warning(disable: 1684) + #pragma warning(disable: 1572) +#endif + +_WX_DEFINE_BASEARRAY(const void *, wxBaseArrayPtrVoid) +_WX_DEFINE_BASEARRAY(char, wxBaseArrayChar) +_WX_DEFINE_BASEARRAY(short, wxBaseArrayShort) +_WX_DEFINE_BASEARRAY(int, wxBaseArrayInt) +_WX_DEFINE_BASEARRAY(long, wxBaseArrayLong) +_WX_DEFINE_BASEARRAY(size_t, wxBaseArraySizeT) +_WX_DEFINE_BASEARRAY(double, wxBaseArrayDouble) + +#ifdef __INTELC__ + #pragma warning(pop) +#endif + +#if wxUSE_STL +#include "wx/arrstr.h" + +#include "wx/beforestd.h" +#include +#include "wx/afterstd.h" + +_WX_DEFINE_BASEARRAY(wxString, wxBaseArrayStringBase) + +// some compilers (Sun CC being the only known example) distinguish between +// extern "C" functions and the functions with C++ linkage and ptr_fun and +// wxStringCompareLess can't take wxStrcmp/wxStricmp directly as arguments in +// this case, we need the wrappers below to make this work +inline int wxStrcmpCppWrapper(const wxChar *p, const wxChar *q) +{ + return wxStrcmp(p, q); +} + +inline int wxStricmpCppWrapper(const wxChar *p, const wxChar *q) +{ + return wxStricmp(p, q); +} + +int wxArrayString::Index(const wxChar* sz, bool bCase, bool WXUNUSED(bFromEnd)) const +{ + wxArrayString::const_iterator it; + + if (bCase) + { + it = std::find_if(begin(), end(), + std::not1( + std::bind2nd( + std::ptr_fun(wxStrcmpCppWrapper), sz))); + } + else // !bCase + { + it = std::find_if(begin(), end(), + std::not1( + std::bind2nd( + std::ptr_fun(wxStricmpCppWrapper), sz))); + } + + return it == end() ? wxNOT_FOUND : it - begin(); +} + +template +class wxStringCompareLess +{ +public: + wxStringCompareLess(F f) : m_f(f) { } + bool operator()(const wxChar* s1, const wxChar* s2) + { return m_f(s1, s2) < 0; } + bool operator()(const wxString& s1, const wxString& s2) + { return m_f(s1, s2) < 0; } +private: + F m_f; +}; + +template +wxStringCompareLess wxStringCompare(F f) +{ + return wxStringCompareLess(f); +} + +void wxArrayString::Sort(CompareFunction function) +{ + std::sort(begin(), end(), wxStringCompare(function)); +} + +void wxArrayString::Sort(bool reverseOrder) +{ + if (reverseOrder) + { + std::sort(begin(), end(), std::greater()); + } + else + { + std::sort(begin(), end()); + } +} + +int wxSortedArrayString::Index(const wxChar* sz, bool bCase, bool WXUNUSED(bFromEnd)) const +{ + wxSortedArrayString::const_iterator it; + wxString s(sz); + + if (bCase) + it = std::lower_bound(begin(), end(), s, + wxStringCompare(wxStrcmpCppWrapper)); + else + it = std::lower_bound(begin(), end(), s, + wxStringCompare(wxStricmpCppWrapper)); + + if (it == end()) + return wxNOT_FOUND; + + if (bCase) + { + if (wxStrcmp(it->c_str(), sz) != 0) + return wxNOT_FOUND; + } + else + { + if (wxStricmp(it->c_str(), sz) != 0) + return wxNOT_FOUND; + } + + return it - begin(); +} + +#endif diff --git a/Source/3rd Party/wx/src/common/dynlib.cpp b/Source/3rd Party/wx/src/common/dynlib.cpp index f4e75259c..a2db5e3ba 100644 --- a/Source/3rd Party/wx/src/common/dynlib.cpp +++ b/Source/3rd Party/wx/src/common/dynlib.cpp @@ -1,323 +1,323 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/dynlib.cpp -// Purpose: Dynamic library management -// Author: Guilhem Lavaux -// Modified by: -// Created: 20/07/98 -// RCS-ID: $Id: dynlib.cpp 41807 2006-10-09 15:58:56Z VZ $ -// Copyright: (c) 1998 Guilhem Lavaux -// 2000-2005 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -//FIXME: This class isn't really common at all, it should be moved into -// platform dependent files (already done for Windows and Unix) - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DYNLIB_CLASS - -#include "wx/dynlib.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/app.h" - #include "wx/utils.h" -#endif //WX_PRECOMP - -#include "wx/filefn.h" -#include "wx/filename.h" // for SplitPath() -#include "wx/platinfo.h" - -#include "wx/arrimpl.cpp" - -#if defined(__WXMAC__) - #include "wx/mac/private.h" -#endif - -WX_DEFINE_USER_EXPORTED_OBJARRAY(wxDynamicLibraryDetailsArray) - -// ============================================================================ -// implementation -// ============================================================================ - -// --------------------------------------------------------------------------- -// wxDynamicLibrary -// --------------------------------------------------------------------------- - -#if defined(__WXPM__) || defined(__EMX__) - const wxChar *wxDynamicLibrary::ms_dllext = _T(".dll"); -#elif defined(__WXMAC__) && !defined(__DARWIN__) - const wxChar *wxDynamicLibrary::ms_dllext = wxEmptyString; -#endif - -// for MSW/Unix it is defined in platform-specific file -#if !(defined(__WXMSW__) || defined(__UNIX__)) || defined(__EMX__) - -wxDllType wxDynamicLibrary::GetProgramHandle() -{ - wxFAIL_MSG( wxT("GetProgramHandle() is not implemented under this platform")); - return 0; -} - -#endif // __WXMSW__ || __UNIX__ - - -bool wxDynamicLibrary::Load(const wxString& libnameOrig, int flags) -{ - wxASSERT_MSG(m_handle == 0, _T("Library already loaded.")); - - // add the proper extension for the DLL ourselves unless told not to - wxString libname = libnameOrig; - if ( !(flags & wxDL_VERBATIM) ) - { - // and also check that the libname doesn't already have it - wxString ext; - wxFileName::SplitPath(libname, NULL, NULL, &ext); - if ( ext.empty() ) - { - libname += GetDllExt(); - } - } - - // different ways to load a shared library - // - // FIXME: should go to the platform-specific files! -#if defined(__WXMAC__) && !defined(__DARWIN__) - FSSpec myFSSpec; - Ptr myMainAddr; - Str255 myErrName; - - wxMacFilename2FSSpec( libname , &myFSSpec ); - - if( GetDiskFragment( &myFSSpec, - 0, - kCFragGoesToEOF, - "\p", - kPrivateCFragCopy, - &m_handle, - &myMainAddr, - myErrName ) != noErr ) - { - wxLogSysError( _("Failed to load shared library '%s' Error '%s'"), - libname.c_str(), - wxMacMakeStringFromPascal( myErrName ).c_str() ); - m_handle = 0; - } - -#elif defined(__WXPM__) || defined(__EMX__) - char err[256] = ""; - DosLoadModule(err, sizeof(err), (PSZ)libname.c_str(), &m_handle); -#else // this should be the only remaining branch eventually - m_handle = RawLoad(libname, flags); -#endif - - if ( m_handle == 0 ) - { -#ifdef wxHAVE_DYNLIB_ERROR - Error(); -#else - wxLogSysError(_("Failed to load shared library '%s'"), libname.c_str()); -#endif - } - - return IsLoaded(); -} - -// for MSW and Unix this is implemented in the platform-specific file -// -// TODO: move the rest to os2/dlpm.cpp and mac/dlmac.cpp! -#if (!defined(__WXMSW__) && !defined(__UNIX__)) || defined(__EMX__) - -/* static */ -void wxDynamicLibrary::Unload(wxDllType handle) -{ -#if defined(__OS2__) || defined(__EMX__) - DosFreeModule( handle ); -#elif defined(__WXMAC__) && !defined(__DARWIN__) - CloseConnection( (CFragConnectionID*) &handle ); -#else - #error "runtime shared lib support not implemented" -#endif -} - -#endif // !(__WXMSW__ || __UNIX__) - -void *wxDynamicLibrary::DoGetSymbol(const wxString &name, bool *success) const -{ - wxCHECK_MSG( IsLoaded(), NULL, - _T("Can't load symbol from unloaded library") ); - - void *symbol = 0; - - wxUnusedVar(symbol); -#if defined(__WXMAC__) && !defined(__DARWIN__) - Ptr symAddress; - CFragSymbolClass symClass; - Str255 symName; -#if TARGET_CARBON - c2pstrcpy( (StringPtr) symName, name.fn_str() ); -#else - strcpy( (char *)symName, name.fn_str() ); - c2pstr( (char *)symName ); -#endif - if( FindSymbol( m_handle, symName, &symAddress, &symClass ) == noErr ) - symbol = (void *)symAddress; -#elif defined(__WXPM__) || defined(__EMX__) - DosQueryProcAddr( m_handle, 1L, (PSZ)name.c_str(), (PFN*)symbol ); -#else - symbol = RawGetSymbol(m_handle, name); -#endif - - if ( success ) - *success = symbol != NULL; - - return symbol; -} - -void *wxDynamicLibrary::GetSymbol(const wxString& name, bool *success) const -{ - void *symbol = DoGetSymbol(name, success); - if ( !symbol ) - { -#ifdef wxHAVE_DYNLIB_ERROR - Error(); -#else - wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"), - name.c_str()); -#endif - } - - return symbol; -} - -// ---------------------------------------------------------------------------- -// informational methods -// ---------------------------------------------------------------------------- - -/*static*/ -wxString -wxDynamicLibrary::CanonicalizeName(const wxString& name, - wxDynamicLibraryCategory cat) -{ - wxString nameCanonic; - - // under Unix the library names usually start with "lib" prefix, add it -#if defined(__UNIX__) && !defined(__EMX__) - switch ( cat ) - { - default: - wxFAIL_MSG( _T("unknown wxDynamicLibraryCategory value") ); - // fall through - - case wxDL_MODULE: - // don't do anything for modules, their names are arbitrary - break; - - case wxDL_LIBRARY: - // library names should start with "lib" under Unix - nameCanonic = _T("lib"); - break; - } -#else // !__UNIX__ - wxUnusedVar(cat); -#endif // __UNIX__/!__UNIX__ - - nameCanonic << name << GetDllExt(); - return nameCanonic; -} - -/*static*/ -wxString wxDynamicLibrary::CanonicalizePluginName(const wxString& name, - wxPluginCategory cat) -{ - wxString suffix; - if ( cat == wxDL_PLUGIN_GUI ) - { - suffix = wxPlatformInfo::Get().GetPortIdShortName(); - } -#if wxUSE_UNICODE - suffix << _T('u'); -#endif -#ifdef __WXDEBUG__ - suffix << _T('d'); -#endif - - if ( !suffix.empty() ) - suffix = wxString(_T("_")) + suffix; - -#define WXSTRINGIZE(x) #x -#if defined(__UNIX__) && !defined(__EMX__) - #if (wxMINOR_VERSION % 2) == 0 - #define wxDLLVER(x,y,z) "-" WXSTRINGIZE(x) "." WXSTRINGIZE(y) - #else - #define wxDLLVER(x,y,z) "-" WXSTRINGIZE(x) "." WXSTRINGIZE(y) "." WXSTRINGIZE(z) - #endif -#else - #if (wxMINOR_VERSION % 2) == 0 - #define wxDLLVER(x,y,z) WXSTRINGIZE(x) WXSTRINGIZE(y) - #else - #define wxDLLVER(x,y,z) WXSTRINGIZE(x) WXSTRINGIZE(y) WXSTRINGIZE(z) - #endif -#endif - - suffix << wxString::FromAscii(wxDLLVER(wxMAJOR_VERSION, wxMINOR_VERSION, - wxRELEASE_NUMBER)); -#undef wxDLLVER -#undef WXSTRINGIZE - -#ifdef __WINDOWS__ - // Add compiler identification: - #if defined(__GNUG__) - suffix << _T("_gcc"); - #elif defined(__VISUALC__) - suffix << _T("_vc"); - #elif defined(__WATCOMC__) - suffix << _T("_wat"); - #elif defined(__BORLANDC__) - suffix << _T("_bcc"); - #endif -#endif - - return CanonicalizeName(name + suffix, wxDL_MODULE); -} - -/*static*/ -wxString wxDynamicLibrary::GetPluginsDirectory() -{ -#ifdef __UNIX__ - wxString format = wxGetInstallPrefix(); - wxString dir; - format << wxFILE_SEP_PATH - << wxT("lib") << wxFILE_SEP_PATH - << wxT("wx") << wxFILE_SEP_PATH -#if (wxMINOR_VERSION % 2) == 0 - << wxT("%i.%i"); - dir.Printf(format.c_str(), wxMAJOR_VERSION, wxMINOR_VERSION); -#else - << wxT("%i.%i.%i"); - dir.Printf(format.c_str(), - wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER); -#endif - return dir; - -#else // ! __UNIX__ - return wxEmptyString; -#endif -} - - -#endif // wxUSE_DYNLIB_CLASS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/dynlib.cpp +// Purpose: Dynamic library management +// Author: Guilhem Lavaux +// Modified by: +// Created: 20/07/98 +// RCS-ID: $Id: dynlib.cpp 41807 2006-10-09 15:58:56Z VZ $ +// Copyright: (c) 1998 Guilhem Lavaux +// 2000-2005 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +//FIXME: This class isn't really common at all, it should be moved into +// platform dependent files (already done for Windows and Unix) + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DYNLIB_CLASS + +#include "wx/dynlib.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/app.h" + #include "wx/utils.h" +#endif //WX_PRECOMP + +#include "wx/filefn.h" +#include "wx/filename.h" // for SplitPath() +#include "wx/platinfo.h" + +#include "wx/arrimpl.cpp" + +#if defined(__WXMAC__) + #include "wx/mac/private.h" +#endif + +WX_DEFINE_USER_EXPORTED_OBJARRAY(wxDynamicLibraryDetailsArray) + +// ============================================================================ +// implementation +// ============================================================================ + +// --------------------------------------------------------------------------- +// wxDynamicLibrary +// --------------------------------------------------------------------------- + +#if defined(__WXPM__) || defined(__EMX__) + const wxChar *wxDynamicLibrary::ms_dllext = _T(".dll"); +#elif defined(__WXMAC__) && !defined(__DARWIN__) + const wxChar *wxDynamicLibrary::ms_dllext = wxEmptyString; +#endif + +// for MSW/Unix it is defined in platform-specific file +#if !(defined(__WXMSW__) || defined(__UNIX__)) || defined(__EMX__) + +wxDllType wxDynamicLibrary::GetProgramHandle() +{ + wxFAIL_MSG( wxT("GetProgramHandle() is not implemented under this platform")); + return 0; +} + +#endif // __WXMSW__ || __UNIX__ + + +bool wxDynamicLibrary::Load(const wxString& libnameOrig, int flags) +{ + wxASSERT_MSG(m_handle == 0, _T("Library already loaded.")); + + // add the proper extension for the DLL ourselves unless told not to + wxString libname = libnameOrig; + if ( !(flags & wxDL_VERBATIM) ) + { + // and also check that the libname doesn't already have it + wxString ext; + wxFileName::SplitPath(libname, NULL, NULL, &ext); + if ( ext.empty() ) + { + libname += GetDllExt(); + } + } + + // different ways to load a shared library + // + // FIXME: should go to the platform-specific files! +#if defined(__WXMAC__) && !defined(__DARWIN__) + FSSpec myFSSpec; + Ptr myMainAddr; + Str255 myErrName; + + wxMacFilename2FSSpec( libname , &myFSSpec ); + + if( GetDiskFragment( &myFSSpec, + 0, + kCFragGoesToEOF, + "\p", + kPrivateCFragCopy, + &m_handle, + &myMainAddr, + myErrName ) != noErr ) + { + wxLogSysError( _("Failed to load shared library '%s' Error '%s'"), + libname.c_str(), + wxMacMakeStringFromPascal( myErrName ).c_str() ); + m_handle = 0; + } + +#elif defined(__WXPM__) || defined(__EMX__) + char err[256] = ""; + DosLoadModule(err, sizeof(err), (PSZ)libname.c_str(), &m_handle); +#else // this should be the only remaining branch eventually + m_handle = RawLoad(libname, flags); +#endif + + if ( m_handle == 0 ) + { +#ifdef wxHAVE_DYNLIB_ERROR + Error(); +#else + wxLogSysError(_("Failed to load shared library '%s'"), libname.c_str()); +#endif + } + + return IsLoaded(); +} + +// for MSW and Unix this is implemented in the platform-specific file +// +// TODO: move the rest to os2/dlpm.cpp and mac/dlmac.cpp! +#if (!defined(__WXMSW__) && !defined(__UNIX__)) || defined(__EMX__) + +/* static */ +void wxDynamicLibrary::Unload(wxDllType handle) +{ +#if defined(__OS2__) || defined(__EMX__) + DosFreeModule( handle ); +#elif defined(__WXMAC__) && !defined(__DARWIN__) + CloseConnection( (CFragConnectionID*) &handle ); +#else + #error "runtime shared lib support not implemented" +#endif +} + +#endif // !(__WXMSW__ || __UNIX__) + +void *wxDynamicLibrary::DoGetSymbol(const wxString &name, bool *success) const +{ + wxCHECK_MSG( IsLoaded(), NULL, + _T("Can't load symbol from unloaded library") ); + + void *symbol = 0; + + wxUnusedVar(symbol); +#if defined(__WXMAC__) && !defined(__DARWIN__) + Ptr symAddress; + CFragSymbolClass symClass; + Str255 symName; +#if TARGET_CARBON + c2pstrcpy( (StringPtr) symName, name.fn_str() ); +#else + strcpy( (char *)symName, name.fn_str() ); + c2pstr( (char *)symName ); +#endif + if( FindSymbol( m_handle, symName, &symAddress, &symClass ) == noErr ) + symbol = (void *)symAddress; +#elif defined(__WXPM__) || defined(__EMX__) + DosQueryProcAddr( m_handle, 1L, (PSZ)name.c_str(), (PFN*)symbol ); +#else + symbol = RawGetSymbol(m_handle, name); +#endif + + if ( success ) + *success = symbol != NULL; + + return symbol; +} + +void *wxDynamicLibrary::GetSymbol(const wxString& name, bool *success) const +{ + void *symbol = DoGetSymbol(name, success); + if ( !symbol ) + { +#ifdef wxHAVE_DYNLIB_ERROR + Error(); +#else + wxLogSysError(_("Couldn't find symbol '%s' in a dynamic library"), + name.c_str()); +#endif + } + + return symbol; +} + +// ---------------------------------------------------------------------------- +// informational methods +// ---------------------------------------------------------------------------- + +/*static*/ +wxString +wxDynamicLibrary::CanonicalizeName(const wxString& name, + wxDynamicLibraryCategory cat) +{ + wxString nameCanonic; + + // under Unix the library names usually start with "lib" prefix, add it +#if defined(__UNIX__) && !defined(__EMX__) + switch ( cat ) + { + default: + wxFAIL_MSG( _T("unknown wxDynamicLibraryCategory value") ); + // fall through + + case wxDL_MODULE: + // don't do anything for modules, their names are arbitrary + break; + + case wxDL_LIBRARY: + // library names should start with "lib" under Unix + nameCanonic = _T("lib"); + break; + } +#else // !__UNIX__ + wxUnusedVar(cat); +#endif // __UNIX__/!__UNIX__ + + nameCanonic << name << GetDllExt(); + return nameCanonic; +} + +/*static*/ +wxString wxDynamicLibrary::CanonicalizePluginName(const wxString& name, + wxPluginCategory cat) +{ + wxString suffix; + if ( cat == wxDL_PLUGIN_GUI ) + { + suffix = wxPlatformInfo::Get().GetPortIdShortName(); + } +#if wxUSE_UNICODE + suffix << _T('u'); +#endif +#ifdef __WXDEBUG__ + suffix << _T('d'); +#endif + + if ( !suffix.empty() ) + suffix = wxString(_T("_")) + suffix; + +#define WXSTRINGIZE(x) #x +#if defined(__UNIX__) && !defined(__EMX__) + #if (wxMINOR_VERSION % 2) == 0 + #define wxDLLVER(x,y,z) "-" WXSTRINGIZE(x) "." WXSTRINGIZE(y) + #else + #define wxDLLVER(x,y,z) "-" WXSTRINGIZE(x) "." WXSTRINGIZE(y) "." WXSTRINGIZE(z) + #endif +#else + #if (wxMINOR_VERSION % 2) == 0 + #define wxDLLVER(x,y,z) WXSTRINGIZE(x) WXSTRINGIZE(y) + #else + #define wxDLLVER(x,y,z) WXSTRINGIZE(x) WXSTRINGIZE(y) WXSTRINGIZE(z) + #endif +#endif + + suffix << wxString::FromAscii(wxDLLVER(wxMAJOR_VERSION, wxMINOR_VERSION, + wxRELEASE_NUMBER)); +#undef wxDLLVER +#undef WXSTRINGIZE + +#ifdef __WINDOWS__ + // Add compiler identification: + #if defined(__GNUG__) + suffix << _T("_gcc"); + #elif defined(__VISUALC__) + suffix << _T("_vc"); + #elif defined(__WATCOMC__) + suffix << _T("_wat"); + #elif defined(__BORLANDC__) + suffix << _T("_bcc"); + #endif +#endif + + return CanonicalizeName(name + suffix, wxDL_MODULE); +} + +/*static*/ +wxString wxDynamicLibrary::GetPluginsDirectory() +{ +#ifdef __UNIX__ + wxString format = wxGetInstallPrefix(); + wxString dir; + format << wxFILE_SEP_PATH + << wxT("lib") << wxFILE_SEP_PATH + << wxT("wx") << wxFILE_SEP_PATH +#if (wxMINOR_VERSION % 2) == 0 + << wxT("%i.%i"); + dir.Printf(format.c_str(), wxMAJOR_VERSION, wxMINOR_VERSION); +#else + << wxT("%i.%i.%i"); + dir.Printf(format.c_str(), + wxMAJOR_VERSION, wxMINOR_VERSION, wxRELEASE_NUMBER); +#endif + return dir; + +#else // ! __UNIX__ + return wxEmptyString; +#endif +} + + +#endif // wxUSE_DYNLIB_CLASS diff --git a/Source/3rd Party/wx/src/common/dynload.cpp b/Source/3rd Party/wx/src/common/dynload.cpp index 1a0aac9b3..a28b9e528 100644 --- a/Source/3rd Party/wx/src/common/dynload.cpp +++ b/Source/3rd Party/wx/src/common/dynload.cpp @@ -1,362 +1,362 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/dynload.cpp -// Purpose: Dynamic loading framework -// Author: Ron Lee, David Falkinder, Vadim Zeitlin and a cast of 1000's -// (derived in part from dynlib.cpp (c) 1998 Guilhem Lavaux) -// Modified by: -// Created: 03/12/01 -// RCS-ID: $Id: dynload.cpp 40943 2006-08-31 19:31:43Z ABX $ -// Copyright: (c) 2001 Ron Lee -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_DYNAMIC_LOADER - -#ifdef __WINDOWS__ - #include "wx/msw/private.h" -#endif - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/hash.h" - #include "wx/utils.h" - #include "wx/module.h" -#endif - -#include "wx/strconv.h" - -#include "wx/dynload.h" - - -// --------------------------------------------------------------------------- -// wxPluginLibrary -// --------------------------------------------------------------------------- - - -wxDLImports* wxPluginLibrary::ms_classes = NULL; - -class wxPluginLibraryModule : public wxModule -{ -public: - wxPluginLibraryModule() { } - - // TODO: create ms_classes on demand, why always preallocate it? - virtual bool OnInit() - { - wxPluginLibrary::ms_classes = new wxDLImports; - wxPluginManager::CreateManifest(); - return true; - } - - virtual void OnExit() - { - delete wxPluginLibrary::ms_classes; - wxPluginLibrary::ms_classes = NULL; - wxPluginManager::ClearManifest(); - } - -private: - DECLARE_DYNAMIC_CLASS(wxPluginLibraryModule ) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxPluginLibraryModule, wxModule) - - -wxPluginLibrary::wxPluginLibrary(const wxString &libname, int flags) - : m_linkcount(1) - , m_objcount(0) -{ - m_before = wxClassInfo::sm_first; - Load( libname, flags ); - m_after = wxClassInfo::sm_first; - - if( m_handle != 0 ) - { - UpdateClasses(); - RegisterModules(); - } - else - { - // Flag us for deletion - --m_linkcount; - } -} - -wxPluginLibrary::~wxPluginLibrary() -{ - if( m_handle != 0 ) - { - UnregisterModules(); - RestoreClasses(); - } -} - -wxPluginLibrary *wxPluginLibrary::RefLib() -{ - wxCHECK_MSG( m_linkcount > 0, NULL, - _T("Library had been already deleted!") ); - - ++m_linkcount; - return this; -} - -bool wxPluginLibrary::UnrefLib() -{ - wxASSERT_MSG( m_objcount == 0, - _T("Library unloaded before all objects were destroyed") ); - - if ( m_linkcount == 0 || --m_linkcount == 0 ) - { - delete this; - return true; - } - - return false; -} - -// ------------------------ -// Private methods -// ------------------------ - -void wxPluginLibrary::UpdateClasses() -{ - for (wxClassInfo *info = m_after; info != m_before; info = info->m_next) - { - if( info->GetClassName() ) - { - // Hash all the class names into a local table too so - // we can quickly find the entry they correspond to. - (*ms_classes)[info->GetClassName()] = this; - } - } -} - -void wxPluginLibrary::RestoreClasses() -{ - // Check if there is a need to restore classes. - if (!ms_classes) - return; - - for(wxClassInfo *info = m_after; info != m_before; info = info->m_next) - { - ms_classes->erase(ms_classes->find(info->GetClassName())); - } -} - -void wxPluginLibrary::RegisterModules() -{ - // Plugin libraries might have wxModules, Register and initialise them if - // they do. - // - // Note that these classes are NOT included in the reference counting since - // it's implicit that they will be unloaded if and when the last handle to - // the library is. We do have to keep a copy of the module's pointer - // though, as there is currently no way to Unregister it without it. - - wxASSERT_MSG( m_linkcount == 1, - _T("RegisterModules should only be called for the first load") ); - - for ( wxClassInfo *info = m_after; info != m_before; info = info->m_next) - { - if( info->IsKindOf(CLASSINFO(wxModule)) ) - { - wxModule *m = wxDynamicCast(info->CreateObject(), wxModule); - - wxASSERT_MSG( m, _T("wxDynamicCast of wxModule failed") ); - - m_wxmodules.push_back(m); - wxModule::RegisterModule(m); - } - } - - // FIXME: Likewise this is (well was) very similar to InitializeModules() - - for ( wxModuleList::iterator it = m_wxmodules.begin(); - it != m_wxmodules.end(); - ++it) - { - if( !(*it)->Init() ) - { - wxLogDebug(_T("wxModule::Init() failed for wxPluginLibrary")); - - // XXX: Watch this, a different hash implementation might break it, - // a good hash implementation would let us fix it though. - - // The name of the game is to remove any uninitialised modules and - // let the dtor Exit the rest on shutdown, (which we'll initiate - // shortly). - - wxModuleList::iterator oldNode = m_wxmodules.end(); - do { - ++it; - if( oldNode != m_wxmodules.end() ) - m_wxmodules.erase(oldNode); - wxModule::UnregisterModule( *it ); - oldNode = it; - } while( it != m_wxmodules.end() ); - - --m_linkcount; // Flag us for deletion - break; - } - } -} - -void wxPluginLibrary::UnregisterModules() -{ - wxModuleList::iterator it; - - for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it ) - (*it)->Exit(); - - for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it ) - wxModule::UnregisterModule( *it ); - - // NB: content of the list was deleted by UnregisterModule calls above: - m_wxmodules.clear(); -} - - -// --------------------------------------------------------------------------- -// wxPluginManager -// --------------------------------------------------------------------------- - -wxDLManifest* wxPluginManager::ms_manifest = NULL; - -// ------------------------ -// Static accessors -// ------------------------ - -wxPluginLibrary * -wxPluginManager::LoadLibrary(const wxString &libname, int flags) -{ - wxString realname(libname); - - if( !(flags & wxDL_VERBATIM) ) - realname += wxDynamicLibrary::GetDllExt(); - - wxPluginLibrary *entry; - - if ( flags & wxDL_NOSHARE ) - { - entry = NULL; - } - else - { - entry = FindByName(realname); - } - - if ( entry ) - { - wxLogTrace(_T("dll"), - _T("LoadLibrary(%s): already loaded."), realname.c_str()); - - entry->RefLib(); - } - else - { - entry = new wxPluginLibrary( libname, flags ); - - if ( entry->IsLoaded() ) - { - (*ms_manifest)[realname] = entry; - - wxLogTrace(_T("dll"), - _T("LoadLibrary(%s): loaded ok."), realname.c_str()); - - } - else - { - wxLogTrace(_T("dll"), - _T("LoadLibrary(%s): failed to load."), realname.c_str()); - - // we have created entry just above - if ( !entry->UnrefLib() ) - { - // ... so UnrefLib() is supposed to delete it - wxFAIL_MSG( _T("Currently linked library is not loaded?") ); - } - - entry = NULL; - } - } - - return entry; -} - -bool wxPluginManager::UnloadLibrary(const wxString& libname) -{ - wxString realname = libname; - - wxPluginLibrary *entry = FindByName(realname); - - if ( !entry ) - { - realname += wxDynamicLibrary::GetDllExt(); - - entry = FindByName(realname); - } - - if ( !entry ) - { - wxLogDebug(_T("Attempt to unload library '%s' which is not loaded."), - libname.c_str()); - - return false; - } - - wxLogTrace(_T("dll"), _T("UnloadLibrary(%s)"), realname.c_str()); - - if ( !entry->UnrefLib() ) - { - // not really unloaded yet - return false; - } - - ms_manifest->erase(ms_manifest->find(realname)); - - return true; -} - -// ------------------------ -// Class implementation -// ------------------------ - -bool wxPluginManager::Load(const wxString &libname, int flags) -{ - m_entry = wxPluginManager::LoadLibrary(libname, flags); - - return IsLoaded(); -} - -void wxPluginManager::Unload() -{ - wxCHECK_RET( m_entry, _T("unloading an invalid wxPluginManager?") ); - - for ( wxDLManifest::iterator i = ms_manifest->begin(); - i != ms_manifest->end(); - ++i ) - { - if ( i->second == m_entry ) - { - ms_manifest->erase(i); - break; - } - } - - m_entry->UnrefLib(); - - m_entry = NULL; -} - -#endif // wxUSE_DYNAMIC_LOADER +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/dynload.cpp +// Purpose: Dynamic loading framework +// Author: Ron Lee, David Falkinder, Vadim Zeitlin and a cast of 1000's +// (derived in part from dynlib.cpp (c) 1998 Guilhem Lavaux) +// Modified by: +// Created: 03/12/01 +// RCS-ID: $Id: dynload.cpp 40943 2006-08-31 19:31:43Z ABX $ +// Copyright: (c) 2001 Ron Lee +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_DYNAMIC_LOADER + +#ifdef __WINDOWS__ + #include "wx/msw/private.h" +#endif + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/hash.h" + #include "wx/utils.h" + #include "wx/module.h" +#endif + +#include "wx/strconv.h" + +#include "wx/dynload.h" + + +// --------------------------------------------------------------------------- +// wxPluginLibrary +// --------------------------------------------------------------------------- + + +wxDLImports* wxPluginLibrary::ms_classes = NULL; + +class wxPluginLibraryModule : public wxModule +{ +public: + wxPluginLibraryModule() { } + + // TODO: create ms_classes on demand, why always preallocate it? + virtual bool OnInit() + { + wxPluginLibrary::ms_classes = new wxDLImports; + wxPluginManager::CreateManifest(); + return true; + } + + virtual void OnExit() + { + delete wxPluginLibrary::ms_classes; + wxPluginLibrary::ms_classes = NULL; + wxPluginManager::ClearManifest(); + } + +private: + DECLARE_DYNAMIC_CLASS(wxPluginLibraryModule ) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxPluginLibraryModule, wxModule) + + +wxPluginLibrary::wxPluginLibrary(const wxString &libname, int flags) + : m_linkcount(1) + , m_objcount(0) +{ + m_before = wxClassInfo::sm_first; + Load( libname, flags ); + m_after = wxClassInfo::sm_first; + + if( m_handle != 0 ) + { + UpdateClasses(); + RegisterModules(); + } + else + { + // Flag us for deletion + --m_linkcount; + } +} + +wxPluginLibrary::~wxPluginLibrary() +{ + if( m_handle != 0 ) + { + UnregisterModules(); + RestoreClasses(); + } +} + +wxPluginLibrary *wxPluginLibrary::RefLib() +{ + wxCHECK_MSG( m_linkcount > 0, NULL, + _T("Library had been already deleted!") ); + + ++m_linkcount; + return this; +} + +bool wxPluginLibrary::UnrefLib() +{ + wxASSERT_MSG( m_objcount == 0, + _T("Library unloaded before all objects were destroyed") ); + + if ( m_linkcount == 0 || --m_linkcount == 0 ) + { + delete this; + return true; + } + + return false; +} + +// ------------------------ +// Private methods +// ------------------------ + +void wxPluginLibrary::UpdateClasses() +{ + for (wxClassInfo *info = m_after; info != m_before; info = info->m_next) + { + if( info->GetClassName() ) + { + // Hash all the class names into a local table too so + // we can quickly find the entry they correspond to. + (*ms_classes)[info->GetClassName()] = this; + } + } +} + +void wxPluginLibrary::RestoreClasses() +{ + // Check if there is a need to restore classes. + if (!ms_classes) + return; + + for(wxClassInfo *info = m_after; info != m_before; info = info->m_next) + { + ms_classes->erase(ms_classes->find(info->GetClassName())); + } +} + +void wxPluginLibrary::RegisterModules() +{ + // Plugin libraries might have wxModules, Register and initialise them if + // they do. + // + // Note that these classes are NOT included in the reference counting since + // it's implicit that they will be unloaded if and when the last handle to + // the library is. We do have to keep a copy of the module's pointer + // though, as there is currently no way to Unregister it without it. + + wxASSERT_MSG( m_linkcount == 1, + _T("RegisterModules should only be called for the first load") ); + + for ( wxClassInfo *info = m_after; info != m_before; info = info->m_next) + { + if( info->IsKindOf(CLASSINFO(wxModule)) ) + { + wxModule *m = wxDynamicCast(info->CreateObject(), wxModule); + + wxASSERT_MSG( m, _T("wxDynamicCast of wxModule failed") ); + + m_wxmodules.push_back(m); + wxModule::RegisterModule(m); + } + } + + // FIXME: Likewise this is (well was) very similar to InitializeModules() + + for ( wxModuleList::iterator it = m_wxmodules.begin(); + it != m_wxmodules.end(); + ++it) + { + if( !(*it)->Init() ) + { + wxLogDebug(_T("wxModule::Init() failed for wxPluginLibrary")); + + // XXX: Watch this, a different hash implementation might break it, + // a good hash implementation would let us fix it though. + + // The name of the game is to remove any uninitialised modules and + // let the dtor Exit the rest on shutdown, (which we'll initiate + // shortly). + + wxModuleList::iterator oldNode = m_wxmodules.end(); + do { + ++it; + if( oldNode != m_wxmodules.end() ) + m_wxmodules.erase(oldNode); + wxModule::UnregisterModule( *it ); + oldNode = it; + } while( it != m_wxmodules.end() ); + + --m_linkcount; // Flag us for deletion + break; + } + } +} + +void wxPluginLibrary::UnregisterModules() +{ + wxModuleList::iterator it; + + for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it ) + (*it)->Exit(); + + for ( it = m_wxmodules.begin(); it != m_wxmodules.end(); ++it ) + wxModule::UnregisterModule( *it ); + + // NB: content of the list was deleted by UnregisterModule calls above: + m_wxmodules.clear(); +} + + +// --------------------------------------------------------------------------- +// wxPluginManager +// --------------------------------------------------------------------------- + +wxDLManifest* wxPluginManager::ms_manifest = NULL; + +// ------------------------ +// Static accessors +// ------------------------ + +wxPluginLibrary * +wxPluginManager::LoadLibrary(const wxString &libname, int flags) +{ + wxString realname(libname); + + if( !(flags & wxDL_VERBATIM) ) + realname += wxDynamicLibrary::GetDllExt(); + + wxPluginLibrary *entry; + + if ( flags & wxDL_NOSHARE ) + { + entry = NULL; + } + else + { + entry = FindByName(realname); + } + + if ( entry ) + { + wxLogTrace(_T("dll"), + _T("LoadLibrary(%s): already loaded."), realname.c_str()); + + entry->RefLib(); + } + else + { + entry = new wxPluginLibrary( libname, flags ); + + if ( entry->IsLoaded() ) + { + (*ms_manifest)[realname] = entry; + + wxLogTrace(_T("dll"), + _T("LoadLibrary(%s): loaded ok."), realname.c_str()); + + } + else + { + wxLogTrace(_T("dll"), + _T("LoadLibrary(%s): failed to load."), realname.c_str()); + + // we have created entry just above + if ( !entry->UnrefLib() ) + { + // ... so UnrefLib() is supposed to delete it + wxFAIL_MSG( _T("Currently linked library is not loaded?") ); + } + + entry = NULL; + } + } + + return entry; +} + +bool wxPluginManager::UnloadLibrary(const wxString& libname) +{ + wxString realname = libname; + + wxPluginLibrary *entry = FindByName(realname); + + if ( !entry ) + { + realname += wxDynamicLibrary::GetDllExt(); + + entry = FindByName(realname); + } + + if ( !entry ) + { + wxLogDebug(_T("Attempt to unload library '%s' which is not loaded."), + libname.c_str()); + + return false; + } + + wxLogTrace(_T("dll"), _T("UnloadLibrary(%s)"), realname.c_str()); + + if ( !entry->UnrefLib() ) + { + // not really unloaded yet + return false; + } + + ms_manifest->erase(ms_manifest->find(realname)); + + return true; +} + +// ------------------------ +// Class implementation +// ------------------------ + +bool wxPluginManager::Load(const wxString &libname, int flags) +{ + m_entry = wxPluginManager::LoadLibrary(libname, flags); + + return IsLoaded(); +} + +void wxPluginManager::Unload() +{ + wxCHECK_RET( m_entry, _T("unloading an invalid wxPluginManager?") ); + + for ( wxDLManifest::iterator i = ms_manifest->begin(); + i != ms_manifest->end(); + ++i ) + { + if ( i->second == m_entry ) + { + ms_manifest->erase(i); + break; + } + } + + m_entry->UnrefLib(); + + m_entry = NULL; +} + +#endif // wxUSE_DYNAMIC_LOADER diff --git a/Source/3rd Party/wx/src/common/effects.cpp b/Source/3rd Party/wx/src/common/effects.cpp index 444595b5f..dc1ab01e5 100644 --- a/Source/3rd Party/wx/src/common/effects.cpp +++ b/Source/3rd Party/wx/src/common/effects.cpp @@ -1,124 +1,124 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/effects.cpp -// Purpose: wxEffects implementation -// Author: Julian Smart -// Modified by: -// Created: 25/4/2000 -// RCS-ID: $Id: effects.cpp 42755 2006-10-30 19:41:46Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/effects.h" - -#ifndef WX_PRECOMP - #include "wx/dcmemory.h" - #include "wx/pen.h" - #include "wx/settings.h" - #include "wx/gdicmn.h" -#endif //WX_PRECOMP - -/* - * wxEffects: various 3D effects - */ - -IMPLEMENT_CLASS(wxEffects, wxObject) - -// Assume system colours -wxEffects::wxEffects() -{ - m_highlightColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT) ; - m_lightShadow = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT) ; - m_faceColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE) ; - m_mediumShadow = wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW) ; - m_darkShadow = wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW) ; -} - -// Going from lightest to darkest -wxEffects::wxEffects(const wxColour& highlightColour, const wxColour& lightShadow, - const wxColour& faceColour, const wxColour& mediumShadow, const wxColour& darkShadow) -{ - m_highlightColour = highlightColour; - m_lightShadow = lightShadow; - m_faceColour = faceColour; - m_mediumShadow = mediumShadow; - m_darkShadow = darkShadow; -} - -// Draw a sunken edge -void wxEffects::DrawSunkenEdge(wxDC& dc, const wxRect& rect, int WXUNUSED(borderSize)) -{ - wxPen highlightPen(m_highlightColour, 1, wxSOLID); - wxPen lightShadowPen(m_lightShadow, 1, wxSOLID); - wxPen facePen(m_faceColour, 1, wxSOLID); - wxPen mediumShadowPen(m_mediumShadow, 1, wxSOLID); - wxPen darkShadowPen(m_darkShadow, 1, wxSOLID); - - //// LEFT AND TOP - // Draw a medium shadow pen on left and top, followed by dark shadow line to - // right and below of these lines - - dc.SetPen(mediumShadowPen); - dc.DrawLine(rect.x, rect.y, rect.x+rect.width-1, rect.y); // Top - dc.DrawLine(rect.x, rect.y, rect.x, rect.y+rect.height-1); // Left - - dc.SetPen(darkShadowPen); - dc.DrawLine(rect.x+1, rect.y+1, rect.x+rect.width-2, rect.y+1); // Top - dc.DrawLine(rect.x+1, rect.y+1, rect.x+1, rect.y+rect.height-1); // Left - - //// RIGHT AND BOTTOM - - dc.SetPen(highlightPen); - dc.DrawLine(rect.x+rect.width-1, rect.y, rect.x+rect.width-1, rect.y+rect.height-1); // Right - dc.DrawLine(rect.x, rect.y+rect.height-1, rect.x+rect.width, rect.y+rect.height-1); // Bottom - - dc.SetPen(lightShadowPen); - dc.DrawLine(rect.x+rect.width-2, rect.y+1, rect.x+rect.width-2, rect.y+rect.height-2); // Right - dc.DrawLine(rect.x+1, rect.y+rect.height-2, rect.x+rect.width-1, rect.y+rect.height-2); // Bottom - - dc.SetPen(wxNullPen); -} - -bool wxEffects::TileBitmap(const wxRect& rect, wxDC& dc, const wxBitmap& bitmap) -{ - int w = bitmap.GetWidth(); - int h = bitmap.GetHeight(); - - wxMemoryDC dcMem; - -#if wxUSE_PALETTE - static bool hiColour = (wxDisplayDepth() >= 16) ; - if (bitmap.GetPalette() && !hiColour) - { - dc.SetPalette(* bitmap.GetPalette()); - dcMem.SetPalette(* bitmap.GetPalette()); - } -#endif // wxUSE_PALETTE - - dcMem.SelectObjectAsSource(bitmap); - - int i, j; - for (i = rect.x; i < rect.x + rect.width; i += w) - { - for (j = rect.y; j < rect.y + rect.height; j+= h) - dc.Blit(i, j, bitmap.GetWidth(), bitmap.GetHeight(), & dcMem, 0, 0); - } - dcMem.SelectObject(wxNullBitmap); - -#if wxUSE_PALETTE - if (bitmap.GetPalette() && !hiColour) - { - dc.SetPalette(wxNullPalette); - dcMem.SetPalette(wxNullPalette); - } -#endif // wxUSE_PALETTE - - return true; -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/effects.cpp +// Purpose: wxEffects implementation +// Author: Julian Smart +// Modified by: +// Created: 25/4/2000 +// RCS-ID: $Id: effects.cpp 42755 2006-10-30 19:41:46Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/effects.h" + +#ifndef WX_PRECOMP + #include "wx/dcmemory.h" + #include "wx/pen.h" + #include "wx/settings.h" + #include "wx/gdicmn.h" +#endif //WX_PRECOMP + +/* + * wxEffects: various 3D effects + */ + +IMPLEMENT_CLASS(wxEffects, wxObject) + +// Assume system colours +wxEffects::wxEffects() +{ + m_highlightColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT) ; + m_lightShadow = wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT) ; + m_faceColour = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE) ; + m_mediumShadow = wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW) ; + m_darkShadow = wxSystemSettings::GetColour(wxSYS_COLOUR_3DDKSHADOW) ; +} + +// Going from lightest to darkest +wxEffects::wxEffects(const wxColour& highlightColour, const wxColour& lightShadow, + const wxColour& faceColour, const wxColour& mediumShadow, const wxColour& darkShadow) +{ + m_highlightColour = highlightColour; + m_lightShadow = lightShadow; + m_faceColour = faceColour; + m_mediumShadow = mediumShadow; + m_darkShadow = darkShadow; +} + +// Draw a sunken edge +void wxEffects::DrawSunkenEdge(wxDC& dc, const wxRect& rect, int WXUNUSED(borderSize)) +{ + wxPen highlightPen(m_highlightColour, 1, wxSOLID); + wxPen lightShadowPen(m_lightShadow, 1, wxSOLID); + wxPen facePen(m_faceColour, 1, wxSOLID); + wxPen mediumShadowPen(m_mediumShadow, 1, wxSOLID); + wxPen darkShadowPen(m_darkShadow, 1, wxSOLID); + + //// LEFT AND TOP + // Draw a medium shadow pen on left and top, followed by dark shadow line to + // right and below of these lines + + dc.SetPen(mediumShadowPen); + dc.DrawLine(rect.x, rect.y, rect.x+rect.width-1, rect.y); // Top + dc.DrawLine(rect.x, rect.y, rect.x, rect.y+rect.height-1); // Left + + dc.SetPen(darkShadowPen); + dc.DrawLine(rect.x+1, rect.y+1, rect.x+rect.width-2, rect.y+1); // Top + dc.DrawLine(rect.x+1, rect.y+1, rect.x+1, rect.y+rect.height-1); // Left + + //// RIGHT AND BOTTOM + + dc.SetPen(highlightPen); + dc.DrawLine(rect.x+rect.width-1, rect.y, rect.x+rect.width-1, rect.y+rect.height-1); // Right + dc.DrawLine(rect.x, rect.y+rect.height-1, rect.x+rect.width, rect.y+rect.height-1); // Bottom + + dc.SetPen(lightShadowPen); + dc.DrawLine(rect.x+rect.width-2, rect.y+1, rect.x+rect.width-2, rect.y+rect.height-2); // Right + dc.DrawLine(rect.x+1, rect.y+rect.height-2, rect.x+rect.width-1, rect.y+rect.height-2); // Bottom + + dc.SetPen(wxNullPen); +} + +bool wxEffects::TileBitmap(const wxRect& rect, wxDC& dc, const wxBitmap& bitmap) +{ + int w = bitmap.GetWidth(); + int h = bitmap.GetHeight(); + + wxMemoryDC dcMem; + +#if wxUSE_PALETTE + static bool hiColour = (wxDisplayDepth() >= 16) ; + if (bitmap.GetPalette() && !hiColour) + { + dc.SetPalette(* bitmap.GetPalette()); + dcMem.SetPalette(* bitmap.GetPalette()); + } +#endif // wxUSE_PALETTE + + dcMem.SelectObjectAsSource(bitmap); + + int i, j; + for (i = rect.x; i < rect.x + rect.width; i += w) + { + for (j = rect.y; j < rect.y + rect.height; j+= h) + dc.Blit(i, j, bitmap.GetWidth(), bitmap.GetHeight(), & dcMem, 0, 0); + } + dcMem.SelectObject(wxNullBitmap); + +#if wxUSE_PALETTE + if (bitmap.GetPalette() && !hiColour) + { + dc.SetPalette(wxNullPalette); + dcMem.SetPalette(wxNullPalette); + } +#endif // wxUSE_PALETTE + + return true; +} diff --git a/Source/3rd Party/wx/src/common/encconv.cpp b/Source/3rd Party/wx/src/common/encconv.cpp index 15f884fb9..15509c9cb 100644 --- a/Source/3rd Party/wx/src/common/encconv.cpp +++ b/Source/3rd Party/wx/src/common/encconv.cpp @@ -1,531 +1,531 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: encconv.cpp -// Purpose: wxEncodingConverter class for converting between different -// font encodings -// Author: Vaclav Slavik -// Copyright: (c) 1999 Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/encconv.h" - -#include - -// conversion tables, generated by scripts in $(WXWIN)/misc/unictabl: -#if defined( __BORLANDC__ ) || defined(__DARWIN__) - #include "../common/unictabl.inc" -#else - #include "unictabl.inc" -#endif - -#if wxUSE_WCHAR_T - typedef wchar_t tchar; -#else - typedef char tchar; -#endif - -#ifdef __WXMAC__ -#ifdef __DARWIN__ -#include -#else -#include -#include -#include -#endif - #include "wx/fontutil.h" - #include "wx/mac/private.h" // includes mac headers - - wxUint16 gMacEncodings[wxFONTENCODING_MACMAX-wxFONTENCODING_MACMIN+1][128] ; - bool gMacEncodingsInited[wxFONTENCODING_MACMAX-wxFONTENCODING_MACMIN+1] ; -#endif - -#ifdef __WXWINCE__ - #include "wx/msw/wince/missing.h" // for bsearch() -#endif - -static const wxUint16* GetEncTable(wxFontEncoding enc) -{ -#ifdef __WXMAC__ - if( enc >= wxFONTENCODING_MACMIN && enc <= wxFONTENCODING_MACMAX ) - { - int i = enc-wxFONTENCODING_MACMIN ; - if ( gMacEncodingsInited[i] == false ) - { - TECObjectRef converter ; - TextEncodingBase code = wxMacGetSystemEncFromFontEnc( enc ) ; - TextEncodingBase unicode = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicode16BitFormat) ; - OSStatus status = TECCreateConverter(&converter,code,unicode); - char s[2] ; - s[1] = 0 ; - ByteCount byteInLen, byteOutLen ; - for( unsigned char c = 255 ; c >= 128 ; --c ) - { - s[0] = c ; - status = TECConvertText(converter, (ConstTextPtr) &s , 1, &byteInLen, - (TextPtr) &gMacEncodings[i][c-128] , 2, &byteOutLen); - } - status = TECDisposeConverter(converter); - gMacEncodingsInited[i]=true; - } - return gMacEncodings[i] ; - } -#endif - - for (int i = 0; encodings_list[i].table != NULL; i++) - { - if (encodings_list[i].encoding == enc) - return encodings_list[i].table; - } - return NULL; -} - -typedef struct { - wxUint16 u; - wxUint8 c; -} CharsetItem; - -extern "C" int wxCMPFUNC_CONV -CompareCharsetItems(const void *i1, const void *i2) -{ - return ( ((CharsetItem*)i1) -> u - ((CharsetItem*)i2) -> u ); -} - - -static CharsetItem* BuildReverseTable(const wxUint16 *tbl) -{ - CharsetItem *rev = new CharsetItem[128]; - - for (int i = 0; i < 128; i++) - rev[i].c = wxUint8(128 + i), rev[i].u = tbl[i]; - - qsort(rev, 128, sizeof(CharsetItem), CompareCharsetItems); - - return rev; -} - - - -wxEncodingConverter::wxEncodingConverter() -{ - m_Table = NULL; - m_UnicodeInput = m_UnicodeOutput = false; - m_JustCopy = false; -} - - - -bool wxEncodingConverter::Init(wxFontEncoding input_enc, wxFontEncoding output_enc, int method) -{ - unsigned i; - const wxUint16 *in_tbl; - const wxUint16 *out_tbl = NULL; - - if (m_Table) {delete[] m_Table; m_Table = NULL;} - -#if !wxUSE_WCHAR_T - if (input_enc == wxFONTENCODING_UNICODE || output_enc == wxFONTENCODING_UNICODE) return false; -#endif - - if (input_enc == output_enc) {m_JustCopy = true; return true;} - - m_UnicodeOutput = (output_enc == wxFONTENCODING_UNICODE); - m_JustCopy = false; - - if (input_enc == wxFONTENCODING_UNICODE) - { - if ((out_tbl = GetEncTable(output_enc)) == NULL) return false; - - m_Table = new tchar[65536]; - for (i = 0; i < 128; i++) m_Table[i] = (tchar)i; // 7bit ASCII - for (i = 128; i < 65536; i++) m_Table[i] = (tchar)0; - - if (method == wxCONVERT_SUBSTITUTE) - { - for (i = 0; i < encoding_unicode_fallback_count; i++) - m_Table[encoding_unicode_fallback[i].c] = (tchar) encoding_unicode_fallback[i].s; - } - - for (i = 0; i < 128; i++) - m_Table[out_tbl[i]] = (tchar)(128 + i); - - m_UnicodeInput = true; - } - else // input !Unicode - { - if ((in_tbl = GetEncTable(input_enc)) == NULL) return false; - if (output_enc != wxFONTENCODING_UNICODE) - if ((out_tbl = GetEncTable(output_enc)) == NULL) return false; - - m_UnicodeInput = false; - - m_Table = new tchar[256]; - for (i = 0; i < 128; i++) m_Table[i] = (tchar)i; // 7bit ASCII - - if (output_enc == wxFONTENCODING_UNICODE) - { - for (i = 0; i < 128; i++) m_Table[128 + i] = (tchar)in_tbl[i]; - return true; - } - else // output !Unicode - { - CharsetItem *rev = BuildReverseTable(out_tbl); - CharsetItem *item; - CharsetItem key; - - for (i = 0; i < 128; i++) - { - key.u = in_tbl[i]; - item = (CharsetItem*) bsearch(&key, rev, 128, sizeof(CharsetItem), CompareCharsetItems); - if (item == NULL && method == wxCONVERT_SUBSTITUTE) - item = (CharsetItem*) bsearch(&key, encoding_unicode_fallback, - encoding_unicode_fallback_count, sizeof(CharsetItem), CompareCharsetItems); - if (item) - m_Table[128 + i] = (tchar)item -> c; - else -#if wxUSE_WCHAR_T - m_Table[128 + i] = (wchar_t)(128 + i); -#else - m_Table[128 + i] = (char)(128 + i); -#endif - } - - delete[] rev; - } - } - - return true; -} - - -#define REPLACEMENT_CHAR ((tchar)'?') - -inline tchar GetTableValue(const tchar *table, tchar value, bool& repl) -{ - tchar r = table[value]; - if (r == 0 && value != 0) - { - r = REPLACEMENT_CHAR; - repl = true; - } - return r; -} - - -bool wxEncodingConverter::Convert(const char* input, char* output) const -{ - wxASSERT_MSG(!m_UnicodeOutput, wxT("You cannot convert to unicode if output is const char*!")); - wxASSERT_MSG(!m_UnicodeInput, wxT("You cannot convert from unicode if input is const char*!")); - - const char *i; - char *o; - - if (m_JustCopy) - { - strcpy(output, input); - return true; - } - - wxCHECK_MSG(m_Table != NULL, false, - wxT("You must call wxEncodingConverter::Init() before actually converting!")); - - bool replaced = false; - - for (i = input, o = output; *i != 0;) - *(o++) = (char)(GetTableValue(m_Table, (wxUint8)*(i++), replaced)); - *o = 0; - - return !replaced; -} - - -#if wxUSE_WCHAR_T - -bool wxEncodingConverter::Convert(const char* input, wchar_t* output) const -{ - wxASSERT_MSG(m_UnicodeOutput, wxT("You cannot convert to 8-bit if output is const wchar_t*!")); - wxASSERT_MSG(!m_UnicodeInput, wxT("You cannot convert from unicode if input is const char*!")); - - const char *i; - wchar_t *o; - - if (m_JustCopy) - { - for (i = input, o = output; *i != 0;) - *(o++) = (wchar_t)(*(i++)); - *o = 0; - return true; - } - - wxCHECK_MSG(m_Table != NULL, false, - wxT("You must call wxEncodingConverter::Init() before actually converting!")); - - bool replaced = false; - - for (i = input, o = output; *i != 0;) - *(o++) = (wchar_t)(GetTableValue(m_Table, (wxUint8)*(i++), replaced)); - *o = 0; - - return !replaced; -} - - - -bool wxEncodingConverter::Convert(const wchar_t* input, char* output) const -{ - wxASSERT_MSG(!m_UnicodeOutput, wxT("You cannot convert to unicode if output is const char*!")); - wxASSERT_MSG(m_UnicodeInput, wxT("You cannot convert from 8-bit if input is const wchar_t*!")); - - const wchar_t *i; - char *o; - - if (m_JustCopy) - { - for (i = input, o = output; *i != 0;) - *(o++) = (char)(*(i++)); - *o = 0; - return true; - } - - wxCHECK_MSG(m_Table != NULL, false, - wxT("You must call wxEncodingConverter::Init() before actually converting!")); - - bool replaced = false; - - for (i = input, o = output; *i != 0;) - *(o++) = (char)(GetTableValue(m_Table, (wxUint16)*(i++), replaced)); - *o = 0; - - return !replaced; -} - - - -bool wxEncodingConverter::Convert(const wchar_t* input, wchar_t* output) const -{ - wxASSERT_MSG(m_UnicodeOutput, wxT("You cannot convert to 8-bit if output is const wchar_t*!")); - wxASSERT_MSG(m_UnicodeInput, wxT("You cannot convert from 8-bit if input is const wchar_t*!")); - - const wchar_t *i; - wchar_t *o; - - if (m_JustCopy) - { - // wcscpy() is not guaranteed to exist - for (i = input, o = output; *i != 0;) - *(o++) = (*(i++)); - *o = 0; - return true; - } - - wxCHECK_MSG(m_Table != NULL, false, - wxT("You must call wxEncodingConverter::Init() before actually converting!")); - - bool replaced = false; - - for (i = input, o = output; *i != 0;) - *(o++) = (wchar_t)(GetTableValue(m_Table, (wxUint8)*(i++), replaced)); - *o = 0; - - return !replaced; -} - -#endif // wxUSE_WCHAR_T - - -wxString wxEncodingConverter::Convert(const wxString& input) const -{ - if (m_JustCopy) return input; - - wxString s; - const wxChar *i; - - wxCHECK_MSG(m_Table != NULL, s, - wxT("You must call wxEncodingConverter::Init() before actually converting!")); - - if (m_UnicodeInput) - { - for (i = input.c_str(); *i != 0; i++) - s << (wxChar)(m_Table[(wxUint16)*i]); - } - else - { - for (i = input.c_str(); *i != 0; i++) - s << (wxChar)(m_Table[(wxUint8)*i]); - } - - return s; -} - - - - - - - -// Following tables describe classes of encoding equivalence. -// - -#define STOP wxFONTENCODING_SYSTEM - -#define NUM_OF_PLATFORMS 4 /*must conform to enum wxPLATFORM_XXXX !!!*/ -#define ENC_PER_PLATFORM 3 - // max no. of encodings for one language used on one platform. - // Using maximum of everything at the current moment to not make the - // library larger than necessary. Make larger only if necessary - MR - -static const wxFontEncoding - EquivalentEncodings[][NUM_OF_PLATFORMS][ENC_PER_PLATFORM+1] = { - - // *** Please put more common encodings as first! *** - - // Western European - { - /* unix */ {wxFONTENCODING_ISO8859_1, wxFONTENCODING_ISO8859_15, STOP}, - /* windows */ {wxFONTENCODING_CP1252, STOP}, - /* os2 */ {STOP}, - /* mac */ {wxFONTENCODING_MACROMAN, STOP} - }, - - // Central European - { - /* unix */ {wxFONTENCODING_ISO8859_2, STOP}, - /* windows */ {wxFONTENCODING_CP1250, STOP}, - /* os2 */ {STOP}, - /* mac */ {wxFONTENCODING_MACCENTRALEUR, STOP} - }, - - // Baltic - { - /* unix */ {wxFONTENCODING_ISO8859_13, wxFONTENCODING_ISO8859_4, STOP}, - /* windows */ {wxFONTENCODING_CP1257, STOP}, - /* os2 */ {STOP}, - /* mac */ {STOP} - }, - - // Hebrew - { - /* unix */ {wxFONTENCODING_ISO8859_8, STOP}, - /* windows */ {wxFONTENCODING_CP1255, STOP}, - /* os2 */ {STOP}, - /* mac */ {wxFONTENCODING_MACHEBREW, STOP} - }, - - // Greek - { - /* unix */ {wxFONTENCODING_ISO8859_7, STOP}, - /* windows */ {wxFONTENCODING_CP1253, STOP}, - /* os2 */ {STOP}, - /* mac */ {wxFONTENCODING_MACGREEK, STOP} - }, - - // Arabic - { - /* unix */ {wxFONTENCODING_ISO8859_6, STOP}, - /* windows */ {wxFONTENCODING_CP1256, STOP}, - /* os2 */ {STOP}, - /* mac */ {wxFONTENCODING_MACARABIC, STOP} - }, - - // Turkish - { - /* unix */ {wxFONTENCODING_ISO8859_9, STOP}, - /* windows */ {wxFONTENCODING_CP1254, STOP}, - /* os2 */ {STOP}, - /* mac */ {wxFONTENCODING_MACTURKISH, STOP} - }, - - // Cyrillic - { - /* unix */ {wxFONTENCODING_KOI8, wxFONTENCODING_KOI8_U, wxFONTENCODING_ISO8859_5, STOP}, - /* windows */ {wxFONTENCODING_CP1251, STOP}, - /* os2 */ {STOP}, - /* mac */ {wxFONTENCODING_MACCYRILLIC, STOP} - }, - - {{STOP},{STOP},{STOP},{STOP}} /* Terminator */ - /* no, _not_ Arnold! */ -}; - - -static bool FindEncoding(const wxFontEncodingArray& arr, wxFontEncoding f) -{ - for (wxFontEncodingArray::const_iterator it = arr.begin(), en = arr.end(); - it != en; ++it) - if (*it == f) - return true; - return false; -} - -wxFontEncodingArray wxEncodingConverter::GetPlatformEquivalents(wxFontEncoding enc, int platform) -{ - if (platform == wxPLATFORM_CURRENT) - { -#if defined(__WXMSW__) - platform = wxPLATFORM_WINDOWS; -#elif defined(__WXGTK__) || defined(__WXMOTIF__) - platform = wxPLATFORM_UNIX; -#elif defined(__WXPM__) - platform = wxPLATFORM_OS2; -#elif defined(__WXMAC__) - platform = wxPLATFORM_MAC; -#endif - } - - int i, clas, e ; - const wxFontEncoding *f; - wxFontEncodingArray arr; - - clas = 0; - while (EquivalentEncodings[clas][0][0] != STOP) - { - for (i = 0; i < NUM_OF_PLATFORMS; i++) - for (e = 0; EquivalentEncodings[clas][i][e] != STOP; e++) - if (EquivalentEncodings[clas][i][e] == enc) - { - for (f = EquivalentEncodings[clas][platform]; *f != STOP; f++) - if (*f == enc) arr.push_back(enc); - for (f = EquivalentEncodings[clas][platform]; *f != STOP; f++) - if (!FindEncoding(arr, *f)) arr.push_back(*f); - i = NUM_OF_PLATFORMS/*hack*/; break; - } - clas++; - } - - return arr; -} - - - -wxFontEncodingArray wxEncodingConverter::GetAllEquivalents(wxFontEncoding enc) -{ - int i, clas, e, j ; - const wxFontEncoding *f; - wxFontEncodingArray arr; - - arr = GetPlatformEquivalents(enc); // we want them to be first items in array - - clas = 0; - while (EquivalentEncodings[clas][0][0] != STOP) - { - for (i = 0; i < NUM_OF_PLATFORMS; i++) - for (e = 0; EquivalentEncodings[clas][i][e] != STOP; e++) - if (EquivalentEncodings[clas][i][e] == enc) - { - for (j = 0; j < NUM_OF_PLATFORMS; j++) - for (f = EquivalentEncodings[clas][j]; *f != STOP; f++) - if (!FindEncoding(arr, *f)) arr.push_back(*f); - i = NUM_OF_PLATFORMS/*hack*/; break; - } - clas++; - } - - return arr; -} - +///////////////////////////////////////////////////////////////////////////// +// Name: encconv.cpp +// Purpose: wxEncodingConverter class for converting between different +// font encodings +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/encconv.h" + +#include + +// conversion tables, generated by scripts in $(WXWIN)/misc/unictabl: +#if defined( __BORLANDC__ ) || defined(__DARWIN__) + #include "../common/unictabl.inc" +#else + #include "unictabl.inc" +#endif + +#if wxUSE_WCHAR_T + typedef wchar_t tchar; +#else + typedef char tchar; +#endif + +#ifdef __WXMAC__ +#ifdef __DARWIN__ +#include +#else +#include +#include +#include +#endif + #include "wx/fontutil.h" + #include "wx/mac/private.h" // includes mac headers + + wxUint16 gMacEncodings[wxFONTENCODING_MACMAX-wxFONTENCODING_MACMIN+1][128] ; + bool gMacEncodingsInited[wxFONTENCODING_MACMAX-wxFONTENCODING_MACMIN+1] ; +#endif + +#ifdef __WXWINCE__ + #include "wx/msw/wince/missing.h" // for bsearch() +#endif + +static const wxUint16* GetEncTable(wxFontEncoding enc) +{ +#ifdef __WXMAC__ + if( enc >= wxFONTENCODING_MACMIN && enc <= wxFONTENCODING_MACMAX ) + { + int i = enc-wxFONTENCODING_MACMIN ; + if ( gMacEncodingsInited[i] == false ) + { + TECObjectRef converter ; + TextEncodingBase code = wxMacGetSystemEncFromFontEnc( enc ) ; + TextEncodingBase unicode = CreateTextEncoding(kTextEncodingUnicodeDefault,0,kUnicode16BitFormat) ; + OSStatus status = TECCreateConverter(&converter,code,unicode); + char s[2] ; + s[1] = 0 ; + ByteCount byteInLen, byteOutLen ; + for( unsigned char c = 255 ; c >= 128 ; --c ) + { + s[0] = c ; + status = TECConvertText(converter, (ConstTextPtr) &s , 1, &byteInLen, + (TextPtr) &gMacEncodings[i][c-128] , 2, &byteOutLen); + } + status = TECDisposeConverter(converter); + gMacEncodingsInited[i]=true; + } + return gMacEncodings[i] ; + } +#endif + + for (int i = 0; encodings_list[i].table != NULL; i++) + { + if (encodings_list[i].encoding == enc) + return encodings_list[i].table; + } + return NULL; +} + +typedef struct { + wxUint16 u; + wxUint8 c; +} CharsetItem; + +extern "C" int wxCMPFUNC_CONV +CompareCharsetItems(const void *i1, const void *i2) +{ + return ( ((CharsetItem*)i1) -> u - ((CharsetItem*)i2) -> u ); +} + + +static CharsetItem* BuildReverseTable(const wxUint16 *tbl) +{ + CharsetItem *rev = new CharsetItem[128]; + + for (int i = 0; i < 128; i++) + rev[i].c = wxUint8(128 + i), rev[i].u = tbl[i]; + + qsort(rev, 128, sizeof(CharsetItem), CompareCharsetItems); + + return rev; +} + + + +wxEncodingConverter::wxEncodingConverter() +{ + m_Table = NULL; + m_UnicodeInput = m_UnicodeOutput = false; + m_JustCopy = false; +} + + + +bool wxEncodingConverter::Init(wxFontEncoding input_enc, wxFontEncoding output_enc, int method) +{ + unsigned i; + const wxUint16 *in_tbl; + const wxUint16 *out_tbl = NULL; + + if (m_Table) {delete[] m_Table; m_Table = NULL;} + +#if !wxUSE_WCHAR_T + if (input_enc == wxFONTENCODING_UNICODE || output_enc == wxFONTENCODING_UNICODE) return false; +#endif + + if (input_enc == output_enc) {m_JustCopy = true; return true;} + + m_UnicodeOutput = (output_enc == wxFONTENCODING_UNICODE); + m_JustCopy = false; + + if (input_enc == wxFONTENCODING_UNICODE) + { + if ((out_tbl = GetEncTable(output_enc)) == NULL) return false; + + m_Table = new tchar[65536]; + for (i = 0; i < 128; i++) m_Table[i] = (tchar)i; // 7bit ASCII + for (i = 128; i < 65536; i++) m_Table[i] = (tchar)0; + + if (method == wxCONVERT_SUBSTITUTE) + { + for (i = 0; i < encoding_unicode_fallback_count; i++) + m_Table[encoding_unicode_fallback[i].c] = (tchar) encoding_unicode_fallback[i].s; + } + + for (i = 0; i < 128; i++) + m_Table[out_tbl[i]] = (tchar)(128 + i); + + m_UnicodeInput = true; + } + else // input !Unicode + { + if ((in_tbl = GetEncTable(input_enc)) == NULL) return false; + if (output_enc != wxFONTENCODING_UNICODE) + if ((out_tbl = GetEncTable(output_enc)) == NULL) return false; + + m_UnicodeInput = false; + + m_Table = new tchar[256]; + for (i = 0; i < 128; i++) m_Table[i] = (tchar)i; // 7bit ASCII + + if (output_enc == wxFONTENCODING_UNICODE) + { + for (i = 0; i < 128; i++) m_Table[128 + i] = (tchar)in_tbl[i]; + return true; + } + else // output !Unicode + { + CharsetItem *rev = BuildReverseTable(out_tbl); + CharsetItem *item; + CharsetItem key; + + for (i = 0; i < 128; i++) + { + key.u = in_tbl[i]; + item = (CharsetItem*) bsearch(&key, rev, 128, sizeof(CharsetItem), CompareCharsetItems); + if (item == NULL && method == wxCONVERT_SUBSTITUTE) + item = (CharsetItem*) bsearch(&key, encoding_unicode_fallback, + encoding_unicode_fallback_count, sizeof(CharsetItem), CompareCharsetItems); + if (item) + m_Table[128 + i] = (tchar)item -> c; + else +#if wxUSE_WCHAR_T + m_Table[128 + i] = (wchar_t)(128 + i); +#else + m_Table[128 + i] = (char)(128 + i); +#endif + } + + delete[] rev; + } + } + + return true; +} + + +#define REPLACEMENT_CHAR ((tchar)'?') + +inline tchar GetTableValue(const tchar *table, tchar value, bool& repl) +{ + tchar r = table[value]; + if (r == 0 && value != 0) + { + r = REPLACEMENT_CHAR; + repl = true; + } + return r; +} + + +bool wxEncodingConverter::Convert(const char* input, char* output) const +{ + wxASSERT_MSG(!m_UnicodeOutput, wxT("You cannot convert to unicode if output is const char*!")); + wxASSERT_MSG(!m_UnicodeInput, wxT("You cannot convert from unicode if input is const char*!")); + + const char *i; + char *o; + + if (m_JustCopy) + { + strcpy(output, input); + return true; + } + + wxCHECK_MSG(m_Table != NULL, false, + wxT("You must call wxEncodingConverter::Init() before actually converting!")); + + bool replaced = false; + + for (i = input, o = output; *i != 0;) + *(o++) = (char)(GetTableValue(m_Table, (wxUint8)*(i++), replaced)); + *o = 0; + + return !replaced; +} + + +#if wxUSE_WCHAR_T + +bool wxEncodingConverter::Convert(const char* input, wchar_t* output) const +{ + wxASSERT_MSG(m_UnicodeOutput, wxT("You cannot convert to 8-bit if output is const wchar_t*!")); + wxASSERT_MSG(!m_UnicodeInput, wxT("You cannot convert from unicode if input is const char*!")); + + const char *i; + wchar_t *o; + + if (m_JustCopy) + { + for (i = input, o = output; *i != 0;) + *(o++) = (wchar_t)(*(i++)); + *o = 0; + return true; + } + + wxCHECK_MSG(m_Table != NULL, false, + wxT("You must call wxEncodingConverter::Init() before actually converting!")); + + bool replaced = false; + + for (i = input, o = output; *i != 0;) + *(o++) = (wchar_t)(GetTableValue(m_Table, (wxUint8)*(i++), replaced)); + *o = 0; + + return !replaced; +} + + + +bool wxEncodingConverter::Convert(const wchar_t* input, char* output) const +{ + wxASSERT_MSG(!m_UnicodeOutput, wxT("You cannot convert to unicode if output is const char*!")); + wxASSERT_MSG(m_UnicodeInput, wxT("You cannot convert from 8-bit if input is const wchar_t*!")); + + const wchar_t *i; + char *o; + + if (m_JustCopy) + { + for (i = input, o = output; *i != 0;) + *(o++) = (char)(*(i++)); + *o = 0; + return true; + } + + wxCHECK_MSG(m_Table != NULL, false, + wxT("You must call wxEncodingConverter::Init() before actually converting!")); + + bool replaced = false; + + for (i = input, o = output; *i != 0;) + *(o++) = (char)(GetTableValue(m_Table, (wxUint16)*(i++), replaced)); + *o = 0; + + return !replaced; +} + + + +bool wxEncodingConverter::Convert(const wchar_t* input, wchar_t* output) const +{ + wxASSERT_MSG(m_UnicodeOutput, wxT("You cannot convert to 8-bit if output is const wchar_t*!")); + wxASSERT_MSG(m_UnicodeInput, wxT("You cannot convert from 8-bit if input is const wchar_t*!")); + + const wchar_t *i; + wchar_t *o; + + if (m_JustCopy) + { + // wcscpy() is not guaranteed to exist + for (i = input, o = output; *i != 0;) + *(o++) = (*(i++)); + *o = 0; + return true; + } + + wxCHECK_MSG(m_Table != NULL, false, + wxT("You must call wxEncodingConverter::Init() before actually converting!")); + + bool replaced = false; + + for (i = input, o = output; *i != 0;) + *(o++) = (wchar_t)(GetTableValue(m_Table, (wxUint8)*(i++), replaced)); + *o = 0; + + return !replaced; +} + +#endif // wxUSE_WCHAR_T + + +wxString wxEncodingConverter::Convert(const wxString& input) const +{ + if (m_JustCopy) return input; + + wxString s; + const wxChar *i; + + wxCHECK_MSG(m_Table != NULL, s, + wxT("You must call wxEncodingConverter::Init() before actually converting!")); + + if (m_UnicodeInput) + { + for (i = input.c_str(); *i != 0; i++) + s << (wxChar)(m_Table[(wxUint16)*i]); + } + else + { + for (i = input.c_str(); *i != 0; i++) + s << (wxChar)(m_Table[(wxUint8)*i]); + } + + return s; +} + + + + + + + +// Following tables describe classes of encoding equivalence. +// + +#define STOP wxFONTENCODING_SYSTEM + +#define NUM_OF_PLATFORMS 4 /*must conform to enum wxPLATFORM_XXXX !!!*/ +#define ENC_PER_PLATFORM 3 + // max no. of encodings for one language used on one platform. + // Using maximum of everything at the current moment to not make the + // library larger than necessary. Make larger only if necessary - MR + +static const wxFontEncoding + EquivalentEncodings[][NUM_OF_PLATFORMS][ENC_PER_PLATFORM+1] = { + + // *** Please put more common encodings as first! *** + + // Western European + { + /* unix */ {wxFONTENCODING_ISO8859_1, wxFONTENCODING_ISO8859_15, STOP}, + /* windows */ {wxFONTENCODING_CP1252, STOP}, + /* os2 */ {STOP}, + /* mac */ {wxFONTENCODING_MACROMAN, STOP} + }, + + // Central European + { + /* unix */ {wxFONTENCODING_ISO8859_2, STOP}, + /* windows */ {wxFONTENCODING_CP1250, STOP}, + /* os2 */ {STOP}, + /* mac */ {wxFONTENCODING_MACCENTRALEUR, STOP} + }, + + // Baltic + { + /* unix */ {wxFONTENCODING_ISO8859_13, wxFONTENCODING_ISO8859_4, STOP}, + /* windows */ {wxFONTENCODING_CP1257, STOP}, + /* os2 */ {STOP}, + /* mac */ {STOP} + }, + + // Hebrew + { + /* unix */ {wxFONTENCODING_ISO8859_8, STOP}, + /* windows */ {wxFONTENCODING_CP1255, STOP}, + /* os2 */ {STOP}, + /* mac */ {wxFONTENCODING_MACHEBREW, STOP} + }, + + // Greek + { + /* unix */ {wxFONTENCODING_ISO8859_7, STOP}, + /* windows */ {wxFONTENCODING_CP1253, STOP}, + /* os2 */ {STOP}, + /* mac */ {wxFONTENCODING_MACGREEK, STOP} + }, + + // Arabic + { + /* unix */ {wxFONTENCODING_ISO8859_6, STOP}, + /* windows */ {wxFONTENCODING_CP1256, STOP}, + /* os2 */ {STOP}, + /* mac */ {wxFONTENCODING_MACARABIC, STOP} + }, + + // Turkish + { + /* unix */ {wxFONTENCODING_ISO8859_9, STOP}, + /* windows */ {wxFONTENCODING_CP1254, STOP}, + /* os2 */ {STOP}, + /* mac */ {wxFONTENCODING_MACTURKISH, STOP} + }, + + // Cyrillic + { + /* unix */ {wxFONTENCODING_KOI8, wxFONTENCODING_KOI8_U, wxFONTENCODING_ISO8859_5, STOP}, + /* windows */ {wxFONTENCODING_CP1251, STOP}, + /* os2 */ {STOP}, + /* mac */ {wxFONTENCODING_MACCYRILLIC, STOP} + }, + + {{STOP},{STOP},{STOP},{STOP}} /* Terminator */ + /* no, _not_ Arnold! */ +}; + + +static bool FindEncoding(const wxFontEncodingArray& arr, wxFontEncoding f) +{ + for (wxFontEncodingArray::const_iterator it = arr.begin(), en = arr.end(); + it != en; ++it) + if (*it == f) + return true; + return false; +} + +wxFontEncodingArray wxEncodingConverter::GetPlatformEquivalents(wxFontEncoding enc, int platform) +{ + if (platform == wxPLATFORM_CURRENT) + { +#if defined(__WXMSW__) + platform = wxPLATFORM_WINDOWS; +#elif defined(__WXGTK__) || defined(__WXMOTIF__) + platform = wxPLATFORM_UNIX; +#elif defined(__WXPM__) + platform = wxPLATFORM_OS2; +#elif defined(__WXMAC__) + platform = wxPLATFORM_MAC; +#endif + } + + int i, clas, e ; + const wxFontEncoding *f; + wxFontEncodingArray arr; + + clas = 0; + while (EquivalentEncodings[clas][0][0] != STOP) + { + for (i = 0; i < NUM_OF_PLATFORMS; i++) + for (e = 0; EquivalentEncodings[clas][i][e] != STOP; e++) + if (EquivalentEncodings[clas][i][e] == enc) + { + for (f = EquivalentEncodings[clas][platform]; *f != STOP; f++) + if (*f == enc) arr.push_back(enc); + for (f = EquivalentEncodings[clas][platform]; *f != STOP; f++) + if (!FindEncoding(arr, *f)) arr.push_back(*f); + i = NUM_OF_PLATFORMS/*hack*/; break; + } + clas++; + } + + return arr; +} + + + +wxFontEncodingArray wxEncodingConverter::GetAllEquivalents(wxFontEncoding enc) +{ + int i, clas, e, j ; + const wxFontEncoding *f; + wxFontEncodingArray arr; + + arr = GetPlatformEquivalents(enc); // we want them to be first items in array + + clas = 0; + while (EquivalentEncodings[clas][0][0] != STOP) + { + for (i = 0; i < NUM_OF_PLATFORMS; i++) + for (e = 0; EquivalentEncodings[clas][i][e] != STOP; e++) + if (EquivalentEncodings[clas][i][e] == enc) + { + for (j = 0; j < NUM_OF_PLATFORMS; j++) + for (f = EquivalentEncodings[clas][j]; *f != STOP; f++) + if (!FindEncoding(arr, *f)) arr.push_back(*f); + i = NUM_OF_PLATFORMS/*hack*/; break; + } + clas++; + } + + return arr; +} + diff --git a/Source/3rd Party/wx/src/common/event.cpp b/Source/3rd Party/wx/src/common/event.cpp index 65bc1d3ca..934456c80 100644 --- a/Source/3rd Party/wx/src/common/event.cpp +++ b/Source/3rd Party/wx/src/common/event.cpp @@ -1,1499 +1,1499 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/event.cpp -// Purpose: Event classes -// Author: Julian Smart -// Modified by: -// Created: 01/02/97 -// RCS-ID: $Id: event.cpp 61982 2009-09-20 21:48:50Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/event.h" - -#ifndef WX_PRECOMP - #include "wx/list.h" - #include "wx/app.h" - #include "wx/utils.h" - #include "wx/stopwatch.h" - #include "wx/module.h" - - #if wxUSE_GUI - #include "wx/window.h" - #include "wx/control.h" - #include "wx/dc.h" - #include "wx/textctrl.h" - #include "wx/validate.h" - #endif // wxUSE_GUI -#endif - -#if wxUSE_BASE - #include "wx/ptr_scpd.h" - - wxDECLARE_SCOPED_PTR(wxEvent, wxEventPtr) - wxDEFINE_SCOPED_PTR(wxEvent, wxEventPtr) -#endif // wxUSE_BASE - -// ---------------------------------------------------------------------------- -// wxWin macros -// ---------------------------------------------------------------------------- - -#if wxUSE_BASE - IMPLEMENT_DYNAMIC_CLASS(wxEvtHandler, wxObject) - IMPLEMENT_ABSTRACT_CLASS(wxEvent, wxObject) -#endif // wxUSE_BASE - -#if wxUSE_GUI - IMPLEMENT_DYNAMIC_CLASS(wxIdleEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxCommandEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxNotifyEvent, wxCommandEvent) - IMPLEMENT_DYNAMIC_CLASS(wxScrollEvent, wxCommandEvent) - IMPLEMENT_DYNAMIC_CLASS(wxScrollWinEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxMouseEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxKeyEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxSizeEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxPaintEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxNcPaintEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxEraseEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxMoveEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxFocusEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxChildFocusEvent, wxCommandEvent) - IMPLEMENT_DYNAMIC_CLASS(wxCloseEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxShowEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxMaximizeEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxIconizeEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxMenuEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxJoystickEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxDropFilesEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxActivateEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxInitDialogEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxSetCursorEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxSysColourChangedEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxDisplayChangedEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxUpdateUIEvent, wxCommandEvent) - IMPLEMENT_DYNAMIC_CLASS(wxNavigationKeyEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxPaletteChangedEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxQueryNewPaletteEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxWindowCreateEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxWindowDestroyEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxHelpEvent, wxCommandEvent) - IMPLEMENT_DYNAMIC_CLASS(wxContextMenuEvent, wxCommandEvent) - IMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureChangedEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureLostEvent, wxEvent) - IMPLEMENT_DYNAMIC_CLASS(wxClipboardTextEvent, wxCommandEvent) -#endif // wxUSE_GUI - -#if wxUSE_BASE - -const wxEventTable *wxEvtHandler::GetEventTable() const - { return &wxEvtHandler::sm_eventTable; } - -const wxEventTable wxEvtHandler::sm_eventTable = - { (const wxEventTable *)NULL, &wxEvtHandler::sm_eventTableEntries[0] }; - -wxEventHashTable &wxEvtHandler::GetEventHashTable() const - { return wxEvtHandler::sm_eventHashTable; } - -wxEventHashTable wxEvtHandler::sm_eventHashTable(wxEvtHandler::sm_eventTable); - -const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] = - { DECLARE_EVENT_TABLE_ENTRY(wxEVT_NULL, 0, 0, (wxObjectEventFunction)NULL, NULL) }; - - -#ifdef __WXDEBUG__ -// Clear up event hash table contents or we can get problems -// when C++ is cleaning up the static object -class wxEventTableEntryModule: public wxModule -{ -DECLARE_DYNAMIC_CLASS(wxEventTableEntryModule) -public: - wxEventTableEntryModule() {} - bool OnInit() - { - wxEventHashTable::ReconstructAll(); - return true; - } - void OnExit() - { - wxEventHashTable::ClearAll(); - } -}; -IMPLEMENT_DYNAMIC_CLASS(wxEventTableEntryModule, wxModule) -#endif - -// ---------------------------------------------------------------------------- -// global variables -// ---------------------------------------------------------------------------- - -// To put pending event handlers -wxList *wxPendingEvents = (wxList *)NULL; - -#if wxUSE_THREADS - // protects wxPendingEvents list - wxCriticalSection *wxPendingEventsLocker = (wxCriticalSection *)NULL; -#endif - -#if !WXWIN_COMPATIBILITY_EVENT_TYPES - -// common event types are defined here, other event types are defined by the -// components which use them - -const wxEventType wxEVT_FIRST = 10000; -const wxEventType wxEVT_USER_FIRST = wxEVT_FIRST + 2000; - -DEFINE_EVENT_TYPE(wxEVT_NULL) -DEFINE_EVENT_TYPE(wxEVT_IDLE) -DEFINE_EVENT_TYPE(wxEVT_SOCKET) - -#endif // !WXWIN_COMPATIBILITY_EVENT_TYPES - -#endif // wxUSE_BASE - -#if wxUSE_GUI - -#if !WXWIN_COMPATIBILITY_EVENT_TYPES - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_BUTTON_CLICKED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_CHECKBOX_CLICKED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_CHOICE_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LISTBOX_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_MENU_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SLIDER_UPDATED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RADIOBOX_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RADIOBUTTON_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SCROLLBAR_UPDATED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_VLBOX_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_COMBOBOX_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOOL_RCLICKED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOOL_ENTER) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPINCTRL_UPDATED) - -// Sockets and timers send events, too -DEFINE_EVENT_TYPE(wxEVT_TIMER) - -// Mouse event types -DEFINE_EVENT_TYPE(wxEVT_LEFT_DOWN) -DEFINE_EVENT_TYPE(wxEVT_LEFT_UP) -DEFINE_EVENT_TYPE(wxEVT_MIDDLE_DOWN) -DEFINE_EVENT_TYPE(wxEVT_MIDDLE_UP) -DEFINE_EVENT_TYPE(wxEVT_RIGHT_DOWN) -DEFINE_EVENT_TYPE(wxEVT_RIGHT_UP) -DEFINE_EVENT_TYPE(wxEVT_MOTION) -DEFINE_EVENT_TYPE(wxEVT_ENTER_WINDOW) -DEFINE_EVENT_TYPE(wxEVT_LEAVE_WINDOW) -DEFINE_EVENT_TYPE(wxEVT_LEFT_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_MIDDLE_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_RIGHT_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_SET_FOCUS) -DEFINE_EVENT_TYPE(wxEVT_KILL_FOCUS) -DEFINE_EVENT_TYPE(wxEVT_CHILD_FOCUS) -DEFINE_EVENT_TYPE(wxEVT_MOUSEWHEEL) - -// Non-client mouse events -DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_DOWN) -DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_UP) -DEFINE_EVENT_TYPE(wxEVT_NC_MIDDLE_DOWN) -DEFINE_EVENT_TYPE(wxEVT_NC_MIDDLE_UP) -DEFINE_EVENT_TYPE(wxEVT_NC_RIGHT_DOWN) -DEFINE_EVENT_TYPE(wxEVT_NC_RIGHT_UP) -DEFINE_EVENT_TYPE(wxEVT_NC_MOTION) -DEFINE_EVENT_TYPE(wxEVT_NC_ENTER_WINDOW) -DEFINE_EVENT_TYPE(wxEVT_NC_LEAVE_WINDOW) -DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_NC_MIDDLE_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_NC_RIGHT_DCLICK) - -// Character input event type -DEFINE_EVENT_TYPE(wxEVT_CHAR) -DEFINE_EVENT_TYPE(wxEVT_CHAR_HOOK) -DEFINE_EVENT_TYPE(wxEVT_NAVIGATION_KEY) -DEFINE_EVENT_TYPE(wxEVT_KEY_DOWN) -DEFINE_EVENT_TYPE(wxEVT_KEY_UP) -#if wxUSE_HOTKEY -DEFINE_EVENT_TYPE(wxEVT_HOTKEY) -#endif - -// Set cursor event -DEFINE_EVENT_TYPE(wxEVT_SET_CURSOR) - -// wxScrollbar and wxSlider event identifiers -DEFINE_EVENT_TYPE(wxEVT_SCROLL_TOP) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_BOTTOM) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_LINEUP) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_LINEDOWN) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_PAGEUP) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_PAGEDOWN) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_THUMBTRACK) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_THUMBRELEASE) -DEFINE_EVENT_TYPE(wxEVT_SCROLL_CHANGED) - -// Scroll events from wxWindow -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_TOP) -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_BOTTOM) -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_LINEUP) -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_LINEDOWN) -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_PAGEUP) -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_PAGEDOWN) -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_THUMBTRACK) -DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_THUMBRELEASE) - -// System events -DEFINE_EVENT_TYPE(wxEVT_SIZE) -DEFINE_EVENT_TYPE(wxEVT_SIZING) -DEFINE_EVENT_TYPE(wxEVT_MOVE) -DEFINE_EVENT_TYPE(wxEVT_MOVING) -DEFINE_EVENT_TYPE(wxEVT_CLOSE_WINDOW) -DEFINE_EVENT_TYPE(wxEVT_END_SESSION) -DEFINE_EVENT_TYPE(wxEVT_QUERY_END_SESSION) -DEFINE_EVENT_TYPE(wxEVT_HIBERNATE) -DEFINE_EVENT_TYPE(wxEVT_ACTIVATE_APP) -DEFINE_EVENT_TYPE(wxEVT_POWER) -DEFINE_EVENT_TYPE(wxEVT_ACTIVATE) -DEFINE_EVENT_TYPE(wxEVT_CREATE) -DEFINE_EVENT_TYPE(wxEVT_DESTROY) -DEFINE_EVENT_TYPE(wxEVT_SHOW) -DEFINE_EVENT_TYPE(wxEVT_ICONIZE) -DEFINE_EVENT_TYPE(wxEVT_MAXIMIZE) -DEFINE_EVENT_TYPE(wxEVT_MOUSE_CAPTURE_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_MOUSE_CAPTURE_LOST) -DEFINE_EVENT_TYPE(wxEVT_PAINT) -DEFINE_EVENT_TYPE(wxEVT_ERASE_BACKGROUND) -DEFINE_EVENT_TYPE(wxEVT_NC_PAINT) -DEFINE_EVENT_TYPE(wxEVT_PAINT_ICON) -DEFINE_EVENT_TYPE(wxEVT_MENU_OPEN) -DEFINE_EVENT_TYPE(wxEVT_MENU_CLOSE) -DEFINE_EVENT_TYPE(wxEVT_MENU_HIGHLIGHT) -DEFINE_EVENT_TYPE(wxEVT_CONTEXT_MENU) -DEFINE_EVENT_TYPE(wxEVT_SYS_COLOUR_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_DISPLAY_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_SETTING_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_QUERY_NEW_PALETTE) -DEFINE_EVENT_TYPE(wxEVT_PALETTE_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_JOY_BUTTON_DOWN) -DEFINE_EVENT_TYPE(wxEVT_JOY_BUTTON_UP) -DEFINE_EVENT_TYPE(wxEVT_JOY_MOVE) -DEFINE_EVENT_TYPE(wxEVT_JOY_ZMOVE) -DEFINE_EVENT_TYPE(wxEVT_DROP_FILES) -DEFINE_EVENT_TYPE(wxEVT_DRAW_ITEM) -DEFINE_EVENT_TYPE(wxEVT_MEASURE_ITEM) -DEFINE_EVENT_TYPE(wxEVT_COMPARE_ITEM) -DEFINE_EVENT_TYPE(wxEVT_INIT_DIALOG) -DEFINE_EVENT_TYPE(wxEVT_UPDATE_UI) - -// Clipboard events -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_COPY) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_CUT) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_PASTE) - -// Generic command events -// Note: a click is a higher-level event than button down/up -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LEFT_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LEFT_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RIGHT_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_RIGHT_DCLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SET_FOCUS) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_KILL_FOCUS) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_ENTER) - -// Help events -DEFINE_EVENT_TYPE(wxEVT_HELP) -DEFINE_EVENT_TYPE(wxEVT_DETAILED_HELP) - -#endif // !WXWIN_COMPATIBILITY_EVENT_TYPES - -#endif // wxUSE_GUI - -#if wxUSE_BASE - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// event initialization -// ---------------------------------------------------------------------------- - -int wxNewEventType() -{ - // MT-FIXME - static int s_lastUsedEventType = wxEVT_FIRST; - - return s_lastUsedEventType++; -} - -// ---------------------------------------------------------------------------- -// wxEvent -// ---------------------------------------------------------------------------- - -/* - * General wxWidgets events, covering - * all interesting things that might happen (button clicking, resizing, - * setting text in widgets, etc.). - * - * For each completely new event type, derive a new event class. - * - */ - -wxEvent::wxEvent(int theId, wxEventType commandType ) -{ - m_eventType = commandType; - m_eventObject = (wxObject *) NULL; - m_timeStamp = 0; - m_id = theId; - m_skipped = false; - m_callbackUserData = (wxObject *) NULL; - m_isCommandEvent = false; - m_propagationLevel = wxEVENT_PROPAGATE_NONE; -} - -wxEvent::wxEvent(const wxEvent &src) - : wxObject(src) - , m_eventObject(src.m_eventObject) - , m_eventType(src.m_eventType) - , m_timeStamp(src.m_timeStamp) - , m_id(src.m_id) - , m_callbackUserData(src.m_callbackUserData) - , m_propagationLevel(src.m_propagationLevel) - , m_skipped(src.m_skipped) - , m_isCommandEvent(src.m_isCommandEvent) -{ -} - -#endif // wxUSE_BASE - -#if wxUSE_GUI - -/* - * Command events - * - */ - -#ifdef __VISUALC__ - // 'this' : used in base member initializer list (for m_commandString) - #pragma warning(disable:4355) -#endif - -wxCommandEvent::wxCommandEvent(wxEventType commandType, int theId) - : wxEvent(theId, commandType) -#if WXWIN_COMPATIBILITY_2_4 - , m_commandString(this) -#endif -{ - m_clientData = (char *) NULL; - m_clientObject = (wxClientData *) NULL; - m_extraLong = 0; - m_commandInt = 0; - m_isCommandEvent = true; - - // the command events are propagated upwards by default - m_propagationLevel = wxEVENT_PROPAGATE_MAX; -} - -#ifdef __VISUALC__ - #pragma warning(default:4355) -#endif - -wxString wxCommandEvent::GetString() const -{ - if(m_eventType != wxEVT_COMMAND_TEXT_UPDATED || !m_eventObject) - return m_cmdString; - else - { -#if wxUSE_TEXTCTRL - wxTextCtrl *txt = wxDynamicCast(m_eventObject, wxTextCtrl); - if(txt) - return txt->GetValue(); - else -#endif // wxUSE_TEXTCTRL - return m_cmdString; - } -} - -/* - * UI update events - */ - -#if wxUSE_LONGLONG -wxLongLong wxUpdateUIEvent::sm_lastUpdate = 0; -#endif - -long wxUpdateUIEvent::sm_updateInterval = 0; - -wxUpdateUIMode wxUpdateUIEvent::sm_updateMode = wxUPDATE_UI_PROCESS_ALL; - -// Can we update? -bool wxUpdateUIEvent::CanUpdate(wxWindowBase *win) -{ - // Don't update if we've switched global updating off - // and this window doesn't support updates. - if (win && - (GetMode() == wxUPDATE_UI_PROCESS_SPECIFIED && - ((win->GetExtraStyle() & wxWS_EX_PROCESS_UI_UPDATES) == 0))) - return false; - - if (sm_updateInterval == -1) - return false; - - if (sm_updateInterval == 0) - return true; - -#if wxUSE_STOPWATCH && wxUSE_LONGLONG - wxLongLong now = wxGetLocalTimeMillis(); - if (now > (sm_lastUpdate + sm_updateInterval)) - { - return true; - } - - return false; -#else - // If we don't have wxStopWatch or wxLongLong, we - // should err on the safe side and update now anyway. - return true; -#endif -} - -// Reset the update time to provide a delay until the next -// time we should update -void wxUpdateUIEvent::ResetUpdateTime() -{ -#if wxUSE_STOPWATCH && wxUSE_LONGLONG - if (sm_updateInterval > 0) - { - wxLongLong now = wxGetLocalTimeMillis(); - if (now > (sm_lastUpdate + sm_updateInterval)) - { - sm_lastUpdate = now; - } - } -#endif -} - -/* - * Idle events - */ - -wxIdleMode wxIdleEvent::sm_idleMode = wxIDLE_PROCESS_ALL; - -// Can we send an idle event? -bool wxIdleEvent::CanSend(wxWindow* win) -{ - // Don't update if we've switched global updating off - // and this window doesn't support updates. - if (win && - (GetMode() == wxIDLE_PROCESS_SPECIFIED && - ((win->GetExtraStyle() & wxWS_EX_PROCESS_IDLE) == 0))) - return false; - - return true; -} - -/* - * Scroll events - */ - -wxScrollEvent::wxScrollEvent(wxEventType commandType, - int id, - int pos, - int orient) - : wxCommandEvent(commandType, id) -{ - m_extraLong = orient; - m_commandInt = pos; -} - -/* - * ScrollWin events - */ - -wxScrollWinEvent::wxScrollWinEvent(wxEventType commandType, - int pos, - int orient) -{ - m_eventType = commandType; - m_extraLong = orient; - m_commandInt = pos; -} - -/* - * Mouse events - * - */ - -wxMouseEvent::wxMouseEvent(wxEventType commandType) -{ - m_eventType = commandType; - m_metaDown = false; - m_altDown = false; - m_controlDown = false; - m_shiftDown = false; - m_leftDown = false; - m_rightDown = false; - m_middleDown = false; - m_x = 0; - m_y = 0; - m_wheelRotation = 0; - m_wheelDelta = 0; - m_linesPerAction = 0; -} - -void wxMouseEvent::Assign(const wxMouseEvent& event) -{ - m_eventType = event.m_eventType; - - m_x = event.m_x; - m_y = event.m_y; - - m_leftDown = event.m_leftDown; - m_middleDown = event.m_middleDown; - m_rightDown = event.m_rightDown; - - m_controlDown = event.m_controlDown; - m_shiftDown = event.m_shiftDown; - m_altDown = event.m_altDown; - m_metaDown = event.m_metaDown; - - m_wheelRotation = event.m_wheelRotation; - m_wheelDelta = event.m_wheelDelta; - m_linesPerAction = event.m_linesPerAction; -} - -// return true if was a button dclick event -bool wxMouseEvent::ButtonDClick(int but) const -{ - switch (but) - { - default: - wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonDClick")); - // fall through - - case wxMOUSE_BTN_ANY: - return (LeftDClick() || MiddleDClick() || RightDClick()); - - case wxMOUSE_BTN_LEFT: - return LeftDClick(); - - case wxMOUSE_BTN_MIDDLE: - return MiddleDClick(); - - case wxMOUSE_BTN_RIGHT: - return RightDClick(); - } -} - -// return true if was a button down event -bool wxMouseEvent::ButtonDown(int but) const -{ - switch (but) - { - default: - wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonDown")); - // fall through - - case wxMOUSE_BTN_ANY: - return (LeftDown() || MiddleDown() || RightDown()); - - case wxMOUSE_BTN_LEFT: - return LeftDown(); - - case wxMOUSE_BTN_MIDDLE: - return MiddleDown(); - - case wxMOUSE_BTN_RIGHT: - return RightDown(); - } -} - -// return true if was a button up event -bool wxMouseEvent::ButtonUp(int but) const -{ - switch (but) - { - default: - wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonUp")); - // fall through - - case wxMOUSE_BTN_ANY: - return (LeftUp() || MiddleUp() || RightUp()); - - case wxMOUSE_BTN_LEFT: - return LeftUp(); - - case wxMOUSE_BTN_MIDDLE: - return MiddleUp(); - - case wxMOUSE_BTN_RIGHT: - return RightUp(); - } -} - -// return true if the given button is currently changing state -bool wxMouseEvent::Button(int but) const -{ - switch (but) - { - default: - wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::Button")); - // fall through - - case wxMOUSE_BTN_ANY: - return ButtonUp(wxMOUSE_BTN_ANY) || - ButtonDown(wxMOUSE_BTN_ANY) || - ButtonDClick(wxMOUSE_BTN_ANY); - - case wxMOUSE_BTN_LEFT: - return LeftDown() || LeftUp() || LeftDClick(); - - case wxMOUSE_BTN_MIDDLE: - return MiddleDown() || MiddleUp() || MiddleDClick(); - - case wxMOUSE_BTN_RIGHT: - return RightDown() || RightUp() || RightDClick(); - } -} - -bool wxMouseEvent::ButtonIsDown(int but) const -{ - switch (but) - { - default: - wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonIsDown")); - // fall through - - case wxMOUSE_BTN_ANY: - return LeftIsDown() || MiddleIsDown() || RightIsDown(); - - case wxMOUSE_BTN_LEFT: - return LeftIsDown(); - - case wxMOUSE_BTN_MIDDLE: - return MiddleIsDown(); - - case wxMOUSE_BTN_RIGHT: - return RightIsDown(); - } -} - -int wxMouseEvent::GetButton() const -{ - for ( int i = 1; i <= 3; i++ ) - { - if ( Button(i) ) - { - return i; - } - } - - return wxMOUSE_BTN_NONE; -} - -// Find the logical position of the event given the DC -wxPoint wxMouseEvent::GetLogicalPosition(const wxDC& dc) const -{ - wxPoint pt(dc.DeviceToLogicalX(m_x), dc.DeviceToLogicalY(m_y)); - return pt; -} - - -/* - * Keyboard event - * - */ - -wxKeyEvent::wxKeyEvent(wxEventType type) -{ - m_eventType = type; - m_shiftDown = false; - m_controlDown = false; - m_metaDown = false; - m_altDown = false; - m_keyCode = 0; - m_scanCode = 0; -#if wxUSE_UNICODE - m_uniChar = 0; -#endif -} - -wxKeyEvent::wxKeyEvent(const wxKeyEvent& evt) - : wxEvent(evt) -{ - m_x = evt.m_x; - m_y = evt.m_y; - - m_keyCode = evt.m_keyCode; - - m_controlDown = evt.m_controlDown; - m_shiftDown = evt.m_shiftDown; - m_altDown = evt.m_altDown; - m_metaDown = evt.m_metaDown; - m_scanCode = evt.m_scanCode; - m_rawCode = evt.m_rawCode; - m_rawFlags = evt.m_rawFlags; - -#if wxUSE_UNICODE - m_uniChar = evt.m_uniChar; -#endif -} - -#if WXWIN_COMPATIBILITY_2_6 -long wxKeyEvent::KeyCode() const -{ - return m_keyCode; -} -#endif // WXWIN_COMPATIBILITY_2_6 - -wxWindowCreateEvent::wxWindowCreateEvent(wxWindow *win) -{ - SetEventType(wxEVT_CREATE); - SetEventObject(win); -} - -wxWindowDestroyEvent::wxWindowDestroyEvent(wxWindow *win) -{ - SetEventType(wxEVT_DESTROY); - SetEventObject(win); -} - -wxChildFocusEvent::wxChildFocusEvent(wxWindow *win) - : wxCommandEvent(wxEVT_CHILD_FOCUS) -{ - SetEventObject(win); -} - -// ---------------------------------------------------------------------------- -// wxHelpEvent -// ---------------------------------------------------------------------------- - -/* static */ -wxHelpEvent::Origin wxHelpEvent::GuessOrigin(Origin origin) -{ - if ( origin == Origin_Unknown ) - { - // assume that the event comes from the help button if it's not from - // keyboard and that pressing F1 always results in the help event - origin = wxGetKeyState(WXK_F1) ? Origin_Keyboard : Origin_HelpButton; - } - - return origin; -} - -#endif // wxUSE_GUI - - -#if wxUSE_BASE - -// ---------------------------------------------------------------------------- -// wxEventHashTable -// ---------------------------------------------------------------------------- - -static const int EVENT_TYPE_TABLE_INIT_SIZE = 31; // Not too big not too small... - -wxEventHashTable* wxEventHashTable::sm_first = NULL; - -wxEventHashTable::wxEventHashTable(const wxEventTable &table) - : m_table(table), - m_rebuildHash(true) -{ - AllocEventTypeTable(EVENT_TYPE_TABLE_INIT_SIZE); - - m_next = sm_first; - if (m_next) - m_next->m_previous = this; - sm_first = this; -} - -wxEventHashTable::~wxEventHashTable() -{ - if (m_next) - m_next->m_previous = m_previous; - if (m_previous) - m_previous->m_next = m_next; - if (sm_first == this) - sm_first = m_next; - - Clear(); -} - -void wxEventHashTable::Clear() -{ - size_t i; - for(i = 0; i < m_size; i++) - { - EventTypeTablePointer eTTnode = m_eventTypeTable[i]; - if (eTTnode) - { - delete eTTnode; - } - } - - // Necessary in order to not invoke the - // overloaded delete operator when statics are cleaned up - if (m_eventTypeTable) - delete[] m_eventTypeTable; - - m_eventTypeTable = NULL; - m_size = 0; -} - -// Clear all tables -void wxEventHashTable::ClearAll() -{ - wxEventHashTable* table = sm_first; - while (table) - { - table->Clear(); - table = table->m_next; - } -} - -// Rebuild all tables if they were cleared by ClearAll -void wxEventHashTable::ReconstructAll() -{ - wxEventHashTable* table = sm_first; - while (table) - { - // This will only be true if the event table was cleared. - // What we do here is basically what the constructor does. - if(table->m_eventTypeTable == NULL) - { - table->AllocEventTypeTable(EVENT_TYPE_TABLE_INIT_SIZE); - table->m_rebuildHash = true; - } - table = table->m_next; - } -} - -bool wxEventHashTable::HandleEvent(wxEvent &event, wxEvtHandler *self) -{ - if (m_rebuildHash) - { - InitHashTable(); - m_rebuildHash = false; - } - - if (!m_eventTypeTable) - return false; - - // Find all entries for the given event type. - wxEventType eventType = event.GetEventType(); - const EventTypeTablePointer eTTnode = m_eventTypeTable[eventType % m_size]; - if (eTTnode && eTTnode->eventType == eventType) - { - // Now start the search for an event handler - // that can handle an event with the given ID. - const wxEventTableEntryPointerArray& - eventEntryTable = eTTnode->eventEntryTable; - - const size_t count = eventEntryTable.GetCount(); - for (size_t n = 0; n < count; n++) - { - if ( wxEvtHandler:: - ProcessEventIfMatches(*eventEntryTable[n], self, event) ) - { - return true; - } - } - } - - return false; -} - -void wxEventHashTable::InitHashTable() -{ - // Loop over the event tables and all its base tables. - const wxEventTable *table = &m_table; - while (table) - { - // Retrieve all valid event handler entries - const wxEventTableEntry *entry = table->entries; - while (entry->m_fn != 0) - { - // Add the event entry in the Hash. - AddEntry(*entry); - - entry++; - } - - table = table->baseTable; - } - - // Lets free some memory. - size_t i; - for(i = 0; i < m_size; i++) - { - EventTypeTablePointer eTTnode = m_eventTypeTable[i]; - if (eTTnode) - { - eTTnode->eventEntryTable.Shrink(); - } - } -} - -void wxEventHashTable::AddEntry(const wxEventTableEntry &entry) -{ - // This might happen 'accidentally' as the app is exiting - if (!m_eventTypeTable) - return; - - EventTypeTablePointer *peTTnode = &m_eventTypeTable[entry.m_eventType % m_size]; - EventTypeTablePointer eTTnode = *peTTnode; - - if (eTTnode) - { - if (eTTnode->eventType != entry.m_eventType) - { - // Resize the table! - GrowEventTypeTable(); - // Try again to add it. - AddEntry(entry); - return; - } - } - else - { - eTTnode = new EventTypeTable; - eTTnode->eventType = entry.m_eventType; - *peTTnode = eTTnode; - } - - // Fill all hash entries between entry.m_id and entry.m_lastId... - eTTnode->eventEntryTable.Add(&entry); -} - -void wxEventHashTable::AllocEventTypeTable(size_t size) -{ - m_eventTypeTable = new EventTypeTablePointer[size]; - memset((void *)m_eventTypeTable, 0, sizeof(EventTypeTablePointer)*size); - m_size = size; -} - -void wxEventHashTable::GrowEventTypeTable() -{ - size_t oldSize = m_size; - EventTypeTablePointer *oldEventTypeTable = m_eventTypeTable; - - // TODO: Search the most optimal grow sequence - AllocEventTypeTable(/* GetNextPrime(oldSize) */oldSize*2+1); - - for ( size_t i = 0; i < oldSize; /* */ ) - { - EventTypeTablePointer eTToldNode = oldEventTypeTable[i]; - if (eTToldNode) - { - EventTypeTablePointer *peTTnode = &m_eventTypeTable[eTToldNode->eventType % m_size]; - EventTypeTablePointer eTTnode = *peTTnode; - - // Check for collision, we don't want any. - if (eTTnode) - { - GrowEventTypeTable(); - continue; // Don't increment the counter, - // as we still need to add this element. - } - else - { - // Get the old value and put it in the new table. - *peTTnode = oldEventTypeTable[i]; - } - } - - i++; - } - - delete[] oldEventTypeTable; -} - - -// ---------------------------------------------------------------------------- -// wxEvtHandler -// ---------------------------------------------------------------------------- - -/* - * Event handler - */ - -wxEvtHandler::wxEvtHandler() -{ - m_nextHandler = (wxEvtHandler *) NULL; - m_previousHandler = (wxEvtHandler *) NULL; - m_enabled = true; - m_dynamicEvents = (wxList *) NULL; - m_pendingEvents = (wxList *) NULL; -#if wxUSE_THREADS -# if !defined(__VISAGECPP__) - m_eventsLocker = new wxCriticalSection; -# endif -#endif - - // no client data (yet) - m_clientData = NULL; - m_clientDataType = wxClientData_None; -} - -wxEvtHandler::~wxEvtHandler() -{ - // Takes itself out of the list of handlers - if (m_previousHandler) - m_previousHandler->m_nextHandler = m_nextHandler; - - if (m_nextHandler) - m_nextHandler->m_previousHandler = m_previousHandler; - - if (m_dynamicEvents) - { - for ( wxList::iterator it = m_dynamicEvents->begin(), - end = m_dynamicEvents->end(); - it != end; - ++it ) - { -#if WXWIN_COMPATIBILITY_EVENT_TYPES - wxEventTableEntry *entry = (wxEventTableEntry*)*it; -#else // !WXWIN_COMPATIBILITY_EVENT_TYPES - wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)*it; -#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES - - if (entry->m_callbackUserData) - delete entry->m_callbackUserData; - delete entry; - } - delete m_dynamicEvents; - }; - - if (m_pendingEvents) - m_pendingEvents->DeleteContents(true); - delete m_pendingEvents; - -#if wxUSE_THREADS -# if !defined(__VISAGECPP__) - delete m_eventsLocker; -# endif - - // Remove us from wxPendingEvents if necessary. - if(wxPendingEventsLocker) - wxENTER_CRIT_SECT(*wxPendingEventsLocker); -#endif // wxUSE_THREADS - - if ( wxPendingEvents ) - { - // Delete all occurences of this from the list of pending events - while (wxPendingEvents->DeleteObject(this)) { } // Do nothing - } - -#if wxUSE_THREADS - if(wxPendingEventsLocker) - wxLEAVE_CRIT_SECT(*wxPendingEventsLocker); -#endif // wxUSE_THREADS - - // we only delete object data, not untyped - if ( m_clientDataType == wxClientData_Object ) - delete m_clientObject; -} - -#if wxUSE_THREADS - -bool wxEvtHandler::ProcessThreadEvent(wxEvent& event) -{ - // check that we are really in a child thread - wxASSERT_MSG( !wxThread::IsMain(), - wxT("use ProcessEvent() in main thread") ); - - AddPendingEvent(event); - - return true; -} - -void wxEvtHandler::ClearEventLocker() -{ -#if !defined(__VISAGECPP__) - delete m_eventsLocker; - m_eventsLocker = NULL; -#endif -} - -#endif // wxUSE_THREADS - -void wxEvtHandler::AddPendingEvent(wxEvent& event) -{ - // 1) Add event to list of pending events of this event handler - - wxEvent *eventCopy = event.Clone(); - - // we must be able to copy the events here so the event class must - // implement Clone() properly instead of just providing a NULL stab for it - wxCHECK_RET( eventCopy, - _T("events of this type aren't supposed to be posted") ); - - wxENTER_CRIT_SECT( Lock() ); - - if ( !m_pendingEvents ) - m_pendingEvents = new wxList; - - m_pendingEvents->Append(eventCopy); - - // 2) Add this event handler to list of event handlers that - // have pending events. - - wxENTER_CRIT_SECT(*wxPendingEventsLocker); - - if ( !wxPendingEvents ) - wxPendingEvents = new wxList; - wxPendingEvents->Append(this); - - wxLEAVE_CRIT_SECT(*wxPendingEventsLocker); - - wxLEAVE_CRIT_SECT( Lock() ); - - // 3) Inform the system that new pending events are somewhere, - // and that these should be processed in idle time. - wxWakeUpIdle(); -} - -void wxEvtHandler::ProcessPendingEvents() -{ - // this method is only called by wxApp if this handler does have - // pending events - wxCHECK_RET( m_pendingEvents, - wxT("Please call wxApp::ProcessPendingEvents() instead") ); - - wxENTER_CRIT_SECT( Lock() ); - - // we leave the loop once we have processed all events that were present at - // the start of ProcessPendingEvents because otherwise we could get into - // infinite loop if the pending event handler execution resulted in another - // event being posted - size_t n = m_pendingEvents->size(); - for ( wxList::compatibility_iterator node = m_pendingEvents->GetFirst(); - node; - node = m_pendingEvents->GetFirst() ) - { - { - wxEventPtr event(wx_static_cast(wxEvent *, node->GetData())); - - // It's important we remove event from list before processing it. - // Else a nested event loop, for example from a modal dialog, might - // process the same event again. - - m_pendingEvents->Erase(node); - - wxLEAVE_CRIT_SECT( Lock() ); - - ProcessEvent(*event); - } // delete the event at this block exit, before re-locking our - // critical section, to avoid deadlocks if the event dtor locks - // something else itself (see #10790) - - wxENTER_CRIT_SECT( Lock() ); - - if ( --n == 0 ) - break; - } - - wxLEAVE_CRIT_SECT( Lock() ); -} - -/* - * Event table stuff - */ -/* static */ bool -wxEvtHandler::ProcessEventIfMatches(const wxEventTableEntryBase& entry, - wxEvtHandler *handler, - wxEvent& event) -{ - int tableId1 = entry.m_id, - tableId2 = entry.m_lastId; - - // match only if the event type is the same and the id is either -1 in - // the event table (meaning "any") or the event id matches the id - // specified in the event table either exactly or by falling into - // range between first and last - if ((tableId1 == wxID_ANY) || - (tableId2 == wxID_ANY && tableId1 == event.GetId()) || - (tableId2 != wxID_ANY && - (event.GetId() >= tableId1 && event.GetId() <= tableId2))) - { - event.Skip(false); - event.m_callbackUserData = entry.m_callbackUserData; - -#if wxUSE_EXCEPTIONS - if ( wxTheApp ) - { - // call the handler via wxApp method which allows the user to catch - // any exceptions which may be thrown by any handler in the program - // in one place - wxTheApp->HandleEvent(handler, (wxEventFunction)entry.m_fn, event); - } - else -#endif // wxUSE_EXCEPTIONS - { - // no need for an extra virtual function call - (handler->*((wxEventFunction) (entry.m_fn)))(event); - } - - if (!event.GetSkipped()) - return true; - } - - return false; -} - -bool wxEvtHandler::TryParent(wxEvent& event) -{ - if ( wxTheApp && (this != wxTheApp) ) - { - // Special case: don't pass wxEVT_IDLE to wxApp, since it'll always - // swallow it. wxEVT_IDLE is sent explicitly to wxApp so it will be - // processed appropriately via SearchEventTable. - if ( event.GetEventType() != wxEVT_IDLE ) - { - if ( wxTheApp->ProcessEvent(event) ) - return true; - } - } - - return false; -} - -bool wxEvtHandler::ProcessEvent(wxEvent& event) -{ - // allow the application to hook into event processing - if ( wxTheApp ) - { - int rc = wxTheApp->FilterEvent(event); - if ( rc != -1 ) - { - wxASSERT_MSG( rc == 1 || rc == 0, - _T("unexpected wxApp::FilterEvent return value") ); - - return rc != 0; - } - //else: proceed normally - } - - // An event handler can be enabled or disabled - if ( GetEvtHandlerEnabled() ) - { - // if we have a validator, it has higher priority than our own event - // table - if ( TryValidator(event) ) - return true; - - // Handle per-instance dynamic event tables first - if ( m_dynamicEvents && SearchDynamicEventTable(event) ) - return true; - - // Then static per-class event tables - if ( GetEventHashTable().HandleEvent(event, this) ) - return true; - } - - // Try going down the event handler chain - if ( GetNextHandler() ) - { - if ( GetNextHandler()->ProcessEvent(event) ) - return true; - } - - // Finally propagate the event upwards the window chain and/or to the - // application object as necessary - return TryParent(event); -} - - -bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event) -{ - const wxEventType eventType = event.GetEventType(); - for ( int i = 0; table.entries[i].m_fn != 0; i++ ) - { - const wxEventTableEntry& entry = table.entries[i]; - if ( eventType == entry.m_eventType ) - { - if ( ProcessEventIfMatches(entry, this, event) ) - return true; - } - } - - return false; -} - -void wxEvtHandler::Connect( int id, int lastId, - int eventType, - wxObjectEventFunction func, - wxObject *userData, - wxEvtHandler* eventSink ) -{ -#if WXWIN_COMPATIBILITY_EVENT_TYPES - wxEventTableEntry *entry = new wxEventTableEntry; - entry->m_eventType = eventType; - entry->m_id = id; - entry->m_lastId = lastId; - entry->m_fn = func; - entry->m_callbackUserData = userData; -#else // !WXWIN_COMPATIBILITY_EVENT_TYPES - wxDynamicEventTableEntry *entry = - new wxDynamicEventTableEntry(eventType, id, lastId, func, userData, eventSink); -#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES - - if (!m_dynamicEvents) - m_dynamicEvents = new wxList; - - // Insert at the front of the list so most recent additions are found first - m_dynamicEvents->Insert( (wxObject*) entry ); -} - -bool wxEvtHandler::Disconnect( int id, int lastId, wxEventType eventType, - wxObjectEventFunction func, - wxObject *userData, - wxEvtHandler* eventSink ) -{ - if (!m_dynamicEvents) - return false; - - wxList::compatibility_iterator node = m_dynamicEvents->GetFirst(); - while (node) - { -#if WXWIN_COMPATIBILITY_EVENT_TYPES - wxEventTableEntry *entry = (wxEventTableEntry*)node->GetData(); -#else // !WXWIN_COMPATIBILITY_EVENT_TYPES - wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); -#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES - - if ((entry->m_id == id) && - ((entry->m_lastId == lastId) || (lastId == wxID_ANY)) && - ((entry->m_eventType == eventType) || (eventType == wxEVT_NULL)) && - ((entry->m_fn == func) || (func == (wxObjectEventFunction)NULL)) && - ((entry->m_eventSink == eventSink) || (eventSink == (wxEvtHandler*)NULL)) && - ((entry->m_callbackUserData == userData) || (userData == (wxObject*)NULL))) - { - if (entry->m_callbackUserData) - delete entry->m_callbackUserData; - m_dynamicEvents->Erase( node ); - delete entry; - return true; - } - node = node->GetNext(); - } - return false; -} - -bool wxEvtHandler::SearchDynamicEventTable( wxEvent& event ) -{ - wxCHECK_MSG( m_dynamicEvents, false, - wxT("caller should check that we have dynamic events") ); - - wxList::compatibility_iterator node = m_dynamicEvents->GetFirst(); - while (node) - { -#if WXWIN_COMPATIBILITY_EVENT_TYPES - wxEventTableEntry *entry = (wxEventTableEntry*)node->GetData(); -#else // !WXWIN_COMPATIBILITY_EVENT_TYPES - wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); -#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES - - // get next node before (maybe) calling the event handler as it could - // call Disconnect() invalidating the current node - node = node->GetNext(); - - if ((event.GetEventType() == entry->m_eventType) && (entry->m_fn != 0)) - { - wxEvtHandler *handler = -#if !WXWIN_COMPATIBILITY_EVENT_TYPES - entry->m_eventSink ? entry->m_eventSink - : -#endif - this; - - if ( ProcessEventIfMatches(*entry, handler, event) ) - { - return true; - } - } - } - - return false; -} - -void wxEvtHandler::DoSetClientObject( wxClientData *data ) -{ - wxASSERT_MSG( m_clientDataType != wxClientData_Void, - wxT("can't have both object and void client data") ); - - if ( m_clientObject ) - delete m_clientObject; - - m_clientObject = data; - m_clientDataType = wxClientData_Object; -} - -wxClientData *wxEvtHandler::DoGetClientObject() const -{ - // it's not an error to call GetClientObject() on a window which doesn't - // have client data at all - NULL will be returned - wxASSERT_MSG( m_clientDataType != wxClientData_Void, - wxT("this window doesn't have object client data") ); - - return m_clientObject; -} - -void wxEvtHandler::DoSetClientData( void *data ) -{ - wxASSERT_MSG( m_clientDataType != wxClientData_Object, - wxT("can't have both object and void client data") ); - - m_clientData = data; - m_clientDataType = wxClientData_Void; -} - -void *wxEvtHandler::DoGetClientData() const -{ - // it's not an error to call GetClientData() on a window which doesn't have - // client data at all - NULL will be returned - wxASSERT_MSG( m_clientDataType != wxClientData_Object, - wxT("this window doesn't have void client data") ); - - return m_clientData; -} - -#endif // wxUSE_BASE - -#if wxUSE_GUI - -// Find a window with the focus, that is also a descendant of the given window. -// This is used to determine the window to initially send commands to. -wxWindow* wxFindFocusDescendant(wxWindow* ancestor) -{ - // Process events starting with the window with the focus, if any. - wxWindow* focusWin = wxWindow::FindFocus(); - wxWindow* win = focusWin; - - // Check if this is a descendant of this frame. - // If not, win will be set to NULL. - while (win) - { - if (win == ancestor) - break; - else - win = win->GetParent(); - } - if (win == (wxWindow*) NULL) - focusWin = (wxWindow*) NULL; - - return focusWin; -} - -#endif // wxUSE_GUI +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/event.cpp +// Purpose: Event classes +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id: event.cpp 61982 2009-09-20 21:48:50Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/event.h" + +#ifndef WX_PRECOMP + #include "wx/list.h" + #include "wx/app.h" + #include "wx/utils.h" + #include "wx/stopwatch.h" + #include "wx/module.h" + + #if wxUSE_GUI + #include "wx/window.h" + #include "wx/control.h" + #include "wx/dc.h" + #include "wx/textctrl.h" + #include "wx/validate.h" + #endif // wxUSE_GUI +#endif + +#if wxUSE_BASE + #include "wx/ptr_scpd.h" + + wxDECLARE_SCOPED_PTR(wxEvent, wxEventPtr) + wxDEFINE_SCOPED_PTR(wxEvent, wxEventPtr) +#endif // wxUSE_BASE + +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + +#if wxUSE_BASE + IMPLEMENT_DYNAMIC_CLASS(wxEvtHandler, wxObject) + IMPLEMENT_ABSTRACT_CLASS(wxEvent, wxObject) +#endif // wxUSE_BASE + +#if wxUSE_GUI + IMPLEMENT_DYNAMIC_CLASS(wxIdleEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxCommandEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxNotifyEvent, wxCommandEvent) + IMPLEMENT_DYNAMIC_CLASS(wxScrollEvent, wxCommandEvent) + IMPLEMENT_DYNAMIC_CLASS(wxScrollWinEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxMouseEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxKeyEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxSizeEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxPaintEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxNcPaintEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxEraseEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxMoveEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxFocusEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxChildFocusEvent, wxCommandEvent) + IMPLEMENT_DYNAMIC_CLASS(wxCloseEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxShowEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxMaximizeEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxIconizeEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxMenuEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxJoystickEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxDropFilesEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxActivateEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxInitDialogEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxSetCursorEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxSysColourChangedEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxDisplayChangedEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxUpdateUIEvent, wxCommandEvent) + IMPLEMENT_DYNAMIC_CLASS(wxNavigationKeyEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxPaletteChangedEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxQueryNewPaletteEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxWindowCreateEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxWindowDestroyEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxHelpEvent, wxCommandEvent) + IMPLEMENT_DYNAMIC_CLASS(wxContextMenuEvent, wxCommandEvent) + IMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureChangedEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxMouseCaptureLostEvent, wxEvent) + IMPLEMENT_DYNAMIC_CLASS(wxClipboardTextEvent, wxCommandEvent) +#endif // wxUSE_GUI + +#if wxUSE_BASE + +const wxEventTable *wxEvtHandler::GetEventTable() const + { return &wxEvtHandler::sm_eventTable; } + +const wxEventTable wxEvtHandler::sm_eventTable = + { (const wxEventTable *)NULL, &wxEvtHandler::sm_eventTableEntries[0] }; + +wxEventHashTable &wxEvtHandler::GetEventHashTable() const + { return wxEvtHandler::sm_eventHashTable; } + +wxEventHashTable wxEvtHandler::sm_eventHashTable(wxEvtHandler::sm_eventTable); + +const wxEventTableEntry wxEvtHandler::sm_eventTableEntries[] = + { DECLARE_EVENT_TABLE_ENTRY(wxEVT_NULL, 0, 0, (wxObjectEventFunction)NULL, NULL) }; + + +#ifdef __WXDEBUG__ +// Clear up event hash table contents or we can get problems +// when C++ is cleaning up the static object +class wxEventTableEntryModule: public wxModule +{ +DECLARE_DYNAMIC_CLASS(wxEventTableEntryModule) +public: + wxEventTableEntryModule() {} + bool OnInit() + { + wxEventHashTable::ReconstructAll(); + return true; + } + void OnExit() + { + wxEventHashTable::ClearAll(); + } +}; +IMPLEMENT_DYNAMIC_CLASS(wxEventTableEntryModule, wxModule) +#endif + +// ---------------------------------------------------------------------------- +// global variables +// ---------------------------------------------------------------------------- + +// To put pending event handlers +wxList *wxPendingEvents = (wxList *)NULL; + +#if wxUSE_THREADS + // protects wxPendingEvents list + wxCriticalSection *wxPendingEventsLocker = (wxCriticalSection *)NULL; +#endif + +#if !WXWIN_COMPATIBILITY_EVENT_TYPES + +// common event types are defined here, other event types are defined by the +// components which use them + +const wxEventType wxEVT_FIRST = 10000; +const wxEventType wxEVT_USER_FIRST = wxEVT_FIRST + 2000; + +DEFINE_EVENT_TYPE(wxEVT_NULL) +DEFINE_EVENT_TYPE(wxEVT_IDLE) +DEFINE_EVENT_TYPE(wxEVT_SOCKET) + +#endif // !WXWIN_COMPATIBILITY_EVENT_TYPES + +#endif // wxUSE_BASE + +#if wxUSE_GUI + +#if !WXWIN_COMPATIBILITY_EVENT_TYPES + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_BUTTON_CLICKED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_CHECKBOX_CLICKED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_CHOICE_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LISTBOX_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LISTBOX_DOUBLECLICKED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_CHECKLISTBOX_TOGGLED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_MENU_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SLIDER_UPDATED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_RADIOBOX_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_RADIOBUTTON_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SCROLLBAR_UPDATED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_VLBOX_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_COMBOBOX_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOOL_RCLICKED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TOOL_ENTER) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SPINCTRL_UPDATED) + +// Sockets and timers send events, too +DEFINE_EVENT_TYPE(wxEVT_TIMER) + +// Mouse event types +DEFINE_EVENT_TYPE(wxEVT_LEFT_DOWN) +DEFINE_EVENT_TYPE(wxEVT_LEFT_UP) +DEFINE_EVENT_TYPE(wxEVT_MIDDLE_DOWN) +DEFINE_EVENT_TYPE(wxEVT_MIDDLE_UP) +DEFINE_EVENT_TYPE(wxEVT_RIGHT_DOWN) +DEFINE_EVENT_TYPE(wxEVT_RIGHT_UP) +DEFINE_EVENT_TYPE(wxEVT_MOTION) +DEFINE_EVENT_TYPE(wxEVT_ENTER_WINDOW) +DEFINE_EVENT_TYPE(wxEVT_LEAVE_WINDOW) +DEFINE_EVENT_TYPE(wxEVT_LEFT_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_MIDDLE_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_RIGHT_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_SET_FOCUS) +DEFINE_EVENT_TYPE(wxEVT_KILL_FOCUS) +DEFINE_EVENT_TYPE(wxEVT_CHILD_FOCUS) +DEFINE_EVENT_TYPE(wxEVT_MOUSEWHEEL) + +// Non-client mouse events +DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_DOWN) +DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_UP) +DEFINE_EVENT_TYPE(wxEVT_NC_MIDDLE_DOWN) +DEFINE_EVENT_TYPE(wxEVT_NC_MIDDLE_UP) +DEFINE_EVENT_TYPE(wxEVT_NC_RIGHT_DOWN) +DEFINE_EVENT_TYPE(wxEVT_NC_RIGHT_UP) +DEFINE_EVENT_TYPE(wxEVT_NC_MOTION) +DEFINE_EVENT_TYPE(wxEVT_NC_ENTER_WINDOW) +DEFINE_EVENT_TYPE(wxEVT_NC_LEAVE_WINDOW) +DEFINE_EVENT_TYPE(wxEVT_NC_LEFT_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_NC_MIDDLE_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_NC_RIGHT_DCLICK) + +// Character input event type +DEFINE_EVENT_TYPE(wxEVT_CHAR) +DEFINE_EVENT_TYPE(wxEVT_CHAR_HOOK) +DEFINE_EVENT_TYPE(wxEVT_NAVIGATION_KEY) +DEFINE_EVENT_TYPE(wxEVT_KEY_DOWN) +DEFINE_EVENT_TYPE(wxEVT_KEY_UP) +#if wxUSE_HOTKEY +DEFINE_EVENT_TYPE(wxEVT_HOTKEY) +#endif + +// Set cursor event +DEFINE_EVENT_TYPE(wxEVT_SET_CURSOR) + +// wxScrollbar and wxSlider event identifiers +DEFINE_EVENT_TYPE(wxEVT_SCROLL_TOP) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_BOTTOM) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_LINEUP) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_LINEDOWN) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_PAGEUP) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_PAGEDOWN) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_THUMBTRACK) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_THUMBRELEASE) +DEFINE_EVENT_TYPE(wxEVT_SCROLL_CHANGED) + +// Scroll events from wxWindow +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_TOP) +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_BOTTOM) +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_LINEUP) +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_LINEDOWN) +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_PAGEUP) +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_PAGEDOWN) +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_THUMBTRACK) +DEFINE_EVENT_TYPE(wxEVT_SCROLLWIN_THUMBRELEASE) + +// System events +DEFINE_EVENT_TYPE(wxEVT_SIZE) +DEFINE_EVENT_TYPE(wxEVT_SIZING) +DEFINE_EVENT_TYPE(wxEVT_MOVE) +DEFINE_EVENT_TYPE(wxEVT_MOVING) +DEFINE_EVENT_TYPE(wxEVT_CLOSE_WINDOW) +DEFINE_EVENT_TYPE(wxEVT_END_SESSION) +DEFINE_EVENT_TYPE(wxEVT_QUERY_END_SESSION) +DEFINE_EVENT_TYPE(wxEVT_HIBERNATE) +DEFINE_EVENT_TYPE(wxEVT_ACTIVATE_APP) +DEFINE_EVENT_TYPE(wxEVT_POWER) +DEFINE_EVENT_TYPE(wxEVT_ACTIVATE) +DEFINE_EVENT_TYPE(wxEVT_CREATE) +DEFINE_EVENT_TYPE(wxEVT_DESTROY) +DEFINE_EVENT_TYPE(wxEVT_SHOW) +DEFINE_EVENT_TYPE(wxEVT_ICONIZE) +DEFINE_EVENT_TYPE(wxEVT_MAXIMIZE) +DEFINE_EVENT_TYPE(wxEVT_MOUSE_CAPTURE_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_MOUSE_CAPTURE_LOST) +DEFINE_EVENT_TYPE(wxEVT_PAINT) +DEFINE_EVENT_TYPE(wxEVT_ERASE_BACKGROUND) +DEFINE_EVENT_TYPE(wxEVT_NC_PAINT) +DEFINE_EVENT_TYPE(wxEVT_PAINT_ICON) +DEFINE_EVENT_TYPE(wxEVT_MENU_OPEN) +DEFINE_EVENT_TYPE(wxEVT_MENU_CLOSE) +DEFINE_EVENT_TYPE(wxEVT_MENU_HIGHLIGHT) +DEFINE_EVENT_TYPE(wxEVT_CONTEXT_MENU) +DEFINE_EVENT_TYPE(wxEVT_SYS_COLOUR_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_DISPLAY_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_SETTING_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_QUERY_NEW_PALETTE) +DEFINE_EVENT_TYPE(wxEVT_PALETTE_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_JOY_BUTTON_DOWN) +DEFINE_EVENT_TYPE(wxEVT_JOY_BUTTON_UP) +DEFINE_EVENT_TYPE(wxEVT_JOY_MOVE) +DEFINE_EVENT_TYPE(wxEVT_JOY_ZMOVE) +DEFINE_EVENT_TYPE(wxEVT_DROP_FILES) +DEFINE_EVENT_TYPE(wxEVT_DRAW_ITEM) +DEFINE_EVENT_TYPE(wxEVT_MEASURE_ITEM) +DEFINE_EVENT_TYPE(wxEVT_COMPARE_ITEM) +DEFINE_EVENT_TYPE(wxEVT_INIT_DIALOG) +DEFINE_EVENT_TYPE(wxEVT_UPDATE_UI) + +// Clipboard events +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_COPY) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_CUT) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_PASTE) + +// Generic command events +// Note: a click is a higher-level event than button down/up +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LEFT_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LEFT_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_RIGHT_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_RIGHT_DCLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SET_FOCUS) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_KILL_FOCUS) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_ENTER) + +// Help events +DEFINE_EVENT_TYPE(wxEVT_HELP) +DEFINE_EVENT_TYPE(wxEVT_DETAILED_HELP) + +#endif // !WXWIN_COMPATIBILITY_EVENT_TYPES + +#endif // wxUSE_GUI + +#if wxUSE_BASE + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// event initialization +// ---------------------------------------------------------------------------- + +int wxNewEventType() +{ + // MT-FIXME + static int s_lastUsedEventType = wxEVT_FIRST; + + return s_lastUsedEventType++; +} + +// ---------------------------------------------------------------------------- +// wxEvent +// ---------------------------------------------------------------------------- + +/* + * General wxWidgets events, covering + * all interesting things that might happen (button clicking, resizing, + * setting text in widgets, etc.). + * + * For each completely new event type, derive a new event class. + * + */ + +wxEvent::wxEvent(int theId, wxEventType commandType ) +{ + m_eventType = commandType; + m_eventObject = (wxObject *) NULL; + m_timeStamp = 0; + m_id = theId; + m_skipped = false; + m_callbackUserData = (wxObject *) NULL; + m_isCommandEvent = false; + m_propagationLevel = wxEVENT_PROPAGATE_NONE; +} + +wxEvent::wxEvent(const wxEvent &src) + : wxObject(src) + , m_eventObject(src.m_eventObject) + , m_eventType(src.m_eventType) + , m_timeStamp(src.m_timeStamp) + , m_id(src.m_id) + , m_callbackUserData(src.m_callbackUserData) + , m_propagationLevel(src.m_propagationLevel) + , m_skipped(src.m_skipped) + , m_isCommandEvent(src.m_isCommandEvent) +{ +} + +#endif // wxUSE_BASE + +#if wxUSE_GUI + +/* + * Command events + * + */ + +#ifdef __VISUALC__ + // 'this' : used in base member initializer list (for m_commandString) + #pragma warning(disable:4355) +#endif + +wxCommandEvent::wxCommandEvent(wxEventType commandType, int theId) + : wxEvent(theId, commandType) +#if WXWIN_COMPATIBILITY_2_4 + , m_commandString(this) +#endif +{ + m_clientData = (char *) NULL; + m_clientObject = (wxClientData *) NULL; + m_extraLong = 0; + m_commandInt = 0; + m_isCommandEvent = true; + + // the command events are propagated upwards by default + m_propagationLevel = wxEVENT_PROPAGATE_MAX; +} + +#ifdef __VISUALC__ + #pragma warning(default:4355) +#endif + +wxString wxCommandEvent::GetString() const +{ + if(m_eventType != wxEVT_COMMAND_TEXT_UPDATED || !m_eventObject) + return m_cmdString; + else + { +#if wxUSE_TEXTCTRL + wxTextCtrl *txt = wxDynamicCast(m_eventObject, wxTextCtrl); + if(txt) + return txt->GetValue(); + else +#endif // wxUSE_TEXTCTRL + return m_cmdString; + } +} + +/* + * UI update events + */ + +#if wxUSE_LONGLONG +wxLongLong wxUpdateUIEvent::sm_lastUpdate = 0; +#endif + +long wxUpdateUIEvent::sm_updateInterval = 0; + +wxUpdateUIMode wxUpdateUIEvent::sm_updateMode = wxUPDATE_UI_PROCESS_ALL; + +// Can we update? +bool wxUpdateUIEvent::CanUpdate(wxWindowBase *win) +{ + // Don't update if we've switched global updating off + // and this window doesn't support updates. + if (win && + (GetMode() == wxUPDATE_UI_PROCESS_SPECIFIED && + ((win->GetExtraStyle() & wxWS_EX_PROCESS_UI_UPDATES) == 0))) + return false; + + if (sm_updateInterval == -1) + return false; + + if (sm_updateInterval == 0) + return true; + +#if wxUSE_STOPWATCH && wxUSE_LONGLONG + wxLongLong now = wxGetLocalTimeMillis(); + if (now > (sm_lastUpdate + sm_updateInterval)) + { + return true; + } + + return false; +#else + // If we don't have wxStopWatch or wxLongLong, we + // should err on the safe side and update now anyway. + return true; +#endif +} + +// Reset the update time to provide a delay until the next +// time we should update +void wxUpdateUIEvent::ResetUpdateTime() +{ +#if wxUSE_STOPWATCH && wxUSE_LONGLONG + if (sm_updateInterval > 0) + { + wxLongLong now = wxGetLocalTimeMillis(); + if (now > (sm_lastUpdate + sm_updateInterval)) + { + sm_lastUpdate = now; + } + } +#endif +} + +/* + * Idle events + */ + +wxIdleMode wxIdleEvent::sm_idleMode = wxIDLE_PROCESS_ALL; + +// Can we send an idle event? +bool wxIdleEvent::CanSend(wxWindow* win) +{ + // Don't update if we've switched global updating off + // and this window doesn't support updates. + if (win && + (GetMode() == wxIDLE_PROCESS_SPECIFIED && + ((win->GetExtraStyle() & wxWS_EX_PROCESS_IDLE) == 0))) + return false; + + return true; +} + +/* + * Scroll events + */ + +wxScrollEvent::wxScrollEvent(wxEventType commandType, + int id, + int pos, + int orient) + : wxCommandEvent(commandType, id) +{ + m_extraLong = orient; + m_commandInt = pos; +} + +/* + * ScrollWin events + */ + +wxScrollWinEvent::wxScrollWinEvent(wxEventType commandType, + int pos, + int orient) +{ + m_eventType = commandType; + m_extraLong = orient; + m_commandInt = pos; +} + +/* + * Mouse events + * + */ + +wxMouseEvent::wxMouseEvent(wxEventType commandType) +{ + m_eventType = commandType; + m_metaDown = false; + m_altDown = false; + m_controlDown = false; + m_shiftDown = false; + m_leftDown = false; + m_rightDown = false; + m_middleDown = false; + m_x = 0; + m_y = 0; + m_wheelRotation = 0; + m_wheelDelta = 0; + m_linesPerAction = 0; +} + +void wxMouseEvent::Assign(const wxMouseEvent& event) +{ + m_eventType = event.m_eventType; + + m_x = event.m_x; + m_y = event.m_y; + + m_leftDown = event.m_leftDown; + m_middleDown = event.m_middleDown; + m_rightDown = event.m_rightDown; + + m_controlDown = event.m_controlDown; + m_shiftDown = event.m_shiftDown; + m_altDown = event.m_altDown; + m_metaDown = event.m_metaDown; + + m_wheelRotation = event.m_wheelRotation; + m_wheelDelta = event.m_wheelDelta; + m_linesPerAction = event.m_linesPerAction; +} + +// return true if was a button dclick event +bool wxMouseEvent::ButtonDClick(int but) const +{ + switch (but) + { + default: + wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonDClick")); + // fall through + + case wxMOUSE_BTN_ANY: + return (LeftDClick() || MiddleDClick() || RightDClick()); + + case wxMOUSE_BTN_LEFT: + return LeftDClick(); + + case wxMOUSE_BTN_MIDDLE: + return MiddleDClick(); + + case wxMOUSE_BTN_RIGHT: + return RightDClick(); + } +} + +// return true if was a button down event +bool wxMouseEvent::ButtonDown(int but) const +{ + switch (but) + { + default: + wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonDown")); + // fall through + + case wxMOUSE_BTN_ANY: + return (LeftDown() || MiddleDown() || RightDown()); + + case wxMOUSE_BTN_LEFT: + return LeftDown(); + + case wxMOUSE_BTN_MIDDLE: + return MiddleDown(); + + case wxMOUSE_BTN_RIGHT: + return RightDown(); + } +} + +// return true if was a button up event +bool wxMouseEvent::ButtonUp(int but) const +{ + switch (but) + { + default: + wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonUp")); + // fall through + + case wxMOUSE_BTN_ANY: + return (LeftUp() || MiddleUp() || RightUp()); + + case wxMOUSE_BTN_LEFT: + return LeftUp(); + + case wxMOUSE_BTN_MIDDLE: + return MiddleUp(); + + case wxMOUSE_BTN_RIGHT: + return RightUp(); + } +} + +// return true if the given button is currently changing state +bool wxMouseEvent::Button(int but) const +{ + switch (but) + { + default: + wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::Button")); + // fall through + + case wxMOUSE_BTN_ANY: + return ButtonUp(wxMOUSE_BTN_ANY) || + ButtonDown(wxMOUSE_BTN_ANY) || + ButtonDClick(wxMOUSE_BTN_ANY); + + case wxMOUSE_BTN_LEFT: + return LeftDown() || LeftUp() || LeftDClick(); + + case wxMOUSE_BTN_MIDDLE: + return MiddleDown() || MiddleUp() || MiddleDClick(); + + case wxMOUSE_BTN_RIGHT: + return RightDown() || RightUp() || RightDClick(); + } +} + +bool wxMouseEvent::ButtonIsDown(int but) const +{ + switch (but) + { + default: + wxFAIL_MSG(wxT("invalid parameter in wxMouseEvent::ButtonIsDown")); + // fall through + + case wxMOUSE_BTN_ANY: + return LeftIsDown() || MiddleIsDown() || RightIsDown(); + + case wxMOUSE_BTN_LEFT: + return LeftIsDown(); + + case wxMOUSE_BTN_MIDDLE: + return MiddleIsDown(); + + case wxMOUSE_BTN_RIGHT: + return RightIsDown(); + } +} + +int wxMouseEvent::GetButton() const +{ + for ( int i = 1; i <= 3; i++ ) + { + if ( Button(i) ) + { + return i; + } + } + + return wxMOUSE_BTN_NONE; +} + +// Find the logical position of the event given the DC +wxPoint wxMouseEvent::GetLogicalPosition(const wxDC& dc) const +{ + wxPoint pt(dc.DeviceToLogicalX(m_x), dc.DeviceToLogicalY(m_y)); + return pt; +} + + +/* + * Keyboard event + * + */ + +wxKeyEvent::wxKeyEvent(wxEventType type) +{ + m_eventType = type; + m_shiftDown = false; + m_controlDown = false; + m_metaDown = false; + m_altDown = false; + m_keyCode = 0; + m_scanCode = 0; +#if wxUSE_UNICODE + m_uniChar = 0; +#endif +} + +wxKeyEvent::wxKeyEvent(const wxKeyEvent& evt) + : wxEvent(evt) +{ + m_x = evt.m_x; + m_y = evt.m_y; + + m_keyCode = evt.m_keyCode; + + m_controlDown = evt.m_controlDown; + m_shiftDown = evt.m_shiftDown; + m_altDown = evt.m_altDown; + m_metaDown = evt.m_metaDown; + m_scanCode = evt.m_scanCode; + m_rawCode = evt.m_rawCode; + m_rawFlags = evt.m_rawFlags; + +#if wxUSE_UNICODE + m_uniChar = evt.m_uniChar; +#endif +} + +#if WXWIN_COMPATIBILITY_2_6 +long wxKeyEvent::KeyCode() const +{ + return m_keyCode; +} +#endif // WXWIN_COMPATIBILITY_2_6 + +wxWindowCreateEvent::wxWindowCreateEvent(wxWindow *win) +{ + SetEventType(wxEVT_CREATE); + SetEventObject(win); +} + +wxWindowDestroyEvent::wxWindowDestroyEvent(wxWindow *win) +{ + SetEventType(wxEVT_DESTROY); + SetEventObject(win); +} + +wxChildFocusEvent::wxChildFocusEvent(wxWindow *win) + : wxCommandEvent(wxEVT_CHILD_FOCUS) +{ + SetEventObject(win); +} + +// ---------------------------------------------------------------------------- +// wxHelpEvent +// ---------------------------------------------------------------------------- + +/* static */ +wxHelpEvent::Origin wxHelpEvent::GuessOrigin(Origin origin) +{ + if ( origin == Origin_Unknown ) + { + // assume that the event comes from the help button if it's not from + // keyboard and that pressing F1 always results in the help event + origin = wxGetKeyState(WXK_F1) ? Origin_Keyboard : Origin_HelpButton; + } + + return origin; +} + +#endif // wxUSE_GUI + + +#if wxUSE_BASE + +// ---------------------------------------------------------------------------- +// wxEventHashTable +// ---------------------------------------------------------------------------- + +static const int EVENT_TYPE_TABLE_INIT_SIZE = 31; // Not too big not too small... + +wxEventHashTable* wxEventHashTable::sm_first = NULL; + +wxEventHashTable::wxEventHashTable(const wxEventTable &table) + : m_table(table), + m_rebuildHash(true) +{ + AllocEventTypeTable(EVENT_TYPE_TABLE_INIT_SIZE); + + m_next = sm_first; + if (m_next) + m_next->m_previous = this; + sm_first = this; +} + +wxEventHashTable::~wxEventHashTable() +{ + if (m_next) + m_next->m_previous = m_previous; + if (m_previous) + m_previous->m_next = m_next; + if (sm_first == this) + sm_first = m_next; + + Clear(); +} + +void wxEventHashTable::Clear() +{ + size_t i; + for(i = 0; i < m_size; i++) + { + EventTypeTablePointer eTTnode = m_eventTypeTable[i]; + if (eTTnode) + { + delete eTTnode; + } + } + + // Necessary in order to not invoke the + // overloaded delete operator when statics are cleaned up + if (m_eventTypeTable) + delete[] m_eventTypeTable; + + m_eventTypeTable = NULL; + m_size = 0; +} + +// Clear all tables +void wxEventHashTable::ClearAll() +{ + wxEventHashTable* table = sm_first; + while (table) + { + table->Clear(); + table = table->m_next; + } +} + +// Rebuild all tables if they were cleared by ClearAll +void wxEventHashTable::ReconstructAll() +{ + wxEventHashTable* table = sm_first; + while (table) + { + // This will only be true if the event table was cleared. + // What we do here is basically what the constructor does. + if(table->m_eventTypeTable == NULL) + { + table->AllocEventTypeTable(EVENT_TYPE_TABLE_INIT_SIZE); + table->m_rebuildHash = true; + } + table = table->m_next; + } +} + +bool wxEventHashTable::HandleEvent(wxEvent &event, wxEvtHandler *self) +{ + if (m_rebuildHash) + { + InitHashTable(); + m_rebuildHash = false; + } + + if (!m_eventTypeTable) + return false; + + // Find all entries for the given event type. + wxEventType eventType = event.GetEventType(); + const EventTypeTablePointer eTTnode = m_eventTypeTable[eventType % m_size]; + if (eTTnode && eTTnode->eventType == eventType) + { + // Now start the search for an event handler + // that can handle an event with the given ID. + const wxEventTableEntryPointerArray& + eventEntryTable = eTTnode->eventEntryTable; + + const size_t count = eventEntryTable.GetCount(); + for (size_t n = 0; n < count; n++) + { + if ( wxEvtHandler:: + ProcessEventIfMatches(*eventEntryTable[n], self, event) ) + { + return true; + } + } + } + + return false; +} + +void wxEventHashTable::InitHashTable() +{ + // Loop over the event tables and all its base tables. + const wxEventTable *table = &m_table; + while (table) + { + // Retrieve all valid event handler entries + const wxEventTableEntry *entry = table->entries; + while (entry->m_fn != 0) + { + // Add the event entry in the Hash. + AddEntry(*entry); + + entry++; + } + + table = table->baseTable; + } + + // Lets free some memory. + size_t i; + for(i = 0; i < m_size; i++) + { + EventTypeTablePointer eTTnode = m_eventTypeTable[i]; + if (eTTnode) + { + eTTnode->eventEntryTable.Shrink(); + } + } +} + +void wxEventHashTable::AddEntry(const wxEventTableEntry &entry) +{ + // This might happen 'accidentally' as the app is exiting + if (!m_eventTypeTable) + return; + + EventTypeTablePointer *peTTnode = &m_eventTypeTable[entry.m_eventType % m_size]; + EventTypeTablePointer eTTnode = *peTTnode; + + if (eTTnode) + { + if (eTTnode->eventType != entry.m_eventType) + { + // Resize the table! + GrowEventTypeTable(); + // Try again to add it. + AddEntry(entry); + return; + } + } + else + { + eTTnode = new EventTypeTable; + eTTnode->eventType = entry.m_eventType; + *peTTnode = eTTnode; + } + + // Fill all hash entries between entry.m_id and entry.m_lastId... + eTTnode->eventEntryTable.Add(&entry); +} + +void wxEventHashTable::AllocEventTypeTable(size_t size) +{ + m_eventTypeTable = new EventTypeTablePointer[size]; + memset((void *)m_eventTypeTable, 0, sizeof(EventTypeTablePointer)*size); + m_size = size; +} + +void wxEventHashTable::GrowEventTypeTable() +{ + size_t oldSize = m_size; + EventTypeTablePointer *oldEventTypeTable = m_eventTypeTable; + + // TODO: Search the most optimal grow sequence + AllocEventTypeTable(/* GetNextPrime(oldSize) */oldSize*2+1); + + for ( size_t i = 0; i < oldSize; /* */ ) + { + EventTypeTablePointer eTToldNode = oldEventTypeTable[i]; + if (eTToldNode) + { + EventTypeTablePointer *peTTnode = &m_eventTypeTable[eTToldNode->eventType % m_size]; + EventTypeTablePointer eTTnode = *peTTnode; + + // Check for collision, we don't want any. + if (eTTnode) + { + GrowEventTypeTable(); + continue; // Don't increment the counter, + // as we still need to add this element. + } + else + { + // Get the old value and put it in the new table. + *peTTnode = oldEventTypeTable[i]; + } + } + + i++; + } + + delete[] oldEventTypeTable; +} + + +// ---------------------------------------------------------------------------- +// wxEvtHandler +// ---------------------------------------------------------------------------- + +/* + * Event handler + */ + +wxEvtHandler::wxEvtHandler() +{ + m_nextHandler = (wxEvtHandler *) NULL; + m_previousHandler = (wxEvtHandler *) NULL; + m_enabled = true; + m_dynamicEvents = (wxList *) NULL; + m_pendingEvents = (wxList *) NULL; +#if wxUSE_THREADS +# if !defined(__VISAGECPP__) + m_eventsLocker = new wxCriticalSection; +# endif +#endif + + // no client data (yet) + m_clientData = NULL; + m_clientDataType = wxClientData_None; +} + +wxEvtHandler::~wxEvtHandler() +{ + // Takes itself out of the list of handlers + if (m_previousHandler) + m_previousHandler->m_nextHandler = m_nextHandler; + + if (m_nextHandler) + m_nextHandler->m_previousHandler = m_previousHandler; + + if (m_dynamicEvents) + { + for ( wxList::iterator it = m_dynamicEvents->begin(), + end = m_dynamicEvents->end(); + it != end; + ++it ) + { +#if WXWIN_COMPATIBILITY_EVENT_TYPES + wxEventTableEntry *entry = (wxEventTableEntry*)*it; +#else // !WXWIN_COMPATIBILITY_EVENT_TYPES + wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)*it; +#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES + + if (entry->m_callbackUserData) + delete entry->m_callbackUserData; + delete entry; + } + delete m_dynamicEvents; + }; + + if (m_pendingEvents) + m_pendingEvents->DeleteContents(true); + delete m_pendingEvents; + +#if wxUSE_THREADS +# if !defined(__VISAGECPP__) + delete m_eventsLocker; +# endif + + // Remove us from wxPendingEvents if necessary. + if(wxPendingEventsLocker) + wxENTER_CRIT_SECT(*wxPendingEventsLocker); +#endif // wxUSE_THREADS + + if ( wxPendingEvents ) + { + // Delete all occurences of this from the list of pending events + while (wxPendingEvents->DeleteObject(this)) { } // Do nothing + } + +#if wxUSE_THREADS + if(wxPendingEventsLocker) + wxLEAVE_CRIT_SECT(*wxPendingEventsLocker); +#endif // wxUSE_THREADS + + // we only delete object data, not untyped + if ( m_clientDataType == wxClientData_Object ) + delete m_clientObject; +} + +#if wxUSE_THREADS + +bool wxEvtHandler::ProcessThreadEvent(wxEvent& event) +{ + // check that we are really in a child thread + wxASSERT_MSG( !wxThread::IsMain(), + wxT("use ProcessEvent() in main thread") ); + + AddPendingEvent(event); + + return true; +} + +void wxEvtHandler::ClearEventLocker() +{ +#if !defined(__VISAGECPP__) + delete m_eventsLocker; + m_eventsLocker = NULL; +#endif +} + +#endif // wxUSE_THREADS + +void wxEvtHandler::AddPendingEvent(wxEvent& event) +{ + // 1) Add event to list of pending events of this event handler + + wxEvent *eventCopy = event.Clone(); + + // we must be able to copy the events here so the event class must + // implement Clone() properly instead of just providing a NULL stab for it + wxCHECK_RET( eventCopy, + _T("events of this type aren't supposed to be posted") ); + + wxENTER_CRIT_SECT( Lock() ); + + if ( !m_pendingEvents ) + m_pendingEvents = new wxList; + + m_pendingEvents->Append(eventCopy); + + // 2) Add this event handler to list of event handlers that + // have pending events. + + wxENTER_CRIT_SECT(*wxPendingEventsLocker); + + if ( !wxPendingEvents ) + wxPendingEvents = new wxList; + wxPendingEvents->Append(this); + + wxLEAVE_CRIT_SECT(*wxPendingEventsLocker); + + wxLEAVE_CRIT_SECT( Lock() ); + + // 3) Inform the system that new pending events are somewhere, + // and that these should be processed in idle time. + wxWakeUpIdle(); +} + +void wxEvtHandler::ProcessPendingEvents() +{ + // this method is only called by wxApp if this handler does have + // pending events + wxCHECK_RET( m_pendingEvents, + wxT("Please call wxApp::ProcessPendingEvents() instead") ); + + wxENTER_CRIT_SECT( Lock() ); + + // we leave the loop once we have processed all events that were present at + // the start of ProcessPendingEvents because otherwise we could get into + // infinite loop if the pending event handler execution resulted in another + // event being posted + size_t n = m_pendingEvents->size(); + for ( wxList::compatibility_iterator node = m_pendingEvents->GetFirst(); + node; + node = m_pendingEvents->GetFirst() ) + { + { + wxEventPtr event(wx_static_cast(wxEvent *, node->GetData())); + + // It's important we remove event from list before processing it. + // Else a nested event loop, for example from a modal dialog, might + // process the same event again. + + m_pendingEvents->Erase(node); + + wxLEAVE_CRIT_SECT( Lock() ); + + ProcessEvent(*event); + } // delete the event at this block exit, before re-locking our + // critical section, to avoid deadlocks if the event dtor locks + // something else itself (see #10790) + + wxENTER_CRIT_SECT( Lock() ); + + if ( --n == 0 ) + break; + } + + wxLEAVE_CRIT_SECT( Lock() ); +} + +/* + * Event table stuff + */ +/* static */ bool +wxEvtHandler::ProcessEventIfMatches(const wxEventTableEntryBase& entry, + wxEvtHandler *handler, + wxEvent& event) +{ + int tableId1 = entry.m_id, + tableId2 = entry.m_lastId; + + // match only if the event type is the same and the id is either -1 in + // the event table (meaning "any") or the event id matches the id + // specified in the event table either exactly or by falling into + // range between first and last + if ((tableId1 == wxID_ANY) || + (tableId2 == wxID_ANY && tableId1 == event.GetId()) || + (tableId2 != wxID_ANY && + (event.GetId() >= tableId1 && event.GetId() <= tableId2))) + { + event.Skip(false); + event.m_callbackUserData = entry.m_callbackUserData; + +#if wxUSE_EXCEPTIONS + if ( wxTheApp ) + { + // call the handler via wxApp method which allows the user to catch + // any exceptions which may be thrown by any handler in the program + // in one place + wxTheApp->HandleEvent(handler, (wxEventFunction)entry.m_fn, event); + } + else +#endif // wxUSE_EXCEPTIONS + { + // no need for an extra virtual function call + (handler->*((wxEventFunction) (entry.m_fn)))(event); + } + + if (!event.GetSkipped()) + return true; + } + + return false; +} + +bool wxEvtHandler::TryParent(wxEvent& event) +{ + if ( wxTheApp && (this != wxTheApp) ) + { + // Special case: don't pass wxEVT_IDLE to wxApp, since it'll always + // swallow it. wxEVT_IDLE is sent explicitly to wxApp so it will be + // processed appropriately via SearchEventTable. + if ( event.GetEventType() != wxEVT_IDLE ) + { + if ( wxTheApp->ProcessEvent(event) ) + return true; + } + } + + return false; +} + +bool wxEvtHandler::ProcessEvent(wxEvent& event) +{ + // allow the application to hook into event processing + if ( wxTheApp ) + { + int rc = wxTheApp->FilterEvent(event); + if ( rc != -1 ) + { + wxASSERT_MSG( rc == 1 || rc == 0, + _T("unexpected wxApp::FilterEvent return value") ); + + return rc != 0; + } + //else: proceed normally + } + + // An event handler can be enabled or disabled + if ( GetEvtHandlerEnabled() ) + { + // if we have a validator, it has higher priority than our own event + // table + if ( TryValidator(event) ) + return true; + + // Handle per-instance dynamic event tables first + if ( m_dynamicEvents && SearchDynamicEventTable(event) ) + return true; + + // Then static per-class event tables + if ( GetEventHashTable().HandleEvent(event, this) ) + return true; + } + + // Try going down the event handler chain + if ( GetNextHandler() ) + { + if ( GetNextHandler()->ProcessEvent(event) ) + return true; + } + + // Finally propagate the event upwards the window chain and/or to the + // application object as necessary + return TryParent(event); +} + + +bool wxEvtHandler::SearchEventTable(wxEventTable& table, wxEvent& event) +{ + const wxEventType eventType = event.GetEventType(); + for ( int i = 0; table.entries[i].m_fn != 0; i++ ) + { + const wxEventTableEntry& entry = table.entries[i]; + if ( eventType == entry.m_eventType ) + { + if ( ProcessEventIfMatches(entry, this, event) ) + return true; + } + } + + return false; +} + +void wxEvtHandler::Connect( int id, int lastId, + int eventType, + wxObjectEventFunction func, + wxObject *userData, + wxEvtHandler* eventSink ) +{ +#if WXWIN_COMPATIBILITY_EVENT_TYPES + wxEventTableEntry *entry = new wxEventTableEntry; + entry->m_eventType = eventType; + entry->m_id = id; + entry->m_lastId = lastId; + entry->m_fn = func; + entry->m_callbackUserData = userData; +#else // !WXWIN_COMPATIBILITY_EVENT_TYPES + wxDynamicEventTableEntry *entry = + new wxDynamicEventTableEntry(eventType, id, lastId, func, userData, eventSink); +#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES + + if (!m_dynamicEvents) + m_dynamicEvents = new wxList; + + // Insert at the front of the list so most recent additions are found first + m_dynamicEvents->Insert( (wxObject*) entry ); +} + +bool wxEvtHandler::Disconnect( int id, int lastId, wxEventType eventType, + wxObjectEventFunction func, + wxObject *userData, + wxEvtHandler* eventSink ) +{ + if (!m_dynamicEvents) + return false; + + wxList::compatibility_iterator node = m_dynamicEvents->GetFirst(); + while (node) + { +#if WXWIN_COMPATIBILITY_EVENT_TYPES + wxEventTableEntry *entry = (wxEventTableEntry*)node->GetData(); +#else // !WXWIN_COMPATIBILITY_EVENT_TYPES + wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); +#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES + + if ((entry->m_id == id) && + ((entry->m_lastId == lastId) || (lastId == wxID_ANY)) && + ((entry->m_eventType == eventType) || (eventType == wxEVT_NULL)) && + ((entry->m_fn == func) || (func == (wxObjectEventFunction)NULL)) && + ((entry->m_eventSink == eventSink) || (eventSink == (wxEvtHandler*)NULL)) && + ((entry->m_callbackUserData == userData) || (userData == (wxObject*)NULL))) + { + if (entry->m_callbackUserData) + delete entry->m_callbackUserData; + m_dynamicEvents->Erase( node ); + delete entry; + return true; + } + node = node->GetNext(); + } + return false; +} + +bool wxEvtHandler::SearchDynamicEventTable( wxEvent& event ) +{ + wxCHECK_MSG( m_dynamicEvents, false, + wxT("caller should check that we have dynamic events") ); + + wxList::compatibility_iterator node = m_dynamicEvents->GetFirst(); + while (node) + { +#if WXWIN_COMPATIBILITY_EVENT_TYPES + wxEventTableEntry *entry = (wxEventTableEntry*)node->GetData(); +#else // !WXWIN_COMPATIBILITY_EVENT_TYPES + wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); +#endif // WXWIN_COMPATIBILITY_EVENT_TYPES/!WXWIN_COMPATIBILITY_EVENT_TYPES + + // get next node before (maybe) calling the event handler as it could + // call Disconnect() invalidating the current node + node = node->GetNext(); + + if ((event.GetEventType() == entry->m_eventType) && (entry->m_fn != 0)) + { + wxEvtHandler *handler = +#if !WXWIN_COMPATIBILITY_EVENT_TYPES + entry->m_eventSink ? entry->m_eventSink + : +#endif + this; + + if ( ProcessEventIfMatches(*entry, handler, event) ) + { + return true; + } + } + } + + return false; +} + +void wxEvtHandler::DoSetClientObject( wxClientData *data ) +{ + wxASSERT_MSG( m_clientDataType != wxClientData_Void, + wxT("can't have both object and void client data") ); + + if ( m_clientObject ) + delete m_clientObject; + + m_clientObject = data; + m_clientDataType = wxClientData_Object; +} + +wxClientData *wxEvtHandler::DoGetClientObject() const +{ + // it's not an error to call GetClientObject() on a window which doesn't + // have client data at all - NULL will be returned + wxASSERT_MSG( m_clientDataType != wxClientData_Void, + wxT("this window doesn't have object client data") ); + + return m_clientObject; +} + +void wxEvtHandler::DoSetClientData( void *data ) +{ + wxASSERT_MSG( m_clientDataType != wxClientData_Object, + wxT("can't have both object and void client data") ); + + m_clientData = data; + m_clientDataType = wxClientData_Void; +} + +void *wxEvtHandler::DoGetClientData() const +{ + // it's not an error to call GetClientData() on a window which doesn't have + // client data at all - NULL will be returned + wxASSERT_MSG( m_clientDataType != wxClientData_Object, + wxT("this window doesn't have void client data") ); + + return m_clientData; +} + +#endif // wxUSE_BASE + +#if wxUSE_GUI + +// Find a window with the focus, that is also a descendant of the given window. +// This is used to determine the window to initially send commands to. +wxWindow* wxFindFocusDescendant(wxWindow* ancestor) +{ + // Process events starting with the window with the focus, if any. + wxWindow* focusWin = wxWindow::FindFocus(); + wxWindow* win = focusWin; + + // Check if this is a descendant of this frame. + // If not, win will be set to NULL. + while (win) + { + if (win == ancestor) + break; + else + win = win->GetParent(); + } + if (win == (wxWindow*) NULL) + focusWin = (wxWindow*) NULL; + + return focusWin; +} + +#endif // wxUSE_GUI diff --git a/Source/3rd Party/wx/src/common/evtloopcmn.cpp b/Source/3rd Party/wx/src/common/evtloopcmn.cpp index 75f88ca12..00bc1001b 100644 --- a/Source/3rd Party/wx/src/common/evtloopcmn.cpp +++ b/Source/3rd Party/wx/src/common/evtloopcmn.cpp @@ -1,172 +1,172 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/evtloopcmn.cpp -// Purpose: common wxEventLoop-related stuff -// Author: Vadim Zeitlin -// Modified by: -// Created: 2006-01-12 -// RCS-ID: $Id: evtloopcmn.cpp 45938 2007-05-10 02:07:41Z VZ $ -// Copyright: (c) 2006 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/evtloop.h" - -#ifndef WX_PRECOMP - #include "wx/app.h" -#endif //WX_PRECOMP - -// see the comment near the declaration of wxRunningEventLoopCount in -// src/msw/thread.cpp for the explanation of this hack -#if defined(__WXMSW__) && wxUSE_THREADS - -extern WXDLLIMPEXP_DATA_BASE(int) wxRunningEventLoopCount; -struct wxRunningEventLoopCounter -{ - wxRunningEventLoopCounter() { wxRunningEventLoopCount++; } - ~wxRunningEventLoopCounter() { wxRunningEventLoopCount--; } -}; - -#endif // __WXMSW__ - -// ---------------------------------------------------------------------------- -// globals -// ---------------------------------------------------------------------------- - -wxEventLoop *wxEventLoopBase::ms_activeLoop = NULL; - -// wxEventLoopManual is unused in the other ports -#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) - -// ============================================================================ -// wxEventLoopManual implementation -// ============================================================================ - -wxEventLoopManual::wxEventLoopManual() -{ - m_exitcode = 0; - m_shouldExit = false; -} - -int wxEventLoopManual::Run() -{ - // event loops are not recursive, you need to create another loop! - wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") ); - - // ProcessIdle() and Dispatch() below may throw so the code here should - // be exception-safe, hence we must use local objects for all actions we - // should undo - wxEventLoopActivator activate(wx_static_cast(wxEventLoop *, this)); - -#if defined(__WXMSW__) && wxUSE_THREADS - wxRunningEventLoopCounter evtLoopCounter; -#endif // __WXMSW__ - - // we must ensure that OnExit() is called even if an exception is thrown - // from inside Dispatch() but we must call it from Exit() in normal - // situations because it is supposed to be called synchronously, - // wxModalEventLoop depends on this (so we can't just use ON_BLOCK_EXIT or - // something similar here) -#if wxUSE_EXCEPTIONS - for ( ;; ) - { - try - { -#endif // wxUSE_EXCEPTIONS - - // this is the event loop itself - for ( ;; ) - { - // give them the possibility to do whatever they want - OnNextIteration(); - - // generate and process idle events for as long as we don't - // have anything else to do - while ( !Pending() && (wxTheApp && wxTheApp->ProcessIdle()) ) - ; - - // if the "should exit" flag is set, the loop should terminate - // but not before processing any remaining messages so while - // Pending() returns true, do process them - if ( m_shouldExit ) - { - while ( Pending() ) - Dispatch(); - - break; - } - - // a message came or no more idle processing to do, sit in - // Dispatch() waiting for the next message - if ( !Dispatch() ) - { - // we got WM_QUIT - break; - } - } - -#if wxUSE_EXCEPTIONS - // exit the outer loop as well - break; - } - catch ( ... ) - { - try - { - if ( !wxTheApp || !wxTheApp->OnExceptionInMainLoop() ) - { - OnExit(); - break; - } - //else: continue running the event loop - } - catch ( ... ) - { - // OnException() throwed, possibly rethrowing the same - // exception again: very good, but we still need OnExit() to - // be called - OnExit(); - throw; - } - } - } -#endif // wxUSE_EXCEPTIONS - - return m_exitcode; -} - -void wxEventLoopManual::Exit(int rc) -{ - wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") ); - - m_exitcode = rc; - m_shouldExit = true; - - OnExit(); - - // all we have to do to exit from the loop is to (maybe) wake it up so that - // it can notice that Exit() had been called - // - // in particular, do *not* use here calls such as PostQuitMessage() (under - // MSW) which terminate the current event loop here because we're not sure - // that it is going to be processed by the correct event loop: it would be - // possible that another one is started and terminated by mistake if we do - // this - WakeUp(); -} - -#endif // __WXMSW__ || __WXMAC__ || __WXDFB__ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/evtloopcmn.cpp +// Purpose: common wxEventLoop-related stuff +// Author: Vadim Zeitlin +// Modified by: +// Created: 2006-01-12 +// RCS-ID: $Id: evtloopcmn.cpp 45938 2007-05-10 02:07:41Z VZ $ +// Copyright: (c) 2006 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/evtloop.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" +#endif //WX_PRECOMP + +// see the comment near the declaration of wxRunningEventLoopCount in +// src/msw/thread.cpp for the explanation of this hack +#if defined(__WXMSW__) && wxUSE_THREADS + +extern WXDLLIMPEXP_DATA_BASE(int) wxRunningEventLoopCount; +struct wxRunningEventLoopCounter +{ + wxRunningEventLoopCounter() { wxRunningEventLoopCount++; } + ~wxRunningEventLoopCounter() { wxRunningEventLoopCount--; } +}; + +#endif // __WXMSW__ + +// ---------------------------------------------------------------------------- +// globals +// ---------------------------------------------------------------------------- + +wxEventLoop *wxEventLoopBase::ms_activeLoop = NULL; + +// wxEventLoopManual is unused in the other ports +#if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXDFB__) + +// ============================================================================ +// wxEventLoopManual implementation +// ============================================================================ + +wxEventLoopManual::wxEventLoopManual() +{ + m_exitcode = 0; + m_shouldExit = false; +} + +int wxEventLoopManual::Run() +{ + // event loops are not recursive, you need to create another loop! + wxCHECK_MSG( !IsRunning(), -1, _T("can't reenter a message loop") ); + + // ProcessIdle() and Dispatch() below may throw so the code here should + // be exception-safe, hence we must use local objects for all actions we + // should undo + wxEventLoopActivator activate(wx_static_cast(wxEventLoop *, this)); + +#if defined(__WXMSW__) && wxUSE_THREADS + wxRunningEventLoopCounter evtLoopCounter; +#endif // __WXMSW__ + + // we must ensure that OnExit() is called even if an exception is thrown + // from inside Dispatch() but we must call it from Exit() in normal + // situations because it is supposed to be called synchronously, + // wxModalEventLoop depends on this (so we can't just use ON_BLOCK_EXIT or + // something similar here) +#if wxUSE_EXCEPTIONS + for ( ;; ) + { + try + { +#endif // wxUSE_EXCEPTIONS + + // this is the event loop itself + for ( ;; ) + { + // give them the possibility to do whatever they want + OnNextIteration(); + + // generate and process idle events for as long as we don't + // have anything else to do + while ( !Pending() && (wxTheApp && wxTheApp->ProcessIdle()) ) + ; + + // if the "should exit" flag is set, the loop should terminate + // but not before processing any remaining messages so while + // Pending() returns true, do process them + if ( m_shouldExit ) + { + while ( Pending() ) + Dispatch(); + + break; + } + + // a message came or no more idle processing to do, sit in + // Dispatch() waiting for the next message + if ( !Dispatch() ) + { + // we got WM_QUIT + break; + } + } + +#if wxUSE_EXCEPTIONS + // exit the outer loop as well + break; + } + catch ( ... ) + { + try + { + if ( !wxTheApp || !wxTheApp->OnExceptionInMainLoop() ) + { + OnExit(); + break; + } + //else: continue running the event loop + } + catch ( ... ) + { + // OnException() throwed, possibly rethrowing the same + // exception again: very good, but we still need OnExit() to + // be called + OnExit(); + throw; + } + } + } +#endif // wxUSE_EXCEPTIONS + + return m_exitcode; +} + +void wxEventLoopManual::Exit(int rc) +{ + wxCHECK_RET( IsRunning(), _T("can't call Exit() if not running") ); + + m_exitcode = rc; + m_shouldExit = true; + + OnExit(); + + // all we have to do to exit from the loop is to (maybe) wake it up so that + // it can notice that Exit() had been called + // + // in particular, do *not* use here calls such as PostQuitMessage() (under + // MSW) which terminate the current event loop here because we're not sure + // that it is going to be processed by the correct event loop: it would be + // possible that another one is started and terminated by mistake if we do + // this + WakeUp(); +} + +#endif // __WXMSW__ || __WXMAC__ || __WXDFB__ diff --git a/Source/3rd Party/wx/src/common/execcmn.cpp b/Source/3rd Party/wx/src/common/execcmn.cpp index 60af65d0e..2b2025270 100644 --- a/Source/3rd Party/wx/src/common/execcmn.cpp +++ b/Source/3rd Party/wx/src/common/execcmn.cpp @@ -1,122 +1,122 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: common/wxexec.cpp -// Purpose: defines wxStreamTempInputBuffer which is used by Unix and MSW -// implementations of wxExecute; this file is only used by the -// library and never by the user code -// Author: Vadim Zeitlin -// Modified by: -// Created: 20.08.02 -// RCS-ID: $Id: execcmn.cpp 35289 2005-08-23 23:12:48Z VZ $ -// Copyright: (c) 2002 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -#ifndef _WX_WXEXEC_CPP_ -#define _WX_WXEXEC_CPP_ - -// this file should never be compiled directly, just included by other code -#ifndef _WX_USED_BY_WXEXECUTE_ - #error "You should never directly build this file!" -#endif - -// ---------------------------------------------------------------------------- -// wxStreamTempInputBuffer -// ---------------------------------------------------------------------------- - -/* - wxStreamTempInputBuffer is a hack which we need to solve the problem of - executing a child process synchronously with IO redirecting: when we do - this, the child writes to a pipe we open to it but when the pipe buffer - (which has finite capacity, e.g. commonly just 4Kb) becomes full we have to - read data from it because the child blocks in its write() until then and if - it blocks we are never going to return from wxExecute() so we dead lock. - - So here is the fix: we now read the output as soon as it appears into a temp - buffer (wxStreamTempInputBuffer object) and later just stuff it back into - the stream when the process terminates. See supporting code in wxExecute() - itself as well. - - Note that this is horribly inefficient for large amounts of output (count - the number of times we copy the data around) and so a better API is badly - needed! However it's not easy to devise a way to do this keeping backwards - compatibility with the existing wxExecute(wxEXEC_SYNC)... -*/ - -class wxStreamTempInputBuffer -{ -public: - wxStreamTempInputBuffer(); - - // call to associate a stream with this buffer, otherwise nothing happens - // at all - void Init(wxPipeInputStream *stream); - - // check for input on our stream and cache it in our buffer if any - void Update(); - - ~wxStreamTempInputBuffer(); - -private: - // the stream we're buffering, if NULL we don't do anything at all - wxPipeInputStream *m_stream; - - // the buffer of size m_size (NULL if m_size == 0) - void *m_buffer; - - // the size of the buffer - size_t m_size; - - DECLARE_NO_COPY_CLASS(wxStreamTempInputBuffer) -}; - -inline wxStreamTempInputBuffer::wxStreamTempInputBuffer() -{ - m_stream = NULL; - m_buffer = NULL; - m_size = 0; -} - -inline void wxStreamTempInputBuffer::Init(wxPipeInputStream *stream) -{ - m_stream = stream; -} - -inline -void wxStreamTempInputBuffer::Update() -{ - if ( m_stream && m_stream->CanRead() ) - { - // realloc in blocks of 4Kb: this is the default (and minimal) buffer - // size of the Unix pipes so it should be the optimal step - // - // NB: don't use "static int" in this inline function, some compilers - // (e.g. IBM xlC) don't like it - enum { incSize = 4096 }; - - void *buf = realloc(m_buffer, m_size + incSize); - if ( !buf ) - { - // don't read any more, we don't have enough memory to do it - m_stream = NULL; - } - else // got memory for the buffer - { - m_buffer = buf; - m_stream->Read((char *)m_buffer + m_size, incSize); - m_size += m_stream->LastRead(); - } - } -} - -inline -wxStreamTempInputBuffer::~wxStreamTempInputBuffer() -{ - if ( m_buffer ) - { - m_stream->Ungetch(m_buffer, m_size); - free(m_buffer); - } -} - -#endif // _WX_WXEXEC_CPP_ - +/////////////////////////////////////////////////////////////////////////////// +// Name: common/wxexec.cpp +// Purpose: defines wxStreamTempInputBuffer which is used by Unix and MSW +// implementations of wxExecute; this file is only used by the +// library and never by the user code +// Author: Vadim Zeitlin +// Modified by: +// Created: 20.08.02 +// RCS-ID: $Id: execcmn.cpp 35289 2005-08-23 23:12:48Z VZ $ +// Copyright: (c) 2002 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_WXEXEC_CPP_ +#define _WX_WXEXEC_CPP_ + +// this file should never be compiled directly, just included by other code +#ifndef _WX_USED_BY_WXEXECUTE_ + #error "You should never directly build this file!" +#endif + +// ---------------------------------------------------------------------------- +// wxStreamTempInputBuffer +// ---------------------------------------------------------------------------- + +/* + wxStreamTempInputBuffer is a hack which we need to solve the problem of + executing a child process synchronously with IO redirecting: when we do + this, the child writes to a pipe we open to it but when the pipe buffer + (which has finite capacity, e.g. commonly just 4Kb) becomes full we have to + read data from it because the child blocks in its write() until then and if + it blocks we are never going to return from wxExecute() so we dead lock. + + So here is the fix: we now read the output as soon as it appears into a temp + buffer (wxStreamTempInputBuffer object) and later just stuff it back into + the stream when the process terminates. See supporting code in wxExecute() + itself as well. + + Note that this is horribly inefficient for large amounts of output (count + the number of times we copy the data around) and so a better API is badly + needed! However it's not easy to devise a way to do this keeping backwards + compatibility with the existing wxExecute(wxEXEC_SYNC)... +*/ + +class wxStreamTempInputBuffer +{ +public: + wxStreamTempInputBuffer(); + + // call to associate a stream with this buffer, otherwise nothing happens + // at all + void Init(wxPipeInputStream *stream); + + // check for input on our stream and cache it in our buffer if any + void Update(); + + ~wxStreamTempInputBuffer(); + +private: + // the stream we're buffering, if NULL we don't do anything at all + wxPipeInputStream *m_stream; + + // the buffer of size m_size (NULL if m_size == 0) + void *m_buffer; + + // the size of the buffer + size_t m_size; + + DECLARE_NO_COPY_CLASS(wxStreamTempInputBuffer) +}; + +inline wxStreamTempInputBuffer::wxStreamTempInputBuffer() +{ + m_stream = NULL; + m_buffer = NULL; + m_size = 0; +} + +inline void wxStreamTempInputBuffer::Init(wxPipeInputStream *stream) +{ + m_stream = stream; +} + +inline +void wxStreamTempInputBuffer::Update() +{ + if ( m_stream && m_stream->CanRead() ) + { + // realloc in blocks of 4Kb: this is the default (and minimal) buffer + // size of the Unix pipes so it should be the optimal step + // + // NB: don't use "static int" in this inline function, some compilers + // (e.g. IBM xlC) don't like it + enum { incSize = 4096 }; + + void *buf = realloc(m_buffer, m_size + incSize); + if ( !buf ) + { + // don't read any more, we don't have enough memory to do it + m_stream = NULL; + } + else // got memory for the buffer + { + m_buffer = buf; + m_stream->Read((char *)m_buffer + m_size, incSize); + m_size += m_stream->LastRead(); + } + } +} + +inline +wxStreamTempInputBuffer::~wxStreamTempInputBuffer() +{ + if ( m_buffer ) + { + m_stream->Ungetch(m_buffer, m_size); + free(m_buffer); + } +} + +#endif // _WX_WXEXEC_CPP_ + diff --git a/Source/3rd Party/wx/src/common/extended.c b/Source/3rd Party/wx/src/common/extended.c index 69fe57e2b..2f9df1b30 100644 --- a/Source/3rd Party/wx/src/common/extended.c +++ b/Source/3rd Party/wx/src/common/extended.c @@ -1,196 +1,196 @@ -/***************************************************************************** -** Name: extended.c -** Purpose: IEEE Extended<->Double routines to save floats to file -** Maintainer: Ryan Norton -** Modified by: -** Created: 11/24/04 -** RCS-ID: $Id: extended.c 36952 2006-01-18 10:25:04Z JS $ -*****************************************************************************/ - - -#if defined(_WIN32_WCE) - /* eVC cause warnings in its own headers: stdlib.h and winnt.h */ - #pragma warning (disable:4115) - #pragma warning (disable:4214) -#endif - -#include -#include -#include -#include -#include -#include "wx/defs.h" - -#if defined(_WIN32_WCE) - #pragma warning (default:4115) - #pragma warning (default:4214) -#endif - -#if wxUSE_APPLE_IEEE - -#include "wx/math.h" - -/* Copyright (C) 1989-1991 Ken Turkowski. - * - * All rights reserved. - * - * Warranty Information - * Even though I have reviewed this software, I make no warranty - * or representation, either express or implied, with respect to this - * software, its quality, accuracy, merchantability, or fitness for a - * particular purpose. As a result, this software is provided "as is," - * and you, its user, are assuming the entire risk as to its quality - * and accuracy. - * - * This code may be used and freely distributed as long as it includes - * this copyright notice and the above warranty information. - * - * Machine-independent I/O routines for IEEE floating-point numbers. - * - * NaN's and infinities are converted to HUGE_VAL or HUGE, which - * happens to be infinity on IEEE machines. Unfortunately, it is - * impossible to preserve NaN's in a machine-independent way. - * Infinities are, however, preserved on IEEE machines. - * - * These routines have been tested on the following machines: - * Apple Macintosh, MPW 3.1 C compiler - * Apple Macintosh, THINK C compiler - * Silicon Graphics IRIS, MIPS compiler - * Cray X/MP and Y/MP - * Digital Equipment VAX - * Sequent Balance (Multiprocesor 386) - * NeXT - * - * - * Implemented by Malcolm Slaney and Ken Turkowski. - * - * Malcolm Slaney contributions during 1988-1990 include big- and little- - * endian file I/O, conversion to and from Motorola's extended 80-bit - * floating-point format, and conversions to and from IEEE single- - * precision floating-point format. - * - * In 1991, Ken Turkowski implemented the conversions to and from - * IEEE double-precision format, added more precision to the extended - * conversions, and accommodated conversions involving +/- infinity, - * NaN's, and denormalized numbers. - */ - -#ifndef HUGE_VAL -# define HUGE_VAL HUGE -#endif /*HUGE_VAL*/ - - -/**************************************************************** - * The following two routines make up for deficiencies in many - * compilers to convert properly between unsigned integers and - * floating-point. Some compilers which have this bug are the - * THINK_C compiler for the Macintosh and the C compiler for the - * Silicon Graphics MIPS-based Iris. - ****************************************************************/ - -#ifdef applec /* The Apple C compiler works */ -# define FloatToUnsigned(f) ((wxUint32)(f)) -# define UnsignedToFloat(u) ((wxFloat64)(u)) -#else /*applec*/ -# define FloatToUnsigned(f) ((wxUint32)(((wxInt32)((f) - 2147483648.0)) + 2147483647L) + 1) -# define UnsignedToFloat(u) (((wxFloat64)((wxInt32)((u) - 2147483647L - 1))) + 2147483648.0) -#endif /*applec*/ - - - -/**************************************************************** - * Extended precision IEEE floating-point conversion routines. - * Extended is an 80-bit number as defined by Motorola, - * with a sign bit, 15 bits of exponent (offset 16383?), - * and a 64-bit mantissa, with no hidden bit. - ****************************************************************/ - -wxFloat64 ConvertFromIeeeExtended(const wxInt8 *bytes) -{ - wxFloat64 f; - wxInt32 expon; - wxUint32 hiMant, loMant; - - expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); - hiMant = ((wxUint32)(bytes[2] & 0xFF) << 24) - | ((wxUint32)(bytes[3] & 0xFF) << 16) - | ((wxUint32)(bytes[4] & 0xFF) << 8) - | ((wxUint32)(bytes[5] & 0xFF)); - loMant = ((wxUint32)(bytes[6] & 0xFF) << 24) - | ((wxUint32)(bytes[7] & 0xFF) << 16) - | ((wxUint32)(bytes[8] & 0xFF) << 8) - | ((wxUint32)(bytes[9] & 0xFF)); - - if (expon == 0 && hiMant == 0 && loMant == 0) { - f = 0; - } - else { - if (expon == 0x7FFF) { /* Infinity or NaN */ - f = HUGE_VAL; - } - else { - expon -= 16383; - f = ldexp(UnsignedToFloat(hiMant), expon-=31); - f += ldexp(UnsignedToFloat(loMant), expon-=32); - } - } - - if (bytes[0] & 0x80) - return -f; - else - return f; -} - - -/****************************************************************/ - - -void ConvertToIeeeExtended(wxFloat64 num, wxInt8 *bytes) -{ - wxInt32 sign; - wxInt32 expon; - wxFloat64 fMant, fsMant; - wxUint32 hiMant, loMant; - - if (num < 0) { - sign = 0x8000; - num *= -1; - } else { - sign = 0; - } - - if (num == 0) { - expon = 0; hiMant = 0; loMant = 0; - } - else { - fMant = frexp(num, &expon); - if ((expon > 16384) || !(fMant < 1)) { /* Infinity or NaN */ - expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */ - } - else { /* Finite */ - expon += 16382; - if (expon < 0) { /* denormalized */ - fMant = ldexp(fMant, expon); - expon = 0; - } - expon |= sign; - fMant = ldexp(fMant, 32); fsMant = floor(fMant); hiMant = FloatToUnsigned(fsMant); - fMant = ldexp(fMant - fsMant, 32); fsMant = floor(fMant); loMant = FloatToUnsigned(fsMant); - } - } - - bytes[0] = expon >> 8; - bytes[1] = expon; - bytes[2] = hiMant >> 24; - bytes[3] = hiMant >> 16; - bytes[4] = hiMant >> 8; - bytes[5] = hiMant; - bytes[6] = loMant >> 24; - bytes[7] = loMant >> 16; - bytes[8] = loMant >> 8; - bytes[9] = loMant; -} - - - -#endif /* wxUSE_APPLE_IEEE */ +/***************************************************************************** +** Name: extended.c +** Purpose: IEEE Extended<->Double routines to save floats to file +** Maintainer: Ryan Norton +** Modified by: +** Created: 11/24/04 +** RCS-ID: $Id: extended.c 36952 2006-01-18 10:25:04Z JS $ +*****************************************************************************/ + + +#if defined(_WIN32_WCE) + /* eVC cause warnings in its own headers: stdlib.h and winnt.h */ + #pragma warning (disable:4115) + #pragma warning (disable:4214) +#endif + +#include +#include +#include +#include +#include +#include "wx/defs.h" + +#if defined(_WIN32_WCE) + #pragma warning (default:4115) + #pragma warning (default:4214) +#endif + +#if wxUSE_APPLE_IEEE + +#include "wx/math.h" + +/* Copyright (C) 1989-1991 Ken Turkowski. + * + * All rights reserved. + * + * Warranty Information + * Even though I have reviewed this software, I make no warranty + * or representation, either express or implied, with respect to this + * software, its quality, accuracy, merchantability, or fitness for a + * particular purpose. As a result, this software is provided "as is," + * and you, its user, are assuming the entire risk as to its quality + * and accuracy. + * + * This code may be used and freely distributed as long as it includes + * this copyright notice and the above warranty information. + * + * Machine-independent I/O routines for IEEE floating-point numbers. + * + * NaN's and infinities are converted to HUGE_VAL or HUGE, which + * happens to be infinity on IEEE machines. Unfortunately, it is + * impossible to preserve NaN's in a machine-independent way. + * Infinities are, however, preserved on IEEE machines. + * + * These routines have been tested on the following machines: + * Apple Macintosh, MPW 3.1 C compiler + * Apple Macintosh, THINK C compiler + * Silicon Graphics IRIS, MIPS compiler + * Cray X/MP and Y/MP + * Digital Equipment VAX + * Sequent Balance (Multiprocesor 386) + * NeXT + * + * + * Implemented by Malcolm Slaney and Ken Turkowski. + * + * Malcolm Slaney contributions during 1988-1990 include big- and little- + * endian file I/O, conversion to and from Motorola's extended 80-bit + * floating-point format, and conversions to and from IEEE single- + * precision floating-point format. + * + * In 1991, Ken Turkowski implemented the conversions to and from + * IEEE double-precision format, added more precision to the extended + * conversions, and accommodated conversions involving +/- infinity, + * NaN's, and denormalized numbers. + */ + +#ifndef HUGE_VAL +# define HUGE_VAL HUGE +#endif /*HUGE_VAL*/ + + +/**************************************************************** + * The following two routines make up for deficiencies in many + * compilers to convert properly between unsigned integers and + * floating-point. Some compilers which have this bug are the + * THINK_C compiler for the Macintosh and the C compiler for the + * Silicon Graphics MIPS-based Iris. + ****************************************************************/ + +#ifdef applec /* The Apple C compiler works */ +# define FloatToUnsigned(f) ((wxUint32)(f)) +# define UnsignedToFloat(u) ((wxFloat64)(u)) +#else /*applec*/ +# define FloatToUnsigned(f) ((wxUint32)(((wxInt32)((f) - 2147483648.0)) + 2147483647L) + 1) +# define UnsignedToFloat(u) (((wxFloat64)((wxInt32)((u) - 2147483647L - 1))) + 2147483648.0) +#endif /*applec*/ + + + +/**************************************************************** + * Extended precision IEEE floating-point conversion routines. + * Extended is an 80-bit number as defined by Motorola, + * with a sign bit, 15 bits of exponent (offset 16383?), + * and a 64-bit mantissa, with no hidden bit. + ****************************************************************/ + +wxFloat64 ConvertFromIeeeExtended(const wxInt8 *bytes) +{ + wxFloat64 f; + wxInt32 expon; + wxUint32 hiMant, loMant; + + expon = ((bytes[0] & 0x7F) << 8) | (bytes[1] & 0xFF); + hiMant = ((wxUint32)(bytes[2] & 0xFF) << 24) + | ((wxUint32)(bytes[3] & 0xFF) << 16) + | ((wxUint32)(bytes[4] & 0xFF) << 8) + | ((wxUint32)(bytes[5] & 0xFF)); + loMant = ((wxUint32)(bytes[6] & 0xFF) << 24) + | ((wxUint32)(bytes[7] & 0xFF) << 16) + | ((wxUint32)(bytes[8] & 0xFF) << 8) + | ((wxUint32)(bytes[9] & 0xFF)); + + if (expon == 0 && hiMant == 0 && loMant == 0) { + f = 0; + } + else { + if (expon == 0x7FFF) { /* Infinity or NaN */ + f = HUGE_VAL; + } + else { + expon -= 16383; + f = ldexp(UnsignedToFloat(hiMant), expon-=31); + f += ldexp(UnsignedToFloat(loMant), expon-=32); + } + } + + if (bytes[0] & 0x80) + return -f; + else + return f; +} + + +/****************************************************************/ + + +void ConvertToIeeeExtended(wxFloat64 num, wxInt8 *bytes) +{ + wxInt32 sign; + wxInt32 expon; + wxFloat64 fMant, fsMant; + wxUint32 hiMant, loMant; + + if (num < 0) { + sign = 0x8000; + num *= -1; + } else { + sign = 0; + } + + if (num == 0) { + expon = 0; hiMant = 0; loMant = 0; + } + else { + fMant = frexp(num, &expon); + if ((expon > 16384) || !(fMant < 1)) { /* Infinity or NaN */ + expon = sign|0x7FFF; hiMant = 0; loMant = 0; /* infinity */ + } + else { /* Finite */ + expon += 16382; + if (expon < 0) { /* denormalized */ + fMant = ldexp(fMant, expon); + expon = 0; + } + expon |= sign; + fMant = ldexp(fMant, 32); fsMant = floor(fMant); hiMant = FloatToUnsigned(fsMant); + fMant = ldexp(fMant - fsMant, 32); fsMant = floor(fMant); loMant = FloatToUnsigned(fsMant); + } + } + + bytes[0] = expon >> 8; + bytes[1] = expon; + bytes[2] = hiMant >> 24; + bytes[3] = hiMant >> 16; + bytes[4] = hiMant >> 8; + bytes[5] = hiMant; + bytes[6] = loMant >> 24; + bytes[7] = loMant >> 16; + bytes[8] = loMant >> 8; + bytes[9] = loMant; +} + + + +#endif /* wxUSE_APPLE_IEEE */ diff --git a/Source/3rd Party/wx/src/common/fddlgcmn.cpp b/Source/3rd Party/wx/src/common/fddlgcmn.cpp index 11585c03c..64d9f91cc 100644 --- a/Source/3rd Party/wx/src/common/fddlgcmn.cpp +++ b/Source/3rd Party/wx/src/common/fddlgcmn.cpp @@ -1,102 +1,102 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fdrepdlg.cpp -// Purpose: common parts of wxFindReplaceDialog implementations -// Author: Vadim Zeitlin -// Modified by: -// Created: 01.08.01 -// RCS-ID: -// Copyright: (c) 2001 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FINDREPLDLG - -#ifndef WX_PRECOMP -#endif - -#include "wx/fdrepdlg.h" - -// ---------------------------------------------------------------------------- -// wxWin macros -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxFindDialogEvent, wxCommandEvent) - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_NEXT) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_REPLACE) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_REPLACE_ALL) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_CLOSE) - -// ============================================================================ -// implementations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxFindReplaceData -// ---------------------------------------------------------------------------- - -void wxFindReplaceData::Init() -{ - m_Flags = 0; -} - -// ---------------------------------------------------------------------------- -// wxFindReplaceDialogBase -// ---------------------------------------------------------------------------- - -wxFindReplaceDialogBase::~wxFindReplaceDialogBase() -{ -} - -void wxFindReplaceDialogBase::Send(wxFindDialogEvent& event) -{ - // we copy the data to dialog->GetData() as well - - m_FindReplaceData->m_Flags = event.GetFlags(); - m_FindReplaceData->m_FindWhat = event.GetFindString(); - if ( HasFlag(wxFR_REPLACEDIALOG) && - (event.GetEventType() == wxEVT_COMMAND_FIND_REPLACE || - event.GetEventType() == wxEVT_COMMAND_FIND_REPLACE_ALL) ) - { - m_FindReplaceData->m_ReplaceWith = event.GetReplaceString(); - } - - // translate wxEVT_COMMAND_FIND_NEXT to wxEVT_COMMAND_FIND if needed - if ( event.GetEventType() == wxEVT_COMMAND_FIND_NEXT ) - { - if ( m_FindReplaceData->m_FindWhat != m_lastSearch ) - { - event.SetEventType(wxEVT_COMMAND_FIND); - - m_lastSearch = m_FindReplaceData->m_FindWhat; - } - } - - if ( !GetEventHandler()->ProcessEvent(event) ) - { - // the event is not propagated upwards to the parent automatically - // because the dialog is a top level window, so do it manually as - // in 9 cases of 10 the message must be processed by the dialog - // owner and not the dialog itself - (void)GetParent()->GetEventHandler()->ProcessEvent(event); - } -} - -#endif // wxUSE_FINDREPLDLG - +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fdrepdlg.cpp +// Purpose: common parts of wxFindReplaceDialog implementations +// Author: Vadim Zeitlin +// Modified by: +// Created: 01.08.01 +// RCS-ID: +// Copyright: (c) 2001 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FINDREPLDLG + +#ifndef WX_PRECOMP +#endif + +#include "wx/fdrepdlg.h" + +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxFindDialogEvent, wxCommandEvent) + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_NEXT) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_REPLACE) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_REPLACE_ALL) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_FIND_CLOSE) + +// ============================================================================ +// implementations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxFindReplaceData +// ---------------------------------------------------------------------------- + +void wxFindReplaceData::Init() +{ + m_Flags = 0; +} + +// ---------------------------------------------------------------------------- +// wxFindReplaceDialogBase +// ---------------------------------------------------------------------------- + +wxFindReplaceDialogBase::~wxFindReplaceDialogBase() +{ +} + +void wxFindReplaceDialogBase::Send(wxFindDialogEvent& event) +{ + // we copy the data to dialog->GetData() as well + + m_FindReplaceData->m_Flags = event.GetFlags(); + m_FindReplaceData->m_FindWhat = event.GetFindString(); + if ( HasFlag(wxFR_REPLACEDIALOG) && + (event.GetEventType() == wxEVT_COMMAND_FIND_REPLACE || + event.GetEventType() == wxEVT_COMMAND_FIND_REPLACE_ALL) ) + { + m_FindReplaceData->m_ReplaceWith = event.GetReplaceString(); + } + + // translate wxEVT_COMMAND_FIND_NEXT to wxEVT_COMMAND_FIND if needed + if ( event.GetEventType() == wxEVT_COMMAND_FIND_NEXT ) + { + if ( m_FindReplaceData->m_FindWhat != m_lastSearch ) + { + event.SetEventType(wxEVT_COMMAND_FIND); + + m_lastSearch = m_FindReplaceData->m_FindWhat; + } + } + + if ( !GetEventHandler()->ProcessEvent(event) ) + { + // the event is not propagated upwards to the parent automatically + // because the dialog is a top level window, so do it manually as + // in 9 cases of 10 the message must be processed by the dialog + // owner and not the dialog itself + (void)GetParent()->GetEventHandler()->ProcessEvent(event); + } +} + +#endif // wxUSE_FINDREPLDLG + diff --git a/Source/3rd Party/wx/src/common/ffile.cpp b/Source/3rd Party/wx/src/common/ffile.cpp index 7074dd5e0..92bc8ede9 100644 --- a/Source/3rd Party/wx/src/common/ffile.cpp +++ b/Source/3rd Party/wx/src/common/ffile.cpp @@ -1,256 +1,256 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: ffile.cpp -// Purpose: wxFFile encapsulates "FILE *" IO stream -// Author: Vadim Zeitlin -// Modified by: -// Created: 14.07.99 -// RCS-ID: $Id: ffile.cpp 63300 2010-01-28 21:36:09Z MW $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FFILE - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" -#endif - -#ifdef __WINDOWS__ -#include "wx/msw/mslu.h" -#endif - -#include "wx/ffile.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// opening the file -// ---------------------------------------------------------------------------- - -wxFFile::wxFFile(const wxChar *filename, const wxChar *mode) -{ - Detach(); - - (void)Open(filename, mode); -} - -bool wxFFile::Open(const wxChar *filename, const wxChar *mode) -{ - wxASSERT_MSG( !m_fp, wxT("should close or detach the old file first") ); - - m_fp = wxFopen(filename, mode); - - if ( !m_fp ) - { - wxLogSysError(_("can't open file '%s'"), filename); - - return false; - } - - m_name = filename; - - return true; -} - -bool wxFFile::Close() -{ - if ( IsOpened() ) - { - if ( fclose(m_fp) != 0 ) - { - wxLogSysError(_("can't close file '%s'"), m_name.c_str()); - - return false; - } - - Detach(); - } - - return true; -} - -// ---------------------------------------------------------------------------- -// read/write -// ---------------------------------------------------------------------------- - -bool wxFFile::ReadAll(wxString *str, const wxMBConv& conv) -{ - wxCHECK_MSG( str, false, wxT("invalid parameter") ); - wxCHECK_MSG( IsOpened(), false, wxT("can't read from closed file") ); - wxCHECK_MSG( Length() >= 0, false, wxT("invalid length") ); - size_t length = wx_truncate_cast(size_t, Length()); - wxCHECK_MSG( (wxFileOffset)length == Length(), false, wxT("huge file not supported") ); - - clearerr(m_fp); - - wxCharBuffer buf(length + 1); - - // note that real length may be less than file length for text files with DOS EOLs - // ('\r's get dropped by CRT when reading which means that we have - // realLen = fileLen - numOfLinesInTheFile) - length = fread(buf.data(), sizeof(char), length, m_fp); - - if ( Error() ) - { - wxLogSysError(_("Read error on file '%s'"), m_name.c_str()); - - return false; - } - - buf.data()[length] = 0; - *str = wxString(buf, conv); - - return true; -} - -size_t wxFFile::Read(void *pBuf, size_t nCount) -{ - wxCHECK_MSG( pBuf, 0, wxT("invalid parameter") ); - wxCHECK_MSG( IsOpened(), 0, wxT("can't read from closed file") ); - - size_t nRead = fread(pBuf, 1, nCount, m_fp); - if ( (nRead < nCount) && Error() ) - { - wxLogSysError(_("Read error on file '%s'"), m_name.c_str()); - } - - return nRead; -} - -size_t wxFFile::Write(const void *pBuf, size_t nCount) -{ - wxCHECK_MSG( pBuf, 0, wxT("invalid parameter") ); - wxCHECK_MSG( IsOpened(), 0, wxT("can't write to closed file") ); - - size_t nWritten = fwrite(pBuf, 1, nCount, m_fp); - if ( nWritten < nCount ) - { - wxLogSysError(_("Write error on file '%s'"), m_name.c_str()); - } - - return nWritten; -} - -bool wxFFile::Flush() -{ - if ( IsOpened() ) - { - // fflush returns non-zero on error - // - if ( fflush(m_fp) ) - { - wxLogSysError(_("failed to flush the file '%s'"), m_name.c_str()); - - return false; - } - } - - return true; -} - -// ---------------------------------------------------------------------------- -// seeking -// ---------------------------------------------------------------------------- - -bool wxFFile::Seek(wxFileOffset ofs, wxSeekMode mode) -{ - wxCHECK_MSG( IsOpened(), false, wxT("can't seek on closed file") ); - - int origin; - switch ( mode ) - { - default: - wxFAIL_MSG(wxT("unknown seek mode")); - // still fall through - - case wxFromStart: - origin = SEEK_SET; - break; - - case wxFromCurrent: - origin = SEEK_CUR; - break; - - case wxFromEnd: - origin = SEEK_END; - break; - } - -#ifndef wxHAS_LARGE_FFILES - if ((long)ofs != ofs) - { - wxLogError(_("Seek error on file '%s' (large files not supported by stdio)"), m_name.c_str()); - - return false; - } - - if ( wxFseek(m_fp, (long)ofs, origin) != 0 ) -#else - if ( wxFseek(m_fp, ofs, origin) != 0 ) -#endif - { - wxLogSysError(_("Seek error on file '%s'"), m_name.c_str()); - - return false; - } - - return true; -} - -wxFileOffset wxFFile::Tell() const -{ - wxCHECK_MSG( IsOpened(), wxInvalidOffset, - _T("wxFFile::Tell(): file is closed!") ); - - wxFileOffset rc = wxFtell(m_fp); - if ( rc == wxInvalidOffset ) - { - wxLogSysError(_("Can't find current position in file '%s'"), - m_name.c_str()); - } - - return rc; -} - -wxFileOffset wxFFile::Length() const -{ - wxCHECK_MSG( IsOpened(), wxInvalidOffset, - _T("wxFFile::Length(): file is closed!") ); - - wxFFile& self = *(wxFFile *)this; // const_cast - - wxFileOffset posOld = Tell(); - if ( posOld != wxInvalidOffset ) - { - if ( self.SeekEnd() ) - { - wxFileOffset len = Tell(); - - (void)self.Seek(posOld); - - return len; - } - } - - return wxInvalidOffset; -} - -#endif // wxUSE_FFILE +///////////////////////////////////////////////////////////////////////////// +// Name: ffile.cpp +// Purpose: wxFFile encapsulates "FILE *" IO stream +// Author: Vadim Zeitlin +// Modified by: +// Created: 14.07.99 +// RCS-ID: $Id: ffile.cpp 63300 2010-01-28 21:36:09Z MW $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FFILE + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" +#endif + +#ifdef __WINDOWS__ +#include "wx/msw/mslu.h" +#endif + +#include "wx/ffile.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// opening the file +// ---------------------------------------------------------------------------- + +wxFFile::wxFFile(const wxChar *filename, const wxChar *mode) +{ + Detach(); + + (void)Open(filename, mode); +} + +bool wxFFile::Open(const wxChar *filename, const wxChar *mode) +{ + wxASSERT_MSG( !m_fp, wxT("should close or detach the old file first") ); + + m_fp = wxFopen(filename, mode); + + if ( !m_fp ) + { + wxLogSysError(_("can't open file '%s'"), filename); + + return false; + } + + m_name = filename; + + return true; +} + +bool wxFFile::Close() +{ + if ( IsOpened() ) + { + if ( fclose(m_fp) != 0 ) + { + wxLogSysError(_("can't close file '%s'"), m_name.c_str()); + + return false; + } + + Detach(); + } + + return true; +} + +// ---------------------------------------------------------------------------- +// read/write +// ---------------------------------------------------------------------------- + +bool wxFFile::ReadAll(wxString *str, const wxMBConv& conv) +{ + wxCHECK_MSG( str, false, wxT("invalid parameter") ); + wxCHECK_MSG( IsOpened(), false, wxT("can't read from closed file") ); + wxCHECK_MSG( Length() >= 0, false, wxT("invalid length") ); + size_t length = wx_truncate_cast(size_t, Length()); + wxCHECK_MSG( (wxFileOffset)length == Length(), false, wxT("huge file not supported") ); + + clearerr(m_fp); + + wxCharBuffer buf(length + 1); + + // note that real length may be less than file length for text files with DOS EOLs + // ('\r's get dropped by CRT when reading which means that we have + // realLen = fileLen - numOfLinesInTheFile) + length = fread(buf.data(), sizeof(char), length, m_fp); + + if ( Error() ) + { + wxLogSysError(_("Read error on file '%s'"), m_name.c_str()); + + return false; + } + + buf.data()[length] = 0; + *str = wxString(buf, conv); + + return true; +} + +size_t wxFFile::Read(void *pBuf, size_t nCount) +{ + wxCHECK_MSG( pBuf, 0, wxT("invalid parameter") ); + wxCHECK_MSG( IsOpened(), 0, wxT("can't read from closed file") ); + + size_t nRead = fread(pBuf, 1, nCount, m_fp); + if ( (nRead < nCount) && Error() ) + { + wxLogSysError(_("Read error on file '%s'"), m_name.c_str()); + } + + return nRead; +} + +size_t wxFFile::Write(const void *pBuf, size_t nCount) +{ + wxCHECK_MSG( pBuf, 0, wxT("invalid parameter") ); + wxCHECK_MSG( IsOpened(), 0, wxT("can't write to closed file") ); + + size_t nWritten = fwrite(pBuf, 1, nCount, m_fp); + if ( nWritten < nCount ) + { + wxLogSysError(_("Write error on file '%s'"), m_name.c_str()); + } + + return nWritten; +} + +bool wxFFile::Flush() +{ + if ( IsOpened() ) + { + // fflush returns non-zero on error + // + if ( fflush(m_fp) ) + { + wxLogSysError(_("failed to flush the file '%s'"), m_name.c_str()); + + return false; + } + } + + return true; +} + +// ---------------------------------------------------------------------------- +// seeking +// ---------------------------------------------------------------------------- + +bool wxFFile::Seek(wxFileOffset ofs, wxSeekMode mode) +{ + wxCHECK_MSG( IsOpened(), false, wxT("can't seek on closed file") ); + + int origin; + switch ( mode ) + { + default: + wxFAIL_MSG(wxT("unknown seek mode")); + // still fall through + + case wxFromStart: + origin = SEEK_SET; + break; + + case wxFromCurrent: + origin = SEEK_CUR; + break; + + case wxFromEnd: + origin = SEEK_END; + break; + } + +#ifndef wxHAS_LARGE_FFILES + if ((long)ofs != ofs) + { + wxLogError(_("Seek error on file '%s' (large files not supported by stdio)"), m_name.c_str()); + + return false; + } + + if ( wxFseek(m_fp, (long)ofs, origin) != 0 ) +#else + if ( wxFseek(m_fp, ofs, origin) != 0 ) +#endif + { + wxLogSysError(_("Seek error on file '%s'"), m_name.c_str()); + + return false; + } + + return true; +} + +wxFileOffset wxFFile::Tell() const +{ + wxCHECK_MSG( IsOpened(), wxInvalidOffset, + _T("wxFFile::Tell(): file is closed!") ); + + wxFileOffset rc = wxFtell(m_fp); + if ( rc == wxInvalidOffset ) + { + wxLogSysError(_("Can't find current position in file '%s'"), + m_name.c_str()); + } + + return rc; +} + +wxFileOffset wxFFile::Length() const +{ + wxCHECK_MSG( IsOpened(), wxInvalidOffset, + _T("wxFFile::Length(): file is closed!") ); + + wxFFile& self = *(wxFFile *)this; // const_cast + + wxFileOffset posOld = Tell(); + if ( posOld != wxInvalidOffset ) + { + if ( self.SeekEnd() ) + { + wxFileOffset len = Tell(); + + (void)self.Seek(posOld); + + return len; + } + } + + return wxInvalidOffset; +} + +#endif // wxUSE_FFILE diff --git a/Source/3rd Party/wx/src/common/file.cpp b/Source/3rd Party/wx/src/common/file.cpp index 7b5427460..26f0ce80d 100644 --- a/Source/3rd Party/wx/src/common/file.cpp +++ b/Source/3rd Party/wx/src/common/file.cpp @@ -1,559 +1,559 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: file.cpp -// Purpose: wxFile - encapsulates low-level "file descriptor" -// wxTempFile -// Author: Vadim Zeitlin -// Modified by: -// Created: 29/01/98 -// RCS-ID: $Id: file.cpp 42876 2006-10-31 23:29:02Z SN $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FILE - -// standard -#if defined(__WXMSW__) && !defined(__GNUWIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) - -#ifndef __SALFORDC__ - #define WIN32_LEAN_AND_MEAN - #define NOSERVICE - #define NOIME - #define NOATOM - #define NOGDI - #define NOGDICAPMASKS - #define NOMETAFILE - #define NOMINMAX - #define NOMSG - #define NOOPENFILE - #define NORASTEROPS - #define NOSCROLL - #define NOSOUND - #define NOSYSMETRICS - #define NOTEXTMETRIC - #define NOWH - #define NOCOMM - #define NOKANJI - #define NOCRYPT - #define NOMCX -#endif - -#elif defined(__WXMSW__) && defined(__WXWINCE__) - #include "wx/msw/missing.h" -#elif (defined(__OS2__)) - #include -#elif (defined(__UNIX__) || defined(__GNUWIN32__)) - #include - #include - #include - #ifdef __GNUWIN32__ - #include "wx/msw/wrapwin.h" - #endif -#elif defined(__DOS__) - #if defined(__WATCOMC__) - #include - #elif defined(__DJGPP__) - #include - #include - #include - #else - #error "Please specify the header with file functions declarations." - #endif -#elif (defined(__WXSTUBS__)) - // Have to ifdef this for different environments - #include -#elif (defined(__WXMAC__)) -#if __MSL__ < 0x6000 - int access( const char *path, int mode ) { return 0 ; } -#else - int _access( const char *path, int mode ) { return 0 ; } -#endif - char* mktemp( char * path ) { return path ;} - #include - #include -#else - #error "Please specify the header with file functions declarations." -#endif //Win/UNIX - -#include // SEEK_xxx constants - -// Windows compilers don't have these constants -#ifndef W_OK - enum - { - F_OK = 0, // test for existence - X_OK = 1, // execute permission - W_OK = 2, // write - R_OK = 4 // read - }; -#endif // W_OK - -#ifdef __SALFORDC__ - #include -#endif - -// some broken compilers don't have 3rd argument in open() and creat() -#ifdef __SALFORDC__ - #define ACCESS(access) - #define stat _stat -#else // normal compiler - #define ACCESS(access) , (access) -#endif // Salford C - -// wxWidgets -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/log.h" -#endif // !WX_PRECOMP - -#include "wx/filename.h" -#include "wx/file.h" -#include "wx/filefn.h" - -// there is no distinction between text and binary files under Unix, so define -// O_BINARY as 0 if the system headers don't do it already -#if defined(__UNIX__) && !defined(O_BINARY) - #define O_BINARY (0) -#endif //__UNIX__ - -#ifdef __WXMSW__ - #include "wx/msw/mslu.h" -#endif - -#ifdef __WXWINCE__ - #include "wx/msw/private.h" -#endif - -#ifndef MAX_PATH - #define MAX_PATH 512 -#endif - -// ============================================================================ -// implementation of wxFile -// ============================================================================ - -// ---------------------------------------------------------------------------- -// static functions -// ---------------------------------------------------------------------------- - -bool wxFile::Exists(const wxChar *name) -{ - return wxFileExists(name); -} - -bool wxFile::Access(const wxChar *name, OpenMode mode) -{ - int how; - - switch ( mode ) - { - default: - wxFAIL_MSG(wxT("bad wxFile::Access mode parameter.")); - // fall through - - case read: - how = R_OK; - break; - - case write: - how = W_OK; - break; - - case read_write: - how = R_OK | W_OK; - break; - } - - return wxAccess(name, how) == 0; -} - -// ---------------------------------------------------------------------------- -// opening/closing -// ---------------------------------------------------------------------------- - -// ctors -wxFile::wxFile(const wxChar *szFileName, OpenMode mode) -{ - m_fd = fd_invalid; - m_error = false; - - Open(szFileName, mode); -} - -// create the file, fail if it already exists and bOverwrite -bool wxFile::Create(const wxChar *szFileName, bool bOverwrite, int accessMode) -{ - // if bOverwrite we create a new file or truncate the existing one, - // otherwise we only create the new file and fail if it already exists -#if defined(__WXMAC__) && !defined(__UNIX__) && !wxUSE_UNICODE - // Dominic Mazzoni [dmazzoni+@cs.cmu.edu] reports that open is still broken on the mac, so we replace - // int fd = open( szFileName , O_CREAT | (bOverwrite ? O_TRUNC : O_EXCL), access); - int fd = creat( szFileName , accessMode); -#else - int fd = wxOpen( szFileName, - O_BINARY | O_WRONLY | O_CREAT | - (bOverwrite ? O_TRUNC : O_EXCL) - ACCESS(accessMode) ); -#endif - if ( fd == -1 ) - { - wxLogSysError(_("can't create file '%s'"), szFileName); - return false; - } - - Attach(fd); - return true; -} - -// open the file -bool wxFile::Open(const wxChar *szFileName, OpenMode mode, int accessMode) -{ - int flags = O_BINARY; - - switch ( mode ) - { - case read: - flags |= O_RDONLY; - break; - - case write_append: - if ( wxFile::Exists(szFileName) ) - { - flags |= O_WRONLY | O_APPEND; - break; - } - //else: fall through as write_append is the same as write if the - // file doesn't exist - - case write: - flags |= O_WRONLY | O_CREAT | O_TRUNC; - break; - - case write_excl: - flags |= O_WRONLY | O_CREAT | O_EXCL; - break; - - case read_write: - flags |= O_RDWR; - break; - } - -#ifdef __WINDOWS__ - // only read/write bits for "all" are supported by this function under - // Windows, and VC++ 8 returns EINVAL if any other bits are used in - // accessMode, so clear them as they have at best no effect anyhow - accessMode &= wxS_IRUSR | wxS_IWUSR; -#endif // __WINDOWS__ - - int fd = wxOpen( szFileName, flags ACCESS(accessMode)); - - if ( fd == -1 ) - { - wxLogSysError(_("can't open file '%s'"), szFileName); - return false; - } - - Attach(fd); - return true; -} - -// close -bool wxFile::Close() -{ - if ( IsOpened() ) { - if (wxClose(m_fd) == -1) - { - wxLogSysError(_("can't close file descriptor %d"), m_fd); - m_fd = fd_invalid; - return false; - } - else - m_fd = fd_invalid; - } - - return true; -} - -// ---------------------------------------------------------------------------- -// read/write -// ---------------------------------------------------------------------------- - -// read -ssize_t wxFile::Read(void *pBuf, size_t nCount) -{ - wxCHECK( (pBuf != NULL) && IsOpened(), 0 ); - - ssize_t iRc = wxRead(m_fd, pBuf, nCount); - - if ( iRc == -1 ) - { - wxLogSysError(_("can't read from file descriptor %d"), m_fd); - return wxInvalidOffset; - } - - return iRc; -} - -// write -size_t wxFile::Write(const void *pBuf, size_t nCount) -{ - wxCHECK( (pBuf != NULL) && IsOpened(), 0 ); - - ssize_t iRc = wxWrite(m_fd, pBuf, nCount); - - if ( iRc == -1 ) - { - wxLogSysError(_("can't write to file descriptor %d"), m_fd); - m_error = true; - iRc = 0; - } - - return iRc; -} - -// flush -bool wxFile::Flush() -{ -#ifdef HAVE_FSYNC - // fsync() only works on disk files and returns errors for pipes, don't - // call it then - if ( IsOpened() && GetKind() == wxFILE_KIND_DISK ) - { - if ( wxFsync(m_fd) == -1 ) - { - wxLogSysError(_("can't flush file descriptor %d"), m_fd); - return false; - } - } -#endif // HAVE_FSYNC - - return true; -} - -// ---------------------------------------------------------------------------- -// seek -// ---------------------------------------------------------------------------- - -// seek -wxFileOffset wxFile::Seek(wxFileOffset ofs, wxSeekMode mode) -{ - wxASSERT_MSG( IsOpened(), _T("can't seek on closed file") ); - wxCHECK_MSG( ofs != wxInvalidOffset || mode != wxFromStart, - wxInvalidOffset, - _T("invalid absolute file offset") ); - - int origin; - switch ( mode ) { - default: - wxFAIL_MSG(_("unknown seek origin")); - - case wxFromStart: - origin = SEEK_SET; - break; - - case wxFromCurrent: - origin = SEEK_CUR; - break; - - case wxFromEnd: - origin = SEEK_END; - break; - } - - wxFileOffset iRc = wxSeek(m_fd, ofs, origin); - if ( iRc == wxInvalidOffset ) - { - wxLogSysError(_("can't seek on file descriptor %d"), m_fd); - } - - return iRc; -} - -// get current file offset -wxFileOffset wxFile::Tell() const -{ - wxASSERT( IsOpened() ); - - wxFileOffset iRc = wxTell(m_fd); - if ( iRc == wxInvalidOffset ) - { - wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd); - } - - return iRc; -} - -// get current file length -wxFileOffset wxFile::Length() const -{ - wxASSERT( IsOpened() ); - - wxFileOffset iRc = Tell(); - if ( iRc != wxInvalidOffset ) { - // have to use const_cast :-( - wxFileOffset iLen = ((wxFile *)this)->SeekEnd(); - if ( iLen != wxInvalidOffset ) { - // restore old position - if ( ((wxFile *)this)->Seek(iRc) == wxInvalidOffset ) { - // error - iLen = wxInvalidOffset; - } - } - - iRc = iLen; - } - - if ( iRc == wxInvalidOffset ) - { - wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd); - } - - return iRc; -} - -// is end of file reached? -bool wxFile::Eof() const -{ - wxASSERT( IsOpened() ); - - wxFileOffset iRc; - -#if defined(__DOS__) || defined(__UNIX__) || defined(__GNUWIN32__) || defined( __MWERKS__ ) || defined(__SALFORDC__) - // @@ this doesn't work, of course, on unseekable file descriptors - wxFileOffset ofsCur = Tell(), - ofsMax = Length(); - if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset ) - iRc = wxInvalidOffset; - else - iRc = ofsCur == ofsMax; -#else // Windows and "native" compiler - iRc = wxEof(m_fd); -#endif // Windows/Unix - - if ( iRc == 1) - {} - else if ( iRc == 0 ) - return false; - else if ( iRc == wxInvalidOffset ) - wxLogSysError(_("can't determine if the end of file is reached on descriptor %d"), m_fd); - else - wxFAIL_MSG(_("invalid eof() return value.")); - - return true; -} - -// ============================================================================ -// implementation of wxTempFile -// ============================================================================ - -// ---------------------------------------------------------------------------- -// construction -// ---------------------------------------------------------------------------- - -wxTempFile::wxTempFile(const wxString& strName) -{ - Open(strName); -} - -bool wxTempFile::Open(const wxString& strName) -{ - // we must have an absolute filename because otherwise CreateTempFileName() - // would create the temp file in $TMP (i.e. the system standard location - // for the temp files) which might be on another volume/drive/mount and - // wxRename()ing it later to m_strName from Commit() would then fail - // - // with the absolute filename, the temp file is created in the same - // directory as this one which ensures that wxRename() may work later - wxFileName fn(strName); - if ( !fn.IsAbsolute() ) - { - fn.Normalize(wxPATH_NORM_ABSOLUTE); - } - - m_strName = fn.GetFullPath(); - - m_strTemp = wxFileName::CreateTempFileName(m_strName, &m_file); - - if ( m_strTemp.empty() ) - { - // CreateTempFileName() failed - return false; - } - -#ifdef __UNIX__ - // the temp file should have the same permissions as the original one - mode_t mode; - - wxStructStat st; - if ( stat( (const char*) m_strName.fn_str(), &st) == 0 ) - { - mode = st.st_mode; - } - else - { - // file probably didn't exist, just give it the default mode _using_ - // user's umask (new files creation should respect umask) - mode_t mask = umask(0777); - mode = 0666 & ~mask; - umask(mask); - } - - if ( chmod( (const char*) m_strTemp.fn_str(), mode) == -1 ) - { -#ifndef __OS2__ - wxLogSysError(_("Failed to set temporary file permissions")); -#endif - } -#endif // Unix - - return true; -} - -// ---------------------------------------------------------------------------- -// destruction -// ---------------------------------------------------------------------------- - -wxTempFile::~wxTempFile() -{ - if ( IsOpened() ) - Discard(); -} - -bool wxTempFile::Commit() -{ - m_file.Close(); - - if ( wxFile::Exists(m_strName) && wxRemove(m_strName) != 0 ) { - wxLogSysError(_("can't remove file '%s'"), m_strName.c_str()); - return false; - } - - if ( !wxRenameFile(m_strTemp, m_strName) ) { - wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str()); - return false; - } - - return true; -} - -void wxTempFile::Discard() -{ - m_file.Close(); - if ( wxRemove(m_strTemp) != 0 ) - wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str()); -} - -#endif // wxUSE_FILE - +///////////////////////////////////////////////////////////////////////////// +// Name: file.cpp +// Purpose: wxFile - encapsulates low-level "file descriptor" +// wxTempFile +// Author: Vadim Zeitlin +// Modified by: +// Created: 29/01/98 +// RCS-ID: $Id: file.cpp 42876 2006-10-31 23:29:02Z SN $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FILE + +// standard +#if defined(__WXMSW__) && !defined(__GNUWIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) + +#ifndef __SALFORDC__ + #define WIN32_LEAN_AND_MEAN + #define NOSERVICE + #define NOIME + #define NOATOM + #define NOGDI + #define NOGDICAPMASKS + #define NOMETAFILE + #define NOMINMAX + #define NOMSG + #define NOOPENFILE + #define NORASTEROPS + #define NOSCROLL + #define NOSOUND + #define NOSYSMETRICS + #define NOTEXTMETRIC + #define NOWH + #define NOCOMM + #define NOKANJI + #define NOCRYPT + #define NOMCX +#endif + +#elif defined(__WXMSW__) && defined(__WXWINCE__) + #include "wx/msw/missing.h" +#elif (defined(__OS2__)) + #include +#elif (defined(__UNIX__) || defined(__GNUWIN32__)) + #include + #include + #include + #ifdef __GNUWIN32__ + #include "wx/msw/wrapwin.h" + #endif +#elif defined(__DOS__) + #if defined(__WATCOMC__) + #include + #elif defined(__DJGPP__) + #include + #include + #include + #else + #error "Please specify the header with file functions declarations." + #endif +#elif (defined(__WXSTUBS__)) + // Have to ifdef this for different environments + #include +#elif (defined(__WXMAC__)) +#if __MSL__ < 0x6000 + int access( const char *path, int mode ) { return 0 ; } +#else + int _access( const char *path, int mode ) { return 0 ; } +#endif + char* mktemp( char * path ) { return path ;} + #include + #include +#else + #error "Please specify the header with file functions declarations." +#endif //Win/UNIX + +#include // SEEK_xxx constants + +// Windows compilers don't have these constants +#ifndef W_OK + enum + { + F_OK = 0, // test for existence + X_OK = 1, // execute permission + W_OK = 2, // write + R_OK = 4 // read + }; +#endif // W_OK + +#ifdef __SALFORDC__ + #include +#endif + +// some broken compilers don't have 3rd argument in open() and creat() +#ifdef __SALFORDC__ + #define ACCESS(access) + #define stat _stat +#else // normal compiler + #define ACCESS(access) , (access) +#endif // Salford C + +// wxWidgets +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" +#endif // !WX_PRECOMP + +#include "wx/filename.h" +#include "wx/file.h" +#include "wx/filefn.h" + +// there is no distinction between text and binary files under Unix, so define +// O_BINARY as 0 if the system headers don't do it already +#if defined(__UNIX__) && !defined(O_BINARY) + #define O_BINARY (0) +#endif //__UNIX__ + +#ifdef __WXMSW__ + #include "wx/msw/mslu.h" +#endif + +#ifdef __WXWINCE__ + #include "wx/msw/private.h" +#endif + +#ifndef MAX_PATH + #define MAX_PATH 512 +#endif + +// ============================================================================ +// implementation of wxFile +// ============================================================================ + +// ---------------------------------------------------------------------------- +// static functions +// ---------------------------------------------------------------------------- + +bool wxFile::Exists(const wxChar *name) +{ + return wxFileExists(name); +} + +bool wxFile::Access(const wxChar *name, OpenMode mode) +{ + int how; + + switch ( mode ) + { + default: + wxFAIL_MSG(wxT("bad wxFile::Access mode parameter.")); + // fall through + + case read: + how = R_OK; + break; + + case write: + how = W_OK; + break; + + case read_write: + how = R_OK | W_OK; + break; + } + + return wxAccess(name, how) == 0; +} + +// ---------------------------------------------------------------------------- +// opening/closing +// ---------------------------------------------------------------------------- + +// ctors +wxFile::wxFile(const wxChar *szFileName, OpenMode mode) +{ + m_fd = fd_invalid; + m_error = false; + + Open(szFileName, mode); +} + +// create the file, fail if it already exists and bOverwrite +bool wxFile::Create(const wxChar *szFileName, bool bOverwrite, int accessMode) +{ + // if bOverwrite we create a new file or truncate the existing one, + // otherwise we only create the new file and fail if it already exists +#if defined(__WXMAC__) && !defined(__UNIX__) && !wxUSE_UNICODE + // Dominic Mazzoni [dmazzoni+@cs.cmu.edu] reports that open is still broken on the mac, so we replace + // int fd = open( szFileName , O_CREAT | (bOverwrite ? O_TRUNC : O_EXCL), access); + int fd = creat( szFileName , accessMode); +#else + int fd = wxOpen( szFileName, + O_BINARY | O_WRONLY | O_CREAT | + (bOverwrite ? O_TRUNC : O_EXCL) + ACCESS(accessMode) ); +#endif + if ( fd == -1 ) + { + wxLogSysError(_("can't create file '%s'"), szFileName); + return false; + } + + Attach(fd); + return true; +} + +// open the file +bool wxFile::Open(const wxChar *szFileName, OpenMode mode, int accessMode) +{ + int flags = O_BINARY; + + switch ( mode ) + { + case read: + flags |= O_RDONLY; + break; + + case write_append: + if ( wxFile::Exists(szFileName) ) + { + flags |= O_WRONLY | O_APPEND; + break; + } + //else: fall through as write_append is the same as write if the + // file doesn't exist + + case write: + flags |= O_WRONLY | O_CREAT | O_TRUNC; + break; + + case write_excl: + flags |= O_WRONLY | O_CREAT | O_EXCL; + break; + + case read_write: + flags |= O_RDWR; + break; + } + +#ifdef __WINDOWS__ + // only read/write bits for "all" are supported by this function under + // Windows, and VC++ 8 returns EINVAL if any other bits are used in + // accessMode, so clear them as they have at best no effect anyhow + accessMode &= wxS_IRUSR | wxS_IWUSR; +#endif // __WINDOWS__ + + int fd = wxOpen( szFileName, flags ACCESS(accessMode)); + + if ( fd == -1 ) + { + wxLogSysError(_("can't open file '%s'"), szFileName); + return false; + } + + Attach(fd); + return true; +} + +// close +bool wxFile::Close() +{ + if ( IsOpened() ) { + if (wxClose(m_fd) == -1) + { + wxLogSysError(_("can't close file descriptor %d"), m_fd); + m_fd = fd_invalid; + return false; + } + else + m_fd = fd_invalid; + } + + return true; +} + +// ---------------------------------------------------------------------------- +// read/write +// ---------------------------------------------------------------------------- + +// read +ssize_t wxFile::Read(void *pBuf, size_t nCount) +{ + wxCHECK( (pBuf != NULL) && IsOpened(), 0 ); + + ssize_t iRc = wxRead(m_fd, pBuf, nCount); + + if ( iRc == -1 ) + { + wxLogSysError(_("can't read from file descriptor %d"), m_fd); + return wxInvalidOffset; + } + + return iRc; +} + +// write +size_t wxFile::Write(const void *pBuf, size_t nCount) +{ + wxCHECK( (pBuf != NULL) && IsOpened(), 0 ); + + ssize_t iRc = wxWrite(m_fd, pBuf, nCount); + + if ( iRc == -1 ) + { + wxLogSysError(_("can't write to file descriptor %d"), m_fd); + m_error = true; + iRc = 0; + } + + return iRc; +} + +// flush +bool wxFile::Flush() +{ +#ifdef HAVE_FSYNC + // fsync() only works on disk files and returns errors for pipes, don't + // call it then + if ( IsOpened() && GetKind() == wxFILE_KIND_DISK ) + { + if ( wxFsync(m_fd) == -1 ) + { + wxLogSysError(_("can't flush file descriptor %d"), m_fd); + return false; + } + } +#endif // HAVE_FSYNC + + return true; +} + +// ---------------------------------------------------------------------------- +// seek +// ---------------------------------------------------------------------------- + +// seek +wxFileOffset wxFile::Seek(wxFileOffset ofs, wxSeekMode mode) +{ + wxASSERT_MSG( IsOpened(), _T("can't seek on closed file") ); + wxCHECK_MSG( ofs != wxInvalidOffset || mode != wxFromStart, + wxInvalidOffset, + _T("invalid absolute file offset") ); + + int origin; + switch ( mode ) { + default: + wxFAIL_MSG(_("unknown seek origin")); + + case wxFromStart: + origin = SEEK_SET; + break; + + case wxFromCurrent: + origin = SEEK_CUR; + break; + + case wxFromEnd: + origin = SEEK_END; + break; + } + + wxFileOffset iRc = wxSeek(m_fd, ofs, origin); + if ( iRc == wxInvalidOffset ) + { + wxLogSysError(_("can't seek on file descriptor %d"), m_fd); + } + + return iRc; +} + +// get current file offset +wxFileOffset wxFile::Tell() const +{ + wxASSERT( IsOpened() ); + + wxFileOffset iRc = wxTell(m_fd); + if ( iRc == wxInvalidOffset ) + { + wxLogSysError(_("can't get seek position on file descriptor %d"), m_fd); + } + + return iRc; +} + +// get current file length +wxFileOffset wxFile::Length() const +{ + wxASSERT( IsOpened() ); + + wxFileOffset iRc = Tell(); + if ( iRc != wxInvalidOffset ) { + // have to use const_cast :-( + wxFileOffset iLen = ((wxFile *)this)->SeekEnd(); + if ( iLen != wxInvalidOffset ) { + // restore old position + if ( ((wxFile *)this)->Seek(iRc) == wxInvalidOffset ) { + // error + iLen = wxInvalidOffset; + } + } + + iRc = iLen; + } + + if ( iRc == wxInvalidOffset ) + { + wxLogSysError(_("can't find length of file on file descriptor %d"), m_fd); + } + + return iRc; +} + +// is end of file reached? +bool wxFile::Eof() const +{ + wxASSERT( IsOpened() ); + + wxFileOffset iRc; + +#if defined(__DOS__) || defined(__UNIX__) || defined(__GNUWIN32__) || defined( __MWERKS__ ) || defined(__SALFORDC__) + // @@ this doesn't work, of course, on unseekable file descriptors + wxFileOffset ofsCur = Tell(), + ofsMax = Length(); + if ( ofsCur == wxInvalidOffset || ofsMax == wxInvalidOffset ) + iRc = wxInvalidOffset; + else + iRc = ofsCur == ofsMax; +#else // Windows and "native" compiler + iRc = wxEof(m_fd); +#endif // Windows/Unix + + if ( iRc == 1) + {} + else if ( iRc == 0 ) + return false; + else if ( iRc == wxInvalidOffset ) + wxLogSysError(_("can't determine if the end of file is reached on descriptor %d"), m_fd); + else + wxFAIL_MSG(_("invalid eof() return value.")); + + return true; +} + +// ============================================================================ +// implementation of wxTempFile +// ============================================================================ + +// ---------------------------------------------------------------------------- +// construction +// ---------------------------------------------------------------------------- + +wxTempFile::wxTempFile(const wxString& strName) +{ + Open(strName); +} + +bool wxTempFile::Open(const wxString& strName) +{ + // we must have an absolute filename because otherwise CreateTempFileName() + // would create the temp file in $TMP (i.e. the system standard location + // for the temp files) which might be on another volume/drive/mount and + // wxRename()ing it later to m_strName from Commit() would then fail + // + // with the absolute filename, the temp file is created in the same + // directory as this one which ensures that wxRename() may work later + wxFileName fn(strName); + if ( !fn.IsAbsolute() ) + { + fn.Normalize(wxPATH_NORM_ABSOLUTE); + } + + m_strName = fn.GetFullPath(); + + m_strTemp = wxFileName::CreateTempFileName(m_strName, &m_file); + + if ( m_strTemp.empty() ) + { + // CreateTempFileName() failed + return false; + } + +#ifdef __UNIX__ + // the temp file should have the same permissions as the original one + mode_t mode; + + wxStructStat st; + if ( stat( (const char*) m_strName.fn_str(), &st) == 0 ) + { + mode = st.st_mode; + } + else + { + // file probably didn't exist, just give it the default mode _using_ + // user's umask (new files creation should respect umask) + mode_t mask = umask(0777); + mode = 0666 & ~mask; + umask(mask); + } + + if ( chmod( (const char*) m_strTemp.fn_str(), mode) == -1 ) + { +#ifndef __OS2__ + wxLogSysError(_("Failed to set temporary file permissions")); +#endif + } +#endif // Unix + + return true; +} + +// ---------------------------------------------------------------------------- +// destruction +// ---------------------------------------------------------------------------- + +wxTempFile::~wxTempFile() +{ + if ( IsOpened() ) + Discard(); +} + +bool wxTempFile::Commit() +{ + m_file.Close(); + + if ( wxFile::Exists(m_strName) && wxRemove(m_strName) != 0 ) { + wxLogSysError(_("can't remove file '%s'"), m_strName.c_str()); + return false; + } + + if ( !wxRenameFile(m_strTemp, m_strName) ) { + wxLogSysError(_("can't commit changes to file '%s'"), m_strName.c_str()); + return false; + } + + return true; +} + +void wxTempFile::Discard() +{ + m_file.Close(); + if ( wxRemove(m_strTemp) != 0 ) + wxLogSysError(_("can't remove temporary file '%s'"), m_strTemp.c_str()); +} + +#endif // wxUSE_FILE + diff --git a/Source/3rd Party/wx/src/common/fileback.cpp b/Source/3rd Party/wx/src/common/fileback.cpp index 58fba90c0..ccce957bf 100644 --- a/Source/3rd Party/wx/src/common/fileback.cpp +++ b/Source/3rd Party/wx/src/common/fileback.cpp @@ -1,338 +1,338 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fileback.cpp -// Purpose: Back an input stream with memory or a file -// Author: Mike Wetherell -// RCS-ID: $Id: fileback.cpp 42651 2006-10-29 20:06:45Z MW $ -// Copyright: (c) 2006 Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FILESYSTEM - -#include "wx/private/fileback.h" - -#ifndef WX_PRECOMP - #include "wx/utils.h" - #include "wx/log.h" -#endif - -#include "wx/private/filename.h" - -// Prefer wxFFile unless wxFile has large file support but wxFFile does not. -// -#if wxUSE_FFILE && (defined wxHAS_LARGE_FFILES || !defined wxHAS_LARGE_FILES) -typedef wxFFile wxBFFile; -static const bool wxBadSeek = false; -#else -typedef wxFile wxBFFile; -static const wxFileOffset wxBadSeek = wxInvalidOffset; -#endif - -///////////////////////////////////////////////////////////////////////////// -// Backing file implementation - -class wxBackingFileImpl -{ -public: - wxBackingFileImpl(wxInputStream *stream, - size_t bufsize, - const wxString& prefix); - ~wxBackingFileImpl(); - - void Release() { if (--m_refcount == 0) delete this; } - wxBackingFileImpl *AddRef() { m_refcount++; return this; } - - wxStreamError ReadAt(wxFileOffset pos, void *buffer, size_t *size); - wxFileOffset GetLength() const; - -private: - int m_refcount; - - wxInputStream *m_stream; - wxStreamError m_parenterror; - - char *m_buf; - size_t m_bufsize; - size_t m_buflen; - - wxString m_prefix; - wxString m_filename; - wxBFFile m_file; - wxFileOffset m_filelen; -}; - -wxBackingFileImpl::wxBackingFileImpl(wxInputStream *stream, - size_t bufsize, - const wxString& prefix) - : m_refcount(1), - m_stream(stream), - m_parenterror(wxSTREAM_NO_ERROR), - m_buf(NULL), - m_bufsize(bufsize), - m_buflen(0), - m_prefix(prefix), - m_filelen(0) -{ - wxFileOffset len = m_stream->GetLength(); - - if (len >= 0 && len + size_t(1) < m_bufsize) - m_bufsize = size_t(len + 1); - - if (m_bufsize) - m_buf = new char[m_bufsize]; -} - -wxBackingFileImpl::~wxBackingFileImpl() -{ - delete m_stream; - delete [] m_buf; - - if (!m_filename.empty()) - wxRemoveFile(m_filename); -} - -wxStreamError wxBackingFileImpl::ReadAt(wxFileOffset pos, - void *buffer, - size_t *size) -{ - size_t reqestedSize = *size; - *size = 0; - - // size1 is the number of bytes it will read directly from the backing - // file. size2 is any remaining bytes not yet backed, these are returned - // from the buffer or read from the parent stream. - size_t size1, size2; - - if (pos + reqestedSize <= m_filelen + size_t(0)) { - size1 = reqestedSize; - size2 = 0; - } else if (pos < m_filelen) { - size1 = size_t(m_filelen - pos); - size2 = reqestedSize - size1; - } else { - size1 = 0; - size2 = reqestedSize; - } - - if (pos < 0) - return wxSTREAM_READ_ERROR; - - // read the backing file - if (size1) { - if (m_file.Seek(pos) == wxBadSeek) - return wxSTREAM_READ_ERROR; - - ssize_t n = m_file.Read(buffer, size1); - if (n > 0) { - *size = n; - pos += n; - } - - if (*size < size1) - return wxSTREAM_READ_ERROR; - } - - // read from the buffer or parent stream - if (size2) - { - while (*size < reqestedSize) - { - // if pos is further ahead than the parent has been read so far, - // then read forward in the parent stream - while (pos - m_filelen + size_t(0) >= m_buflen) - { - // if the parent is small enough, don't use a backing file - // just the buffer memory - if (!m_stream && m_filelen == 0) - return m_parenterror; - - // before refilling the buffer write out the current buffer - // to the backing file if there is anything in it - if (m_buflen) - { - if (!m_file.IsOpened()) - if (!wxCreateTempFile(m_prefix, &m_file, &m_filename)) - return wxSTREAM_READ_ERROR; - - if (m_file.Seek(m_filelen) == wxBadSeek) - return wxSTREAM_READ_ERROR; - - size_t count = m_file.Write(m_buf, m_buflen); - m_filelen += count; - - if (count < m_buflen) { - delete m_stream; - m_stream = NULL; - if (count > 0) { - delete[] m_buf; - m_buf = NULL; - m_buflen = 0; - } - m_parenterror = wxSTREAM_READ_ERROR; - return m_parenterror; - } - - m_buflen = 0; - - if (!m_stream) { - delete[] m_buf; - m_buf = NULL; - } - } - - if (!m_stream) - return m_parenterror; - - // refill buffer - m_buflen = m_stream->Read(m_buf, m_bufsize).LastRead(); - - if (m_buflen < m_bufsize) { - m_parenterror = m_stream->GetLastError(); - if (m_parenterror == wxSTREAM_NO_ERROR) - m_parenterror = wxSTREAM_EOF; - delete m_stream; - m_stream = NULL; - } - } - - // copy to the user's buffer - size_t start = size_t(pos - m_filelen); - size_t len = wxMin(m_buflen - start, reqestedSize - *size); - - memcpy((char*)buffer + *size, m_buf + start, len); - *size += len; - pos += len; - } - } - - return wxSTREAM_NO_ERROR; -} - -wxFileOffset wxBackingFileImpl::GetLength() const -{ - if (m_parenterror != wxSTREAM_EOF) { - wxLogNull nolog; - return m_stream->GetLength(); - } - return m_filelen + m_buflen; -} - - -///////////////////////////////////////////////////////////////////////////// -// Backing File, the handle part - -wxBackingFile::wxBackingFile(wxInputStream *stream, - size_t bufsize, - const wxString& prefix) - : m_impl(new wxBackingFileImpl(stream, bufsize, prefix)) -{ -} - -wxBackingFile::wxBackingFile(const wxBackingFile& backer) - : m_impl(backer.m_impl ? backer.m_impl->AddRef() : NULL) -{ -} - -wxBackingFile& wxBackingFile::operator=(const wxBackingFile& backer) -{ - if (backer.m_impl != m_impl) { - if (m_impl) - m_impl->Release(); - - m_impl = backer.m_impl; - - if (m_impl) - m_impl->AddRef(); - } - - return *this; -} - -wxBackingFile::~wxBackingFile() -{ - if (m_impl) - m_impl->Release(); -} - - -///////////////////////////////////////////////////////////////////////////// -// Input stream - -wxBackedInputStream::wxBackedInputStream(const wxBackingFile& backer) - : m_backer(backer), - m_pos(0) -{ -} - -wxFileOffset wxBackedInputStream::GetLength() const -{ - return m_backer.m_impl->GetLength(); -} - -wxFileOffset wxBackedInputStream::FindLength() const -{ - wxFileOffset len = GetLength(); - - if (len == wxInvalidOffset && IsOk()) { - // read a byte at 7ff...ffe - wxFileOffset pos = 1; - pos <<= sizeof(pos) * 8 - 1; - pos = ~pos - 1; - char ch; - size_t size = 1; - m_backer.m_impl->ReadAt(pos, &ch, &size); - len = GetLength(); - } - - return len; -} - -size_t wxBackedInputStream::OnSysRead(void *buffer, size_t size) -{ - if (!IsOk()) - return 0; - - m_lasterror = m_backer.m_impl->ReadAt(m_pos, buffer, &size); - m_pos += size; - return size; -} - -wxFileOffset wxBackedInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - switch (mode) { - case wxFromCurrent: - { - m_pos += pos; - break; - } - case wxFromEnd: - { - wxFileOffset len = GetLength(); - if (len == wxInvalidOffset) - return wxInvalidOffset; - m_pos = len + pos; - break; - } - default: - { - m_pos = pos; - break; - } - } - - return m_pos; -} - -wxFileOffset wxBackedInputStream::OnSysTell() const -{ - return m_pos; -} - -#endif // wxUSE_FILESYSTEM +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fileback.cpp +// Purpose: Back an input stream with memory or a file +// Author: Mike Wetherell +// RCS-ID: $Id: fileback.cpp 42651 2006-10-29 20:06:45Z MW $ +// Copyright: (c) 2006 Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FILESYSTEM + +#include "wx/private/fileback.h" + +#ifndef WX_PRECOMP + #include "wx/utils.h" + #include "wx/log.h" +#endif + +#include "wx/private/filename.h" + +// Prefer wxFFile unless wxFile has large file support but wxFFile does not. +// +#if wxUSE_FFILE && (defined wxHAS_LARGE_FFILES || !defined wxHAS_LARGE_FILES) +typedef wxFFile wxBFFile; +static const bool wxBadSeek = false; +#else +typedef wxFile wxBFFile; +static const wxFileOffset wxBadSeek = wxInvalidOffset; +#endif + +///////////////////////////////////////////////////////////////////////////// +// Backing file implementation + +class wxBackingFileImpl +{ +public: + wxBackingFileImpl(wxInputStream *stream, + size_t bufsize, + const wxString& prefix); + ~wxBackingFileImpl(); + + void Release() { if (--m_refcount == 0) delete this; } + wxBackingFileImpl *AddRef() { m_refcount++; return this; } + + wxStreamError ReadAt(wxFileOffset pos, void *buffer, size_t *size); + wxFileOffset GetLength() const; + +private: + int m_refcount; + + wxInputStream *m_stream; + wxStreamError m_parenterror; + + char *m_buf; + size_t m_bufsize; + size_t m_buflen; + + wxString m_prefix; + wxString m_filename; + wxBFFile m_file; + wxFileOffset m_filelen; +}; + +wxBackingFileImpl::wxBackingFileImpl(wxInputStream *stream, + size_t bufsize, + const wxString& prefix) + : m_refcount(1), + m_stream(stream), + m_parenterror(wxSTREAM_NO_ERROR), + m_buf(NULL), + m_bufsize(bufsize), + m_buflen(0), + m_prefix(prefix), + m_filelen(0) +{ + wxFileOffset len = m_stream->GetLength(); + + if (len >= 0 && len + size_t(1) < m_bufsize) + m_bufsize = size_t(len + 1); + + if (m_bufsize) + m_buf = new char[m_bufsize]; +} + +wxBackingFileImpl::~wxBackingFileImpl() +{ + delete m_stream; + delete [] m_buf; + + if (!m_filename.empty()) + wxRemoveFile(m_filename); +} + +wxStreamError wxBackingFileImpl::ReadAt(wxFileOffset pos, + void *buffer, + size_t *size) +{ + size_t reqestedSize = *size; + *size = 0; + + // size1 is the number of bytes it will read directly from the backing + // file. size2 is any remaining bytes not yet backed, these are returned + // from the buffer or read from the parent stream. + size_t size1, size2; + + if (pos + reqestedSize <= m_filelen + size_t(0)) { + size1 = reqestedSize; + size2 = 0; + } else if (pos < m_filelen) { + size1 = size_t(m_filelen - pos); + size2 = reqestedSize - size1; + } else { + size1 = 0; + size2 = reqestedSize; + } + + if (pos < 0) + return wxSTREAM_READ_ERROR; + + // read the backing file + if (size1) { + if (m_file.Seek(pos) == wxBadSeek) + return wxSTREAM_READ_ERROR; + + ssize_t n = m_file.Read(buffer, size1); + if (n > 0) { + *size = n; + pos += n; + } + + if (*size < size1) + return wxSTREAM_READ_ERROR; + } + + // read from the buffer or parent stream + if (size2) + { + while (*size < reqestedSize) + { + // if pos is further ahead than the parent has been read so far, + // then read forward in the parent stream + while (pos - m_filelen + size_t(0) >= m_buflen) + { + // if the parent is small enough, don't use a backing file + // just the buffer memory + if (!m_stream && m_filelen == 0) + return m_parenterror; + + // before refilling the buffer write out the current buffer + // to the backing file if there is anything in it + if (m_buflen) + { + if (!m_file.IsOpened()) + if (!wxCreateTempFile(m_prefix, &m_file, &m_filename)) + return wxSTREAM_READ_ERROR; + + if (m_file.Seek(m_filelen) == wxBadSeek) + return wxSTREAM_READ_ERROR; + + size_t count = m_file.Write(m_buf, m_buflen); + m_filelen += count; + + if (count < m_buflen) { + delete m_stream; + m_stream = NULL; + if (count > 0) { + delete[] m_buf; + m_buf = NULL; + m_buflen = 0; + } + m_parenterror = wxSTREAM_READ_ERROR; + return m_parenterror; + } + + m_buflen = 0; + + if (!m_stream) { + delete[] m_buf; + m_buf = NULL; + } + } + + if (!m_stream) + return m_parenterror; + + // refill buffer + m_buflen = m_stream->Read(m_buf, m_bufsize).LastRead(); + + if (m_buflen < m_bufsize) { + m_parenterror = m_stream->GetLastError(); + if (m_parenterror == wxSTREAM_NO_ERROR) + m_parenterror = wxSTREAM_EOF; + delete m_stream; + m_stream = NULL; + } + } + + // copy to the user's buffer + size_t start = size_t(pos - m_filelen); + size_t len = wxMin(m_buflen - start, reqestedSize - *size); + + memcpy((char*)buffer + *size, m_buf + start, len); + *size += len; + pos += len; + } + } + + return wxSTREAM_NO_ERROR; +} + +wxFileOffset wxBackingFileImpl::GetLength() const +{ + if (m_parenterror != wxSTREAM_EOF) { + wxLogNull nolog; + return m_stream->GetLength(); + } + return m_filelen + m_buflen; +} + + +///////////////////////////////////////////////////////////////////////////// +// Backing File, the handle part + +wxBackingFile::wxBackingFile(wxInputStream *stream, + size_t bufsize, + const wxString& prefix) + : m_impl(new wxBackingFileImpl(stream, bufsize, prefix)) +{ +} + +wxBackingFile::wxBackingFile(const wxBackingFile& backer) + : m_impl(backer.m_impl ? backer.m_impl->AddRef() : NULL) +{ +} + +wxBackingFile& wxBackingFile::operator=(const wxBackingFile& backer) +{ + if (backer.m_impl != m_impl) { + if (m_impl) + m_impl->Release(); + + m_impl = backer.m_impl; + + if (m_impl) + m_impl->AddRef(); + } + + return *this; +} + +wxBackingFile::~wxBackingFile() +{ + if (m_impl) + m_impl->Release(); +} + + +///////////////////////////////////////////////////////////////////////////// +// Input stream + +wxBackedInputStream::wxBackedInputStream(const wxBackingFile& backer) + : m_backer(backer), + m_pos(0) +{ +} + +wxFileOffset wxBackedInputStream::GetLength() const +{ + return m_backer.m_impl->GetLength(); +} + +wxFileOffset wxBackedInputStream::FindLength() const +{ + wxFileOffset len = GetLength(); + + if (len == wxInvalidOffset && IsOk()) { + // read a byte at 7ff...ffe + wxFileOffset pos = 1; + pos <<= sizeof(pos) * 8 - 1; + pos = ~pos - 1; + char ch; + size_t size = 1; + m_backer.m_impl->ReadAt(pos, &ch, &size); + len = GetLength(); + } + + return len; +} + +size_t wxBackedInputStream::OnSysRead(void *buffer, size_t size) +{ + if (!IsOk()) + return 0; + + m_lasterror = m_backer.m_impl->ReadAt(m_pos, buffer, &size); + m_pos += size; + return size; +} + +wxFileOffset wxBackedInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + switch (mode) { + case wxFromCurrent: + { + m_pos += pos; + break; + } + case wxFromEnd: + { + wxFileOffset len = GetLength(); + if (len == wxInvalidOffset) + return wxInvalidOffset; + m_pos = len + pos; + break; + } + default: + { + m_pos = pos; + break; + } + } + + return m_pos; +} + +wxFileOffset wxBackedInputStream::OnSysTell() const +{ + return m_pos; +} + +#endif // wxUSE_FILESYSTEM diff --git a/Source/3rd Party/wx/src/common/fileconf.cpp b/Source/3rd Party/wx/src/common/fileconf.cpp index d89f8a96f..c85ebe894 100644 --- a/Source/3rd Party/wx/src/common/fileconf.cpp +++ b/Source/3rd Party/wx/src/common/fileconf.cpp @@ -1,2131 +1,2131 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/fileconf.cpp -// Purpose: implementation of wxFileConfig derivation of wxConfig -// Author: Vadim Zeitlin -// Modified by: -// Created: 07.04.98 (adapted from appconf.cpp) -// RCS-ID: $Id: fileconf.cpp 50711 2007-12-15 02:57:58Z VZ $ -// Copyright: (c) 1997 Karsten Ballueder & Vadim Zeitlin -// Ballueder@usa.net -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif //__BORLANDC__ - -#if wxUSE_CONFIG && wxUSE_FILECONFIG - -#ifndef WX_PRECOMP - #include "wx/dynarray.h" - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/app.h" - #include "wx/utils.h" // for wxGetHomeDir - #if wxUSE_STREAMS - #include "wx/stream.h" - #endif // wxUSE_STREAMS -#endif //WX_PRECOMP - -#include "wx/file.h" -#include "wx/textfile.h" -#include "wx/memtext.h" -#include "wx/config.h" -#include "wx/fileconf.h" -#include "wx/filefn.h" - -#if defined(__WXMAC__) - #include "wx/mac/private.h" // includes mac headers - #include "wx/filename.h" // for MacSetTypeAndCreator -#endif - -#if defined(__WXMSW__) - #include "wx/msw/private.h" -#endif //windows.h -#if defined(__WXPM__) - #define INCL_DOS - #include -#endif - -#include -#include - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- -#define CONST_CAST ((wxFileConfig *)this)-> - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -#ifndef MAX_PATH - #define MAX_PATH 512 -#endif - -#define FILECONF_TRACE_MASK _T("fileconf") - -// ---------------------------------------------------------------------------- -// global functions declarations -// ---------------------------------------------------------------------------- - -// compare functions for sorting the arrays -static int LINKAGEMODE CompareEntries(wxFileConfigEntry *p1, wxFileConfigEntry *p2); -static int LINKAGEMODE CompareGroups(wxFileConfigGroup *p1, wxFileConfigGroup *p2); - -// filter strings -static wxString FilterInValue(const wxString& str); -static wxString FilterOutValue(const wxString& str); - -static wxString FilterInEntryName(const wxString& str); -static wxString FilterOutEntryName(const wxString& str); - -// get the name to use in wxFileConfig ctor -static wxString GetAppName(const wxString& appname); - -// ============================================================================ -// private classes -// ============================================================================ - -// ---------------------------------------------------------------------------- -// "template" array types -// ---------------------------------------------------------------------------- - -#ifdef WXMAKINGDLL_BASE - WX_DEFINE_SORTED_USER_EXPORTED_ARRAY(wxFileConfigEntry *, ArrayEntries, - WXDLLIMPEXP_BASE); - WX_DEFINE_SORTED_USER_EXPORTED_ARRAY(wxFileConfigGroup *, ArrayGroups, - WXDLLIMPEXP_BASE); -#else - WX_DEFINE_SORTED_ARRAY(wxFileConfigEntry *, ArrayEntries); - WX_DEFINE_SORTED_ARRAY(wxFileConfigGroup *, ArrayGroups); -#endif - -// ---------------------------------------------------------------------------- -// wxFileConfigLineList -// ---------------------------------------------------------------------------- - -// we store all lines of the local config file as a linked list in memory -class wxFileConfigLineList -{ -public: - void SetNext(wxFileConfigLineList *pNext) { m_pNext = pNext; } - void SetPrev(wxFileConfigLineList *pPrev) { m_pPrev = pPrev; } - - // ctor - wxFileConfigLineList(const wxString& str, - wxFileConfigLineList *pNext = NULL) : m_strLine(str) - { SetNext(pNext); SetPrev(NULL); } - - // next/prev nodes in the linked list - wxFileConfigLineList *Next() const { return m_pNext; } - wxFileConfigLineList *Prev() const { return m_pPrev; } - - // get/change lines text - void SetText(const wxString& str) { m_strLine = str; } - const wxString& Text() const { return m_strLine; } - -private: - wxString m_strLine; // line contents - wxFileConfigLineList *m_pNext, // next node - *m_pPrev; // previous one - - DECLARE_NO_COPY_CLASS(wxFileConfigLineList) -}; - -// ---------------------------------------------------------------------------- -// wxFileConfigEntry: a name/value pair -// ---------------------------------------------------------------------------- - -class wxFileConfigEntry -{ -private: - wxFileConfigGroup *m_pParent; // group that contains us - - wxString m_strName, // entry name - m_strValue; // value - bool m_bImmutable:1, // can be overriden locally? - m_bHasValue:1; // set after first call to SetValue() - - int m_nLine; // used if m_pLine == NULL only - - // pointer to our line in the linked list or NULL if it was found in global - // file (which we don't modify) - wxFileConfigLineList *m_pLine; - -public: - wxFileConfigEntry(wxFileConfigGroup *pParent, - const wxString& strName, int nLine); - - // simple accessors - const wxString& Name() const { return m_strName; } - const wxString& Value() const { return m_strValue; } - wxFileConfigGroup *Group() const { return m_pParent; } - bool IsImmutable() const { return m_bImmutable; } - bool IsLocal() const { return m_pLine != 0; } - int Line() const { return m_nLine; } - wxFileConfigLineList * - GetLine() const { return m_pLine; } - - // modify entry attributes - void SetValue(const wxString& strValue, bool bUser = true); - void SetLine(wxFileConfigLineList *pLine); - - DECLARE_NO_COPY_CLASS(wxFileConfigEntry) -}; - -// ---------------------------------------------------------------------------- -// wxFileConfigGroup: container of entries and other groups -// ---------------------------------------------------------------------------- - -class wxFileConfigGroup -{ -private: - wxFileConfig *m_pConfig; // config object we belong to - wxFileConfigGroup *m_pParent; // parent group (NULL for root group) - ArrayEntries m_aEntries; // entries in this group - ArrayGroups m_aSubgroups; // subgroups - wxString m_strName; // group's name - wxFileConfigLineList *m_pLine; // pointer to our line in the linked list - wxFileConfigEntry *m_pLastEntry; // last entry/subgroup of this group in the - wxFileConfigGroup *m_pLastGroup; // local file (we insert new ones after it) - - // DeleteSubgroupByName helper - bool DeleteSubgroup(wxFileConfigGroup *pGroup); - - // used by Rename() - void UpdateGroupAndSubgroupsLines(); - -public: - // ctor - wxFileConfigGroup(wxFileConfigGroup *pParent, const wxString& strName, wxFileConfig *); - - // dtor deletes all entries and subgroups also - ~wxFileConfigGroup(); - - // simple accessors - const wxString& Name() const { return m_strName; } - wxFileConfigGroup *Parent() const { return m_pParent; } - wxFileConfig *Config() const { return m_pConfig; } - - const ArrayEntries& Entries() const { return m_aEntries; } - const ArrayGroups& Groups() const { return m_aSubgroups; } - bool IsEmpty() const { return Entries().IsEmpty() && Groups().IsEmpty(); } - - // find entry/subgroup (NULL if not found) - wxFileConfigGroup *FindSubgroup(const wxChar *szName) const; - wxFileConfigEntry *FindEntry (const wxChar *szName) const; - - // delete entry/subgroup, return false if doesn't exist - bool DeleteSubgroupByName(const wxChar *szName); - bool DeleteEntry(const wxChar *szName); - - // create new entry/subgroup returning pointer to newly created element - wxFileConfigGroup *AddSubgroup(const wxString& strName); - wxFileConfigEntry *AddEntry (const wxString& strName, int nLine = wxNOT_FOUND); - - void SetLine(wxFileConfigLineList *pLine); - - // rename: no checks are done to ensure that the name is unique! - void Rename(const wxString& newName); - - // - wxString GetFullName() const; - - // get the last line belonging to an entry/subgroup of this group - wxFileConfigLineList *GetGroupLine(); // line which contains [group] - // may be NULL for "/" only - wxFileConfigLineList *GetLastEntryLine(); // after which our subgroups start - wxFileConfigLineList *GetLastGroupLine(); // after which the next group starts - - // called by entries/subgroups when they're created/deleted - void SetLastEntry(wxFileConfigEntry *pEntry); - void SetLastGroup(wxFileConfigGroup *pGroup) - { m_pLastGroup = pGroup; } - - DECLARE_NO_COPY_CLASS(wxFileConfigGroup) -}; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// static functions -// ---------------------------------------------------------------------------- -wxString wxFileConfig::GetGlobalDir() -{ - wxString strDir; - -#ifdef __VMS__ // Note if __VMS is defined __UNIX is also defined - strDir = wxT("sys$manager:"); -#elif defined(__WXMAC__) - strDir = wxMacFindFolder( (short) kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder ) ; -#elif defined( __UNIX__ ) - strDir = wxT("/etc/"); -#elif defined(__OS2__) - ULONG aulSysInfo[QSV_MAX] = {0}; - UINT drive; - APIRET rc; - - rc = DosQuerySysInfo( 1L, QSV_MAX, (PVOID)aulSysInfo, sizeof(ULONG)*QSV_MAX); - if (rc == 0) - { - drive = aulSysInfo[QSV_BOOT_DRIVE - 1]; - strDir.Printf(wxT("%c:\\OS2\\"), 'A'+drive-1); - } -#elif defined(__WXSTUBS__) - wxFAIL_MSG( wxT("TODO") ); -#elif defined(__DOS__) - // There's no such thing as global cfg dir in MS-DOS, let's return - // current directory (FIXME_MGL?) - strDir = wxT(".\\"); -#elif defined(__WXWINCE__) - strDir = wxT("\\Windows\\"); -#else // Windows - - wxChar szWinDir[MAX_PATH]; - ::GetWindowsDirectory(szWinDir, MAX_PATH); - - strDir = szWinDir; - strDir << wxT('\\'); -#endif // Unix/Windows - - return strDir; -} - -wxString wxFileConfig::GetLocalDir() -{ - wxString strDir; - -#if defined(__WXMAC__) || defined(__DOS__) - // no local dir concept on Mac OS 9 or MS-DOS - strDir << GetGlobalDir() ; -#else - wxGetHomeDir(&strDir); - - #ifdef __UNIX__ - if ( - (strDir.Last() != wxT('/')) - #ifdef __VMS - && (strDir.Last() != wxT(']')) - #endif - ) - strDir << wxT('/'); - #else - if (strDir.Last() != wxT('\\')) - strDir << wxT('\\'); - #endif -#endif - - return strDir; -} - -wxString wxFileConfig::GetGlobalFileName(const wxChar *szFile) -{ - wxString str = GetGlobalDir(); - str << szFile; - - if ( wxStrchr(szFile, wxT('.')) == NULL ) -#if defined( __WXMAC__ ) - str << wxT(" Preferences") ; -#elif defined( __UNIX__ ) - str << wxT(".conf"); -#else // Windows - str << wxT(".ini"); -#endif // UNIX/Win - - return str; -} - -wxString wxFileConfig::GetLocalFileName(const wxChar *szFile) -{ -#ifdef __VMS__ - // On VMS I saw the problem that the home directory was appended - // twice for the configuration file. Does that also happen for - // other platforms? - wxString str = wxT( '.' ); -#else - wxString str = GetLocalDir(); -#endif - -#if defined( __UNIX__ ) && !defined( __VMS ) && !defined( __WXMAC__ ) - str << wxT('.'); -#endif - - str << szFile; - -#if defined(__WINDOWS__) || defined(__DOS__) - if ( wxStrchr(szFile, wxT('.')) == NULL ) - str << wxT(".ini"); -#endif - -#ifdef __WXMAC__ - str << wxT(" Preferences") ; -#endif - - return str; -} - -// ---------------------------------------------------------------------------- -// ctor -// ---------------------------------------------------------------------------- - -void wxFileConfig::Init() -{ - m_pCurrentGroup = - m_pRootGroup = new wxFileConfigGroup(NULL, wxEmptyString, this); - - m_linesHead = - m_linesTail = NULL; - - // It's not an error if (one of the) file(s) doesn't exist. - - // parse the global file - if ( !m_strGlobalFile.empty() && wxFile::Exists(m_strGlobalFile) ) - { - wxTextFile fileGlobal(m_strGlobalFile); - - if ( fileGlobal.Open(*m_conv/*ignored in ANSI build*/) ) - { - Parse(fileGlobal, false /* global */); - SetRootPath(); - } - else - { - wxLogWarning(_("can't open global configuration file '%s'."), m_strGlobalFile.c_str()); - } - } - - // parse the local file - if ( !m_strLocalFile.empty() && wxFile::Exists(m_strLocalFile) ) - { - wxTextFile fileLocal(m_strLocalFile); - if ( fileLocal.Open(*m_conv/*ignored in ANSI build*/) ) - { - Parse(fileLocal, true /* local */); - SetRootPath(); - } - else - { - wxLogWarning(_("can't open user configuration file '%s'."), m_strLocalFile.c_str() ); - } - } - - m_isDirty = false; -} - -// constructor supports creation of wxFileConfig objects of any type -wxFileConfig::wxFileConfig(const wxString& appName, const wxString& vendorName, - const wxString& strLocal, const wxString& strGlobal, - long style, - const wxMBConv& conv) - : wxConfigBase(::GetAppName(appName), vendorName, - strLocal, strGlobal, - style), - m_strLocalFile(strLocal), m_strGlobalFile(strGlobal), - m_conv(conv.Clone()) -{ - // Make up names for files if empty - if ( m_strLocalFile.empty() && (style & wxCONFIG_USE_LOCAL_FILE) ) - { - m_strLocalFile = GetLocalFileName(GetAppName()); -#if defined(__UNIX__) && !defined(__VMS) - if ( style & wxCONFIG_USE_SUBDIR ) - m_strLocalFile << wxFILE_SEP_PATH << GetAppName() << _T(".conf"); -#endif - } - - if ( m_strGlobalFile.empty() && (style & wxCONFIG_USE_GLOBAL_FILE) ) - m_strGlobalFile = GetGlobalFileName(GetAppName()); - - // Check if styles are not supplied, but filenames are, in which case - // add the correct styles. - if ( !m_strLocalFile.empty() ) - SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE); - - if ( !m_strGlobalFile.empty() ) - SetStyle(GetStyle() | wxCONFIG_USE_GLOBAL_FILE); - - // if the path is not absolute, prepend the standard directory to it - // UNLESS wxCONFIG_USE_RELATIVE_PATH style is set - if ( !(style & wxCONFIG_USE_RELATIVE_PATH) ) - { - if ( !m_strLocalFile.empty() && !wxIsAbsolutePath(m_strLocalFile) ) - { - const wxString strLocalOrig = m_strLocalFile; - m_strLocalFile = GetLocalDir(); - m_strLocalFile << strLocalOrig; - } - - if ( !m_strGlobalFile.empty() && !wxIsAbsolutePath(m_strGlobalFile) ) - { - const wxString strGlobalOrig = m_strGlobalFile; - m_strGlobalFile = GetGlobalDir(); - m_strGlobalFile << strGlobalOrig; - } - } - - SetUmask(-1); - - Init(); -} - -#if wxUSE_STREAMS - -wxFileConfig::wxFileConfig(wxInputStream &inStream, const wxMBConv& conv) - : m_conv(conv.Clone()) -{ - // always local_file when this constructor is called (?) - SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE); - - m_pCurrentGroup = - m_pRootGroup = new wxFileConfigGroup(NULL, wxEmptyString, this); - - m_linesHead = - m_linesTail = NULL; - - // read the entire stream contents in memory - wxString str; - { - static const size_t chunkLen = 1024; - - wxMemoryBuffer buf(chunkLen); - do - { - inStream.Read(buf.GetAppendBuf(chunkLen), chunkLen); - buf.UngetAppendBuf(inStream.LastRead()); - - const wxStreamError err = inStream.GetLastError(); - - if ( err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF ) - { - wxLogError(_("Error reading config options.")); - break; - } - } - while ( !inStream.Eof() ); - -#if wxUSE_UNICODE - size_t len; - str = conv.cMB2WC((char *)buf.GetData(), buf.GetDataLen(), &len); - if ( !len && buf.GetDataLen() ) - { - wxLogError(_("Failed to read config options.")); - } -#else // !wxUSE_UNICODE - // no need for conversion - str.assign((char *)buf.GetData(), buf.GetDataLen()); -#endif // wxUSE_UNICODE/!wxUSE_UNICODE - } - - - // translate everything to the current (platform-dependent) line - // termination character - str = wxTextBuffer::Translate(str); - - wxMemoryText memText; - - // Now we can add the text to the memory text. To do this we extract line - // by line from the translated string, until we've reached the end. - // - // VZ: all this is horribly inefficient, we should do the translation on - // the fly in one pass saving both memory and time (TODO) - - const wxChar *pEOL = wxTextBuffer::GetEOL(wxTextBuffer::typeDefault); - const size_t EOLLen = wxStrlen(pEOL); - - int posLineStart = str.Find(pEOL); - while ( posLineStart != -1 ) - { - wxString line(str.Left(posLineStart)); - - memText.AddLine(line); - - str = str.Mid(posLineStart + EOLLen); - - posLineStart = str.Find(pEOL); - } - - // also add whatever we have left in the translated string. - if ( !str.empty() ) - memText.AddLine(str); - - // Finally we can parse it all. - Parse(memText, true /* local */); - - SetRootPath(); - ResetDirty(); -} - -#endif // wxUSE_STREAMS - -void wxFileConfig::CleanUp() -{ - delete m_pRootGroup; - - wxFileConfigLineList *pCur = m_linesHead; - while ( pCur != NULL ) { - wxFileConfigLineList *pNext = pCur->Next(); - delete pCur; - pCur = pNext; - } -} - -wxFileConfig::~wxFileConfig() -{ - Flush(); - - CleanUp(); - - delete m_conv; -} - -// ---------------------------------------------------------------------------- -// parse a config file -// ---------------------------------------------------------------------------- - -void wxFileConfig::Parse(const wxTextBuffer& buffer, bool bLocal) -{ - const wxChar *pStart; - const wxChar *pEnd; - wxString strLine; - - size_t nLineCount = buffer.GetLineCount(); - - for ( size_t n = 0; n < nLineCount; n++ ) - { - strLine = buffer[n]; - - // add the line to linked list - if ( bLocal ) - LineListAppend(strLine); - - - // skip leading spaces - for ( pStart = strLine; wxIsspace(*pStart); pStart++ ) - ; - - // skip blank/comment lines - if ( *pStart == wxT('\0')|| *pStart == wxT(';') || *pStart == wxT('#') ) - continue; - - if ( *pStart == wxT('[') ) { // a new group - pEnd = pStart; - - while ( *++pEnd != wxT(']') ) { - if ( *pEnd == wxT('\\') ) { - // the next char is escaped, so skip it even if it is ']' - pEnd++; - } - - if ( *pEnd == wxT('\n') || *pEnd == wxT('\0') ) { - // we reached the end of line, break out of the loop - break; - } - } - - if ( *pEnd != wxT(']') ) { - wxLogError(_("file '%s': unexpected character %c at line %d."), - buffer.GetName(), *pEnd, n + 1); - continue; // skip this line - } - - // group name here is always considered as abs path - wxString strGroup; - pStart++; - strGroup << wxCONFIG_PATH_SEPARATOR - << FilterInEntryName(wxString(pStart, pEnd - pStart)); - - // will create it if doesn't yet exist - SetPath(strGroup); - - if ( bLocal ) - { - if ( m_pCurrentGroup->Parent() ) - m_pCurrentGroup->Parent()->SetLastGroup(m_pCurrentGroup); - m_pCurrentGroup->SetLine(m_linesTail); - } - - // check that there is nothing except comments left on this line - bool bCont = true; - while ( *++pEnd != wxT('\0') && bCont ) { - switch ( *pEnd ) { - case wxT('#'): - case wxT(';'): - bCont = false; - break; - - case wxT(' '): - case wxT('\t'): - // ignore whitespace ('\n' impossible here) - break; - - default: - wxLogWarning(_("file '%s', line %d: '%s' ignored after group header."), - buffer.GetName(), n + 1, pEnd); - bCont = false; - } - } - } - else { // a key - pEnd = pStart; - while ( *pEnd && *pEnd != wxT('=') /* && !wxIsspace(*pEnd)*/ ) { - if ( *pEnd == wxT('\\') ) { - // next character may be space or not - still take it because it's - // quoted (unless there is nothing) - pEnd++; - if ( !*pEnd ) { - // the error message will be given below anyhow - break; - } - } - - pEnd++; - } - - wxString strKey(FilterInEntryName(wxString(pStart, pEnd).Trim())); - - // skip whitespace - while ( wxIsspace(*pEnd) ) - pEnd++; - - if ( *pEnd++ != wxT('=') ) { - wxLogError(_("file '%s', line %d: '=' expected."), - buffer.GetName(), n + 1); - } - else { - wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strKey); - - if ( pEntry == NULL ) { - // new entry - pEntry = m_pCurrentGroup->AddEntry(strKey, n); - } - else { - if ( bLocal && pEntry->IsImmutable() ) { - // immutable keys can't be changed by user - wxLogWarning(_("file '%s', line %d: value for immutable key '%s' ignored."), - buffer.GetName(), n + 1, strKey.c_str()); - continue; - } - // the condition below catches the cases (a) and (b) but not (c): - // (a) global key found second time in global file - // (b) key found second (or more) time in local file - // (c) key from global file now found in local one - // which is exactly what we want. - else if ( !bLocal || pEntry->IsLocal() ) { - wxLogWarning(_("file '%s', line %d: key '%s' was first found at line %d."), - buffer.GetName(), n + 1, strKey.c_str(), pEntry->Line()); - - } - } - - if ( bLocal ) - pEntry->SetLine(m_linesTail); - - // skip whitespace - while ( wxIsspace(*pEnd) ) - pEnd++; - - wxString value = pEnd; - if ( !(GetStyle() & wxCONFIG_USE_NO_ESCAPE_CHARACTERS) ) - value = FilterInValue(value); - - pEntry->SetValue(value, false); - } - } - } -} - -// ---------------------------------------------------------------------------- -// set/retrieve path -// ---------------------------------------------------------------------------- - -void wxFileConfig::SetRootPath() -{ - m_strPath.Empty(); - m_pCurrentGroup = m_pRootGroup; -} - -bool -wxFileConfig::DoSetPath(const wxString& strPath, bool createMissingComponents) -{ - wxArrayString aParts; - - if ( strPath.empty() ) { - SetRootPath(); - return true; - } - - if ( strPath[0] == wxCONFIG_PATH_SEPARATOR ) { - // absolute path - wxSplitPath(aParts, strPath); - } - else { - // relative path, combine with current one - wxString strFullPath = m_strPath; - strFullPath << wxCONFIG_PATH_SEPARATOR << strPath; - wxSplitPath(aParts, strFullPath); - } - - // change current group - size_t n; - m_pCurrentGroup = m_pRootGroup; - for ( n = 0; n < aParts.Count(); n++ ) { - wxFileConfigGroup *pNextGroup = m_pCurrentGroup->FindSubgroup(aParts[n]); - if ( pNextGroup == NULL ) - { - if ( !createMissingComponents ) - return false; - - pNextGroup = m_pCurrentGroup->AddSubgroup(aParts[n]); - } - - m_pCurrentGroup = pNextGroup; - } - - // recombine path parts in one variable - m_strPath.Empty(); - for ( n = 0; n < aParts.Count(); n++ ) { - m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n]; - } - - return true; -} - -void wxFileConfig::SetPath(const wxString& strPath) -{ - DoSetPath(strPath, true /* create missing path components */); -} - -// ---------------------------------------------------------------------------- -// enumeration -// ---------------------------------------------------------------------------- - -bool wxFileConfig::GetFirstGroup(wxString& str, long& lIndex) const -{ - lIndex = 0; - return GetNextGroup(str, lIndex); -} - -bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex) const -{ - if ( size_t(lIndex) < m_pCurrentGroup->Groups().Count() ) { - str = m_pCurrentGroup->Groups()[(size_t)lIndex++]->Name(); - return true; - } - else - return false; -} - -bool wxFileConfig::GetFirstEntry(wxString& str, long& lIndex) const -{ - lIndex = 0; - return GetNextEntry(str, lIndex); -} - -bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const -{ - if ( size_t(lIndex) < m_pCurrentGroup->Entries().Count() ) { - str = m_pCurrentGroup->Entries()[(size_t)lIndex++]->Name(); - return true; - } - else - return false; -} - -size_t wxFileConfig::GetNumberOfEntries(bool bRecursive) const -{ - size_t n = m_pCurrentGroup->Entries().Count(); - if ( bRecursive ) { - wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup; - size_t nSubgroups = m_pCurrentGroup->Groups().Count(); - for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) { - CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup]; - n += GetNumberOfEntries(true); - CONST_CAST m_pCurrentGroup = pOldCurrentGroup; - } - } - - return n; -} - -size_t wxFileConfig::GetNumberOfGroups(bool bRecursive) const -{ - size_t n = m_pCurrentGroup->Groups().Count(); - if ( bRecursive ) { - wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup; - size_t nSubgroups = m_pCurrentGroup->Groups().Count(); - for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) { - CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup]; - n += GetNumberOfGroups(true); - CONST_CAST m_pCurrentGroup = pOldCurrentGroup; - } - } - - return n; -} - -// ---------------------------------------------------------------------------- -// tests for existence -// ---------------------------------------------------------------------------- - -bool wxFileConfig::HasGroup(const wxString& strName) const -{ - // special case: DoSetPath("") does work as it's equivalent to DoSetPath("/") - // but there is no group with empty name so treat this separately - if ( strName.empty() ) - return false; - - const wxString pathOld = GetPath(); - - wxFileConfig *self = wx_const_cast(wxFileConfig *, this); - const bool - rc = self->DoSetPath(strName, false /* don't create missing components */); - - self->SetPath(pathOld); - - return rc; -} - -bool wxFileConfig::HasEntry(const wxString& entry) const -{ - // path is the part before the last "/" - wxString path = entry.BeforeLast(wxCONFIG_PATH_SEPARATOR); - - // except in the special case of "/keyname" when there is nothing before "/" - if ( path.empty() && *entry.c_str() == wxCONFIG_PATH_SEPARATOR ) - { - path = wxCONFIG_PATH_SEPARATOR; - } - - // change to the path of the entry if necessary and remember the old path - // to restore it later - wxString pathOld; - wxFileConfig * const self = wx_const_cast(wxFileConfig *, this); - if ( !path.empty() ) - { - pathOld = GetPath(); - if ( pathOld.empty() ) - pathOld = wxCONFIG_PATH_SEPARATOR; - - if ( !self->DoSetPath(path, false /* don't create if doesn't exist */) ) - { - return false; - } - } - - // check if the entry exists in this group - const bool exists = m_pCurrentGroup->FindEntry( - entry.AfterLast(wxCONFIG_PATH_SEPARATOR)) != NULL; - - // restore the old path if we changed it above - if ( !pathOld.empty() ) - { - self->SetPath(pathOld); - } - - return exists; -} - -// ---------------------------------------------------------------------------- -// read/write values -// ---------------------------------------------------------------------------- - -bool wxFileConfig::DoReadString(const wxString& key, wxString* pStr) const -{ - wxConfigPathChanger path(this, key); - - wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name()); - if (pEntry == NULL) { - return false; - } - - *pStr = pEntry->Value(); - - return true; -} - -bool wxFileConfig::DoReadLong(const wxString& key, long *pl) const -{ - wxString str; - if ( !Read(key, &str) ) - return false; - - // extra spaces shouldn't prevent us from reading numeric values - str.Trim(); - - return str.ToLong(pl); -} - -bool wxFileConfig::DoWriteString(const wxString& key, const wxString& szValue) -{ - wxConfigPathChanger path(this, key); - wxString strName = path.Name(); - - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Writing String '%s' = '%s' to Group '%s'"), - strName.c_str(), - szValue.c_str(), - GetPath().c_str() ); - - if ( strName.empty() ) - { - // setting the value of a group is an error - - wxASSERT_MSG( szValue.empty(), wxT("can't set value of a group!") ); - - // ... except if it's empty in which case it's a way to force it's creation - - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Creating group %s"), - m_pCurrentGroup->Name().c_str() ); - - SetDirty(); - - // this will add a line for this group if it didn't have it before (or - // do nothing for the root but it's ok as it always exists anyhow) - (void)m_pCurrentGroup->GetGroupLine(); - } - else - { - // writing an entry check that the name is reasonable - if ( strName[0u] == wxCONFIG_IMMUTABLE_PREFIX ) - { - wxLogError( _("Config entry name cannot start with '%c'."), - wxCONFIG_IMMUTABLE_PREFIX); - return false; - } - - wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strName); - - if ( pEntry == 0 ) - { - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Adding Entry %s"), - strName.c_str() ); - pEntry = m_pCurrentGroup->AddEntry(strName); - } - - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Setting value %s"), - szValue.c_str() ); - pEntry->SetValue(szValue); - - SetDirty(); - } - - return true; -} - -bool wxFileConfig::DoWriteLong(const wxString& key, long lValue) -{ - return Write(key, wxString::Format(_T("%ld"), lValue)); -} - -bool wxFileConfig::Flush(bool /* bCurrentOnly */) -{ - if ( !IsDirty() || !m_strLocalFile ) - return true; - - // set the umask if needed - wxCHANGE_UMASK(m_umask); - - wxTempFile file(m_strLocalFile); - - if ( !file.IsOpened() ) - { - wxLogError(_("can't open user configuration file.")); - return false; - } - - // write all strings to file - wxString filetext; - filetext.reserve(4096); - for ( wxFileConfigLineList *p = m_linesHead; p != NULL; p = p->Next() ) - { - filetext << p->Text() << wxTextFile::GetEOL(); - } - - if ( !file.Write(filetext, *m_conv) ) - { - wxLogError(_("can't write user configuration file.")); - return false; - } - - if ( !file.Commit() ) - { - wxLogError(_("Failed to update user configuration file.")); - - return false; - } - - ResetDirty(); - -#if defined(__WXMAC__) - wxFileName(m_strLocalFile).MacSetTypeAndCreator('TEXT', 'ttxt'); -#endif // __WXMAC__ - - return true; -} - -#if wxUSE_STREAMS - -bool wxFileConfig::Save(wxOutputStream& os, const wxMBConv& conv) -{ - // save unconditionally, even if not dirty - for ( wxFileConfigLineList *p = m_linesHead; p != NULL; p = p->Next() ) - { - wxString line = p->Text(); - line += wxTextFile::GetEOL(); - - wxCharBuffer buf(line.mb_str(conv)); - if ( !os.Write(buf, strlen(buf)) ) - { - wxLogError(_("Error saving user configuration data.")); - - return false; - } - } - - ResetDirty(); - - return true; -} - -#endif // wxUSE_STREAMS - -// ---------------------------------------------------------------------------- -// renaming groups/entries -// ---------------------------------------------------------------------------- - -bool wxFileConfig::RenameEntry(const wxString& oldName, - const wxString& newName) -{ - wxASSERT_MSG( !wxStrchr(oldName, wxCONFIG_PATH_SEPARATOR), - _T("RenameEntry(): paths are not supported") ); - - // check that the entry exists - wxFileConfigEntry *oldEntry = m_pCurrentGroup->FindEntry(oldName); - if ( !oldEntry ) - return false; - - // check that the new entry doesn't already exist - if ( m_pCurrentGroup->FindEntry(newName) ) - return false; - - // delete the old entry, create the new one - wxString value = oldEntry->Value(); - if ( !m_pCurrentGroup->DeleteEntry(oldName) ) - return false; - - SetDirty(); - - wxFileConfigEntry *newEntry = m_pCurrentGroup->AddEntry(newName); - newEntry->SetValue(value); - - return true; -} - -bool wxFileConfig::RenameGroup(const wxString& oldName, - const wxString& newName) -{ - // check that the group exists - wxFileConfigGroup *group = m_pCurrentGroup->FindSubgroup(oldName); - if ( !group ) - return false; - - // check that the new group doesn't already exist - if ( m_pCurrentGroup->FindSubgroup(newName) ) - return false; - - group->Rename(newName); - - SetDirty(); - - return true; -} - -// ---------------------------------------------------------------------------- -// delete groups/entries -// ---------------------------------------------------------------------------- - -bool wxFileConfig::DeleteEntry(const wxString& key, bool bGroupIfEmptyAlso) -{ - wxConfigPathChanger path(this, key); - - if ( !m_pCurrentGroup->DeleteEntry(path.Name()) ) - return false; - - SetDirty(); - - if ( bGroupIfEmptyAlso && m_pCurrentGroup->IsEmpty() ) { - if ( m_pCurrentGroup != m_pRootGroup ) { - wxFileConfigGroup *pGroup = m_pCurrentGroup; - SetPath(wxT("..")); // changes m_pCurrentGroup! - m_pCurrentGroup->DeleteSubgroupByName(pGroup->Name()); - } - //else: never delete the root group - } - - return true; -} - -bool wxFileConfig::DeleteGroup(const wxString& key) -{ - wxConfigPathChanger path(this, RemoveTrailingSeparator(key)); - - if ( !m_pCurrentGroup->DeleteSubgroupByName(path.Name()) ) - return false; - - path.UpdateIfDeleted(); - - SetDirty(); - - return true; -} - -bool wxFileConfig::DeleteAll() -{ - CleanUp(); - - if ( !m_strLocalFile.empty() ) - { - if ( wxFile::Exists(m_strLocalFile) && wxRemove(m_strLocalFile) == -1 ) - { - wxLogSysError(_("can't delete user configuration file '%s'"), - m_strLocalFile.c_str()); - return false; - } - } - - Init(); - - return true; -} - -// ---------------------------------------------------------------------------- -// linked list functions -// ---------------------------------------------------------------------------- - - // append a new line to the end of the list - -wxFileConfigLineList *wxFileConfig::LineListAppend(const wxString& str) -{ - wxLogTrace( FILECONF_TRACE_MASK, - _T(" ** Adding Line '%s'"), - str.c_str() ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" head: %s"), - ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" tail: %s"), - ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); - - wxFileConfigLineList *pLine = new wxFileConfigLineList(str); - - if ( m_linesTail == NULL ) - { - // list is empty - m_linesHead = pLine; - } - else - { - // adjust pointers - m_linesTail->SetNext(pLine); - pLine->SetPrev(m_linesTail); - } - - m_linesTail = pLine; - - wxLogTrace( FILECONF_TRACE_MASK, - _T(" head: %s"), - ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" tail: %s"), - ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); - - return m_linesTail; -} - -// insert a new line after the given one or in the very beginning if !pLine -wxFileConfigLineList *wxFileConfig::LineListInsert(const wxString& str, - wxFileConfigLineList *pLine) -{ - wxLogTrace( FILECONF_TRACE_MASK, - _T(" ** Inserting Line '%s' after '%s'"), - str.c_str(), - ((pLine) ? pLine->Text().c_str() : wxEmptyString) ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" head: %s"), - ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" tail: %s"), - ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); - - if ( pLine == m_linesTail ) - return LineListAppend(str); - - wxFileConfigLineList *pNewLine = new wxFileConfigLineList(str); - if ( pLine == NULL ) - { - // prepend to the list - pNewLine->SetNext(m_linesHead); - m_linesHead->SetPrev(pNewLine); - m_linesHead = pNewLine; - } - else - { - // insert before pLine - wxFileConfigLineList *pNext = pLine->Next(); - pNewLine->SetNext(pNext); - pNewLine->SetPrev(pLine); - pNext->SetPrev(pNewLine); - pLine->SetNext(pNewLine); - } - - wxLogTrace( FILECONF_TRACE_MASK, - _T(" head: %s"), - ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" tail: %s"), - ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); - - return pNewLine; -} - -void wxFileConfig::LineListRemove(wxFileConfigLineList *pLine) -{ - wxLogTrace( FILECONF_TRACE_MASK, - _T(" ** Removing Line '%s'"), - pLine->Text().c_str() ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" head: %s"), - ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" tail: %s"), - ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); - - wxFileConfigLineList *pPrev = pLine->Prev(), - *pNext = pLine->Next(); - - // first entry? - - if ( pPrev == NULL ) - m_linesHead = pNext; - else - pPrev->SetNext(pNext); - - // last entry? - - if ( pNext == NULL ) - m_linesTail = pPrev; - else - pNext->SetPrev(pPrev); - - if ( m_pRootGroup->GetGroupLine() == pLine ) - m_pRootGroup->SetLine(m_linesHead); - - wxLogTrace( FILECONF_TRACE_MASK, - _T(" head: %s"), - ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" tail: %s"), - ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); - - delete pLine; -} - -bool wxFileConfig::LineListIsEmpty() -{ - return m_linesHead == NULL; -} - -// ============================================================================ -// wxFileConfig::wxFileConfigGroup -// ============================================================================ - -// ---------------------------------------------------------------------------- -// ctor/dtor -// ---------------------------------------------------------------------------- - -// ctor -wxFileConfigGroup::wxFileConfigGroup(wxFileConfigGroup *pParent, - const wxString& strName, - wxFileConfig *pConfig) - : m_aEntries(CompareEntries), - m_aSubgroups(CompareGroups), - m_strName(strName) -{ - m_pConfig = pConfig; - m_pParent = pParent; - m_pLine = NULL; - - m_pLastEntry = NULL; - m_pLastGroup = NULL; -} - -// dtor deletes all children -wxFileConfigGroup::~wxFileConfigGroup() -{ - // entries - size_t n, nCount = m_aEntries.Count(); - for ( n = 0; n < nCount; n++ ) - delete m_aEntries[n]; - - // subgroups - nCount = m_aSubgroups.Count(); - for ( n = 0; n < nCount; n++ ) - delete m_aSubgroups[n]; -} - -// ---------------------------------------------------------------------------- -// line -// ---------------------------------------------------------------------------- - -void wxFileConfigGroup::SetLine(wxFileConfigLineList *pLine) -{ - // for a normal (i.e. not root) group this method shouldn't be called twice - // unless we are resetting the line - wxASSERT_MSG( !m_pParent || !m_pLine || !pLine, - _T("changing line for a non-root group?") ); - - m_pLine = pLine; -} - -/* - This is a bit complicated, so let me explain it in details. All lines that - were read from the local file (the only one we will ever modify) are stored - in a (doubly) linked list. Our problem is to know at which position in this - list should we insert the new entries/subgroups. To solve it we keep three - variables for each group: m_pLine, m_pLastEntry and m_pLastGroup. - - m_pLine points to the line containing "[group_name]" - m_pLastEntry points to the last entry of this group in the local file. - m_pLastGroup subgroup - - Initially, they're NULL all three. When the group (an entry/subgroup) is read - from the local file, the corresponding variable is set. However, if the group - was read from the global file and then modified or created by the application - these variables are still NULL and we need to create the corresponding lines. - See the following functions (and comments preceding them) for the details of - how we do it. - - Also, when our last entry/group are deleted we need to find the new last - element - the code in DeleteEntry/Subgroup does this by backtracking the list - of lines until it either founds an entry/subgroup (and this is the new last - element) or the m_pLine of the group, in which case there are no more entries - (or subgroups) left and m_pLast becomes NULL. - - NB: This last problem could be avoided for entries if we added new entries - immediately after m_pLine, but in this case the entries would appear - backwards in the config file (OTOH, it's not that important) and as we - would still need to do it for the subgroups the code wouldn't have been - significantly less complicated. -*/ - -// Return the line which contains "[our name]". If we're still not in the list, -// add our line to it immediately after the last line of our parent group if we -// have it or in the very beginning if we're the root group. -wxFileConfigLineList *wxFileConfigGroup::GetGroupLine() -{ - wxLogTrace( FILECONF_TRACE_MASK, - _T(" GetGroupLine() for Group '%s'"), - Name().c_str() ); - - if ( !m_pLine ) - { - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Getting Line item pointer") ); - - wxFileConfigGroup *pParent = Parent(); - - // this group wasn't present in local config file, add it now - if ( pParent ) - { - wxLogTrace( FILECONF_TRACE_MASK, - _T(" checking parent '%s'"), - pParent->Name().c_str() ); - - wxString strFullName; - - // add 1 to the name because we don't want to start with '/' - strFullName << wxT("[") - << FilterOutEntryName(GetFullName().c_str() + 1) - << wxT("]"); - m_pLine = m_pConfig->LineListInsert(strFullName, - pParent->GetLastGroupLine()); - pParent->SetLastGroup(this); // we're surely after all the others - } - //else: this is the root group and so we return NULL because we don't - // have any group line - } - - return m_pLine; -} - -// Return the last line belonging to the subgroups of this group (after which -// we can add a new subgroup), if we don't have any subgroups or entries our -// last line is the group line (m_pLine) itself. -wxFileConfigLineList *wxFileConfigGroup::GetLastGroupLine() -{ - // if we have any subgroups, our last line is the last line of the last - // subgroup - if ( m_pLastGroup ) - { - wxFileConfigLineList *pLine = m_pLastGroup->GetLastGroupLine(); - - wxASSERT_MSG( pLine, _T("last group must have !NULL associated line") ); - - return pLine; - } - - // no subgroups, so the last line is the line of thelast entry (if any) - return GetLastEntryLine(); -} - -// return the last line belonging to the entries of this group (after which -// we can add a new entry), if we don't have any entries we will add the new -// one immediately after the group line itself. -wxFileConfigLineList *wxFileConfigGroup::GetLastEntryLine() -{ - wxLogTrace( FILECONF_TRACE_MASK, - _T(" GetLastEntryLine() for Group '%s'"), - Name().c_str() ); - - if ( m_pLastEntry ) - { - wxFileConfigLineList *pLine = m_pLastEntry->GetLine(); - - wxASSERT_MSG( pLine, _T("last entry must have !NULL associated line") ); - - return pLine; - } - - // no entries: insert after the group header, if any - return GetGroupLine(); -} - -void wxFileConfigGroup::SetLastEntry(wxFileConfigEntry *pEntry) -{ - m_pLastEntry = pEntry; - - if ( !m_pLine ) - { - // the only situation in which a group without its own line can have - // an entry is when the first entry is added to the initially empty - // root pseudo-group - wxASSERT_MSG( !m_pParent, _T("unexpected for non root group") ); - - // let the group know that it does have a line in the file now - m_pLine = pEntry->GetLine(); - } -} - -// ---------------------------------------------------------------------------- -// group name -// ---------------------------------------------------------------------------- - -void wxFileConfigGroup::UpdateGroupAndSubgroupsLines() -{ - // update the line of this group - wxFileConfigLineList *line = GetGroupLine(); - wxCHECK_RET( line, _T("a non root group must have a corresponding line!") ); - - // +1: skip the leading '/' - line->SetText(wxString::Format(_T("[%s]"), GetFullName().c_str() + 1)); - - - // also update all subgroups as they have this groups name in their lines - const size_t nCount = m_aSubgroups.Count(); - for ( size_t n = 0; n < nCount; n++ ) - { - m_aSubgroups[n]->UpdateGroupAndSubgroupsLines(); - } -} - -void wxFileConfigGroup::Rename(const wxString& newName) -{ - wxCHECK_RET( m_pParent, _T("the root group can't be renamed") ); - - if ( newName == m_strName ) - return; - - // we need to remove the group from the parent and it back under the new - // name to keep the parents array of subgroups alphabetically sorted - m_pParent->m_aSubgroups.Remove(this); - - m_strName = newName; - - m_pParent->m_aSubgroups.Add(this); - - // update the group lines recursively - UpdateGroupAndSubgroupsLines(); -} - -wxString wxFileConfigGroup::GetFullName() const -{ - wxString fullname; - if ( Parent() ) - fullname = Parent()->GetFullName() + wxCONFIG_PATH_SEPARATOR + Name(); - - return fullname; -} - -// ---------------------------------------------------------------------------- -// find an item -// ---------------------------------------------------------------------------- - -// use binary search because the array is sorted -wxFileConfigEntry * -wxFileConfigGroup::FindEntry(const wxChar *szName) const -{ - size_t i, - lo = 0, - hi = m_aEntries.Count(); - int res; - wxFileConfigEntry *pEntry; - - while ( lo < hi ) { - i = (lo + hi)/2; - pEntry = m_aEntries[i]; - - #if wxCONFIG_CASE_SENSITIVE - res = wxStrcmp(pEntry->Name(), szName); - #else - res = wxStricmp(pEntry->Name(), szName); - #endif - - if ( res > 0 ) - hi = i; - else if ( res < 0 ) - lo = i + 1; - else - return pEntry; - } - - return NULL; -} - -wxFileConfigGroup * -wxFileConfigGroup::FindSubgroup(const wxChar *szName) const -{ - size_t i, - lo = 0, - hi = m_aSubgroups.Count(); - int res; - wxFileConfigGroup *pGroup; - - while ( lo < hi ) { - i = (lo + hi)/2; - pGroup = m_aSubgroups[i]; - - #if wxCONFIG_CASE_SENSITIVE - res = wxStrcmp(pGroup->Name(), szName); - #else - res = wxStricmp(pGroup->Name(), szName); - #endif - - if ( res > 0 ) - hi = i; - else if ( res < 0 ) - lo = i + 1; - else - return pGroup; - } - - return NULL; -} - -// ---------------------------------------------------------------------------- -// create a new item -// ---------------------------------------------------------------------------- - -// create a new entry and add it to the current group -wxFileConfigEntry *wxFileConfigGroup::AddEntry(const wxString& strName, int nLine) -{ - wxASSERT( FindEntry(strName) == 0 ); - - wxFileConfigEntry *pEntry = new wxFileConfigEntry(this, strName, nLine); - - m_aEntries.Add(pEntry); - return pEntry; -} - -// create a new group and add it to the current group -wxFileConfigGroup *wxFileConfigGroup::AddSubgroup(const wxString& strName) -{ - wxASSERT( FindSubgroup(strName) == 0 ); - - wxFileConfigGroup *pGroup = new wxFileConfigGroup(this, strName, m_pConfig); - - m_aSubgroups.Add(pGroup); - return pGroup; -} - -// ---------------------------------------------------------------------------- -// delete an item -// ---------------------------------------------------------------------------- - -/* - The delete operations are _very_ slow if we delete the last item of this - group (see comments before GetXXXLineXXX functions for more details), - so it's much better to start with the first entry/group if we want to - delete several of them. - */ - -bool wxFileConfigGroup::DeleteSubgroupByName(const wxChar *szName) -{ - wxFileConfigGroup * const pGroup = FindSubgroup(szName); - - return pGroup ? DeleteSubgroup(pGroup) : false; -} - -// Delete the subgroup and remove all references to it from -// other data structures. -bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup) -{ - wxCHECK_MSG( pGroup, false, _T("deleting non existing group?") ); - - wxLogTrace( FILECONF_TRACE_MASK, - _T("Deleting group '%s' from '%s'"), - pGroup->Name().c_str(), - Name().c_str() ); - - wxLogTrace( FILECONF_TRACE_MASK, - _T(" (m_pLine) = prev: %p, this %p, next %p"), - m_pLine ? wx_static_cast(void*, m_pLine->Prev()) : 0, - wx_static_cast(void*, m_pLine), - m_pLine ? wx_static_cast(void*, m_pLine->Next()) : 0 ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" text: '%s'"), - m_pLine ? m_pLine->Text().c_str() : wxEmptyString ); - - // delete all entries... - size_t nCount = pGroup->m_aEntries.Count(); - - wxLogTrace(FILECONF_TRACE_MASK, - _T("Removing %lu entries"), (unsigned long)nCount ); - - for ( size_t nEntry = 0; nEntry < nCount; nEntry++ ) - { - wxFileConfigLineList *pLine = pGroup->m_aEntries[nEntry]->GetLine(); - - if ( pLine ) - { - wxLogTrace( FILECONF_TRACE_MASK, - _T(" '%s'"), - pLine->Text().c_str() ); - m_pConfig->LineListRemove(pLine); - } - } - - // ...and subgroups of this subgroup - nCount = pGroup->m_aSubgroups.Count(); - - wxLogTrace( FILECONF_TRACE_MASK, - _T("Removing %lu subgroups"), (unsigned long)nCount ); - - for ( size_t nGroup = 0; nGroup < nCount; nGroup++ ) - { - pGroup->DeleteSubgroup(pGroup->m_aSubgroups[0]); - } - - // and then finally the group itself - wxFileConfigLineList *pLine = pGroup->m_pLine; - if ( pLine ) - { - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Removing line for group '%s' : '%s'"), - pGroup->Name().c_str(), - pLine->Text().c_str() ); - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Removing from group '%s' : '%s'"), - Name().c_str(), - ((m_pLine) ? m_pLine->Text().c_str() : wxEmptyString) ); - - // notice that we may do this test inside the previous "if" - // because the last entry's line is surely !NULL - if ( pGroup == m_pLastGroup ) - { - wxLogTrace( FILECONF_TRACE_MASK, - _T(" Removing last group") ); - - // our last entry is being deleted, so find the last one which - // stays by going back until we find a subgroup or reach the - // group line - const size_t nSubgroups = m_aSubgroups.Count(); - - m_pLastGroup = NULL; - for ( wxFileConfigLineList *pl = pLine->Prev(); - pl && !m_pLastGroup; - pl = pl->Prev() ) - { - // does this line belong to our subgroup? - for ( size_t n = 0; n < nSubgroups; n++ ) - { - // do _not_ call GetGroupLine! we don't want to add it to - // the local file if it's not already there - if ( m_aSubgroups[n]->m_pLine == pl ) - { - m_pLastGroup = m_aSubgroups[n]; - break; - } - } - - if ( pl == m_pLine ) - break; - } - } - - m_pConfig->LineListRemove(pLine); - } - else - { - wxLogTrace( FILECONF_TRACE_MASK, - _T(" No line entry for Group '%s'?"), - pGroup->Name().c_str() ); - } - - m_aSubgroups.Remove(pGroup); - delete pGroup; - - return true; -} - -bool wxFileConfigGroup::DeleteEntry(const wxChar *szName) -{ - wxFileConfigEntry *pEntry = FindEntry(szName); - if ( !pEntry ) - { - // entry doesn't exist, nothing to do - return false; - } - - wxFileConfigLineList *pLine = pEntry->GetLine(); - if ( pLine != NULL ) { - // notice that we may do this test inside the previous "if" because the - // last entry's line is surely !NULL - if ( pEntry == m_pLastEntry ) { - // our last entry is being deleted - find the last one which stays - wxASSERT( m_pLine != NULL ); // if we have an entry with !NULL pLine... - - // find the previous entry (if any) - wxFileConfigEntry *pNewLast = NULL; - const wxFileConfigLineList * const - pNewLastLine = m_pLastEntry->GetLine()->Prev(); - const size_t nEntries = m_aEntries.GetCount(); - for ( size_t n = 0; n < nEntries; n++ ) { - if ( m_aEntries[n]->GetLine() == pNewLastLine ) { - pNewLast = m_aEntries[n]; - break; - } - } - - // pNewLast can be NULL here -- it's ok and can happen if we have no - // entries left - m_pLastEntry = pNewLast; - } - - m_pConfig->LineListRemove(pLine); - } - - m_aEntries.Remove(pEntry); - delete pEntry; - - return true; -} - -// ============================================================================ -// wxFileConfig::wxFileConfigEntry -// ============================================================================ - -// ---------------------------------------------------------------------------- -// ctor -// ---------------------------------------------------------------------------- -wxFileConfigEntry::wxFileConfigEntry(wxFileConfigGroup *pParent, - const wxString& strName, - int nLine) - : m_strName(strName) -{ - wxASSERT( !strName.empty() ); - - m_pParent = pParent; - m_nLine = nLine; - m_pLine = NULL; - - m_bHasValue = false; - - m_bImmutable = strName[0] == wxCONFIG_IMMUTABLE_PREFIX; - if ( m_bImmutable ) - m_strName.erase(0, 1); // remove first character -} - -// ---------------------------------------------------------------------------- -// set value -// ---------------------------------------------------------------------------- - -void wxFileConfigEntry::SetLine(wxFileConfigLineList *pLine) -{ - if ( m_pLine != NULL ) { - wxLogWarning(_("entry '%s' appears more than once in group '%s'"), - Name().c_str(), m_pParent->GetFullName().c_str()); - } - - m_pLine = pLine; - Group()->SetLastEntry(this); -} - -// second parameter is false if we read the value from file and prevents the -// entry from being marked as 'dirty' -void wxFileConfigEntry::SetValue(const wxString& strValue, bool bUser) -{ - if ( bUser && IsImmutable() ) - { - wxLogWarning( _("attempt to change immutable key '%s' ignored."), - Name().c_str()); - return; - } - - // do nothing if it's the same value: but don't test for it if m_bHasValue - // hadn't been set yet or we'd never write empty values to the file - if ( m_bHasValue && strValue == m_strValue ) - return; - - m_bHasValue = true; - m_strValue = strValue; - - if ( bUser ) - { - wxString strValFiltered; - - if ( Group()->Config()->GetStyle() & wxCONFIG_USE_NO_ESCAPE_CHARACTERS ) - { - strValFiltered = strValue; - } - else { - strValFiltered = FilterOutValue(strValue); - } - - wxString strLine; - strLine << FilterOutEntryName(m_strName) << wxT('=') << strValFiltered; - - if ( m_pLine ) - { - // entry was read from the local config file, just modify the line - m_pLine->SetText(strLine); - } - else // this entry didn't exist in the local file - { - // add a new line to the file: note that line returned by - // GetLastEntryLine() may be NULL if we're in the root group and it - // doesn't have any entries yet, but this is ok as passing NULL - // line to LineListInsert() means to prepend new line to the list - wxFileConfigLineList *line = Group()->GetLastEntryLine(); - m_pLine = Group()->Config()->LineListInsert(strLine, line); - - Group()->SetLastEntry(this); - } - } -} - -// ============================================================================ -// global functions -// ============================================================================ - -// ---------------------------------------------------------------------------- -// compare functions for array sorting -// ---------------------------------------------------------------------------- - -int CompareEntries(wxFileConfigEntry *p1, wxFileConfigEntry *p2) -{ -#if wxCONFIG_CASE_SENSITIVE - return wxStrcmp(p1->Name(), p2->Name()); -#else - return wxStricmp(p1->Name(), p2->Name()); -#endif -} - -int CompareGroups(wxFileConfigGroup *p1, wxFileConfigGroup *p2) -{ -#if wxCONFIG_CASE_SENSITIVE - return wxStrcmp(p1->Name(), p2->Name()); -#else - return wxStricmp(p1->Name(), p2->Name()); -#endif -} - -// ---------------------------------------------------------------------------- -// filter functions -// ---------------------------------------------------------------------------- - -// undo FilterOutValue -static wxString FilterInValue(const wxString& str) -{ - wxString strResult; - strResult.Alloc(str.Len()); - - bool bQuoted = !str.empty() && str[0] == '"'; - - for ( size_t n = bQuoted ? 1 : 0; n < str.Len(); n++ ) { - if ( str[n] == wxT('\\') ) { - switch ( str[++n] ) { - case wxT('n'): - strResult += wxT('\n'); - break; - - case wxT('r'): - strResult += wxT('\r'); - break; - - case wxT('t'): - strResult += wxT('\t'); - break; - - case wxT('\\'): - strResult += wxT('\\'); - break; - - case wxT('"'): - strResult += wxT('"'); - break; - } - } - else { - if ( str[n] != wxT('"') || !bQuoted ) - strResult += str[n]; - else if ( n != str.Len() - 1 ) { - wxLogWarning(_("unexpected \" at position %d in '%s'."), - n, str.c_str()); - } - //else: it's the last quote of a quoted string, ok - } - } - - return strResult; -} - -// quote the string before writing it to file -static wxString FilterOutValue(const wxString& str) -{ - if ( !str ) - return str; - - wxString strResult; - strResult.Alloc(str.Len()); - - // quoting is necessary to preserve spaces in the beginning of the string - bool bQuote = wxIsspace(str[0]) || str[0] == wxT('"'); - - if ( bQuote ) - strResult += wxT('"'); - - wxChar c; - for ( size_t n = 0; n < str.Len(); n++ ) { - switch ( str[n] ) { - case wxT('\n'): - c = wxT('n'); - break; - - case wxT('\r'): - c = wxT('r'); - break; - - case wxT('\t'): - c = wxT('t'); - break; - - case wxT('\\'): - c = wxT('\\'); - break; - - case wxT('"'): - if ( bQuote ) { - c = wxT('"'); - break; - } - //else: fall through - - default: - strResult += str[n]; - continue; // nothing special to do - } - - // we get here only for special characters - strResult << wxT('\\') << c; - } - - if ( bQuote ) - strResult += wxT('"'); - - return strResult; -} - -// undo FilterOutEntryName -static wxString FilterInEntryName(const wxString& str) -{ - wxString strResult; - strResult.Alloc(str.Len()); - - for ( const wxChar *pc = str.c_str(); *pc != '\0'; pc++ ) { - if ( *pc == wxT('\\') ) { - // we need to test it here or we'd skip past the NUL in the loop line - if ( *++pc == _T('\0') ) - break; - } - - strResult += *pc; - } - - return strResult; -} - -// sanitize entry or group name: insert '\\' before any special characters -static wxString FilterOutEntryName(const wxString& str) -{ - wxString strResult; - strResult.Alloc(str.Len()); - - for ( const wxChar *pc = str.c_str(); *pc != wxT('\0'); pc++ ) { - const wxChar c = *pc; - - // we explicitly allow some of "safe" chars and 8bit ASCII characters - // which will probably never have special meaning and with which we can't - // use isalnum() anyhow (in ASCII built, in Unicode it's just fine) - // - // NB: note that wxCONFIG_IMMUTABLE_PREFIX and wxCONFIG_PATH_SEPARATOR - // should *not* be quoted - if ( -#if !wxUSE_UNICODE - ((unsigned char)c < 127) && -#endif // ANSI - !wxIsalnum(c) && !wxStrchr(wxT("@_/-!.*%"), c) ) - { - strResult += wxT('\\'); - } - - strResult += c; - } - - return strResult; -} - -// we can't put ?: in the ctor initializer list because it confuses some -// broken compilers (Borland C++) -static wxString GetAppName(const wxString& appName) -{ - if ( !appName && wxTheApp ) - return wxTheApp->GetAppName(); - else - return appName; -} - -#endif // wxUSE_CONFIG +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/fileconf.cpp +// Purpose: implementation of wxFileConfig derivation of wxConfig +// Author: Vadim Zeitlin +// Modified by: +// Created: 07.04.98 (adapted from appconf.cpp) +// RCS-ID: $Id: fileconf.cpp 50711 2007-12-15 02:57:58Z VZ $ +// Copyright: (c) 1997 Karsten Ballueder & Vadim Zeitlin +// Ballueder@usa.net +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif //__BORLANDC__ + +#if wxUSE_CONFIG && wxUSE_FILECONFIG + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/app.h" + #include "wx/utils.h" // for wxGetHomeDir + #if wxUSE_STREAMS + #include "wx/stream.h" + #endif // wxUSE_STREAMS +#endif //WX_PRECOMP + +#include "wx/file.h" +#include "wx/textfile.h" +#include "wx/memtext.h" +#include "wx/config.h" +#include "wx/fileconf.h" +#include "wx/filefn.h" + +#if defined(__WXMAC__) + #include "wx/mac/private.h" // includes mac headers + #include "wx/filename.h" // for MacSetTypeAndCreator +#endif + +#if defined(__WXMSW__) + #include "wx/msw/private.h" +#endif //windows.h +#if defined(__WXPM__) + #define INCL_DOS + #include +#endif + +#include +#include + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- +#define CONST_CAST ((wxFileConfig *)this)-> + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +#ifndef MAX_PATH + #define MAX_PATH 512 +#endif + +#define FILECONF_TRACE_MASK _T("fileconf") + +// ---------------------------------------------------------------------------- +// global functions declarations +// ---------------------------------------------------------------------------- + +// compare functions for sorting the arrays +static int LINKAGEMODE CompareEntries(wxFileConfigEntry *p1, wxFileConfigEntry *p2); +static int LINKAGEMODE CompareGroups(wxFileConfigGroup *p1, wxFileConfigGroup *p2); + +// filter strings +static wxString FilterInValue(const wxString& str); +static wxString FilterOutValue(const wxString& str); + +static wxString FilterInEntryName(const wxString& str); +static wxString FilterOutEntryName(const wxString& str); + +// get the name to use in wxFileConfig ctor +static wxString GetAppName(const wxString& appname); + +// ============================================================================ +// private classes +// ============================================================================ + +// ---------------------------------------------------------------------------- +// "template" array types +// ---------------------------------------------------------------------------- + +#ifdef WXMAKINGDLL_BASE + WX_DEFINE_SORTED_USER_EXPORTED_ARRAY(wxFileConfigEntry *, ArrayEntries, + WXDLLIMPEXP_BASE); + WX_DEFINE_SORTED_USER_EXPORTED_ARRAY(wxFileConfigGroup *, ArrayGroups, + WXDLLIMPEXP_BASE); +#else + WX_DEFINE_SORTED_ARRAY(wxFileConfigEntry *, ArrayEntries); + WX_DEFINE_SORTED_ARRAY(wxFileConfigGroup *, ArrayGroups); +#endif + +// ---------------------------------------------------------------------------- +// wxFileConfigLineList +// ---------------------------------------------------------------------------- + +// we store all lines of the local config file as a linked list in memory +class wxFileConfigLineList +{ +public: + void SetNext(wxFileConfigLineList *pNext) { m_pNext = pNext; } + void SetPrev(wxFileConfigLineList *pPrev) { m_pPrev = pPrev; } + + // ctor + wxFileConfigLineList(const wxString& str, + wxFileConfigLineList *pNext = NULL) : m_strLine(str) + { SetNext(pNext); SetPrev(NULL); } + + // next/prev nodes in the linked list + wxFileConfigLineList *Next() const { return m_pNext; } + wxFileConfigLineList *Prev() const { return m_pPrev; } + + // get/change lines text + void SetText(const wxString& str) { m_strLine = str; } + const wxString& Text() const { return m_strLine; } + +private: + wxString m_strLine; // line contents + wxFileConfigLineList *m_pNext, // next node + *m_pPrev; // previous one + + DECLARE_NO_COPY_CLASS(wxFileConfigLineList) +}; + +// ---------------------------------------------------------------------------- +// wxFileConfigEntry: a name/value pair +// ---------------------------------------------------------------------------- + +class wxFileConfigEntry +{ +private: + wxFileConfigGroup *m_pParent; // group that contains us + + wxString m_strName, // entry name + m_strValue; // value + bool m_bImmutable:1, // can be overriden locally? + m_bHasValue:1; // set after first call to SetValue() + + int m_nLine; // used if m_pLine == NULL only + + // pointer to our line in the linked list or NULL if it was found in global + // file (which we don't modify) + wxFileConfigLineList *m_pLine; + +public: + wxFileConfigEntry(wxFileConfigGroup *pParent, + const wxString& strName, int nLine); + + // simple accessors + const wxString& Name() const { return m_strName; } + const wxString& Value() const { return m_strValue; } + wxFileConfigGroup *Group() const { return m_pParent; } + bool IsImmutable() const { return m_bImmutable; } + bool IsLocal() const { return m_pLine != 0; } + int Line() const { return m_nLine; } + wxFileConfigLineList * + GetLine() const { return m_pLine; } + + // modify entry attributes + void SetValue(const wxString& strValue, bool bUser = true); + void SetLine(wxFileConfigLineList *pLine); + + DECLARE_NO_COPY_CLASS(wxFileConfigEntry) +}; + +// ---------------------------------------------------------------------------- +// wxFileConfigGroup: container of entries and other groups +// ---------------------------------------------------------------------------- + +class wxFileConfigGroup +{ +private: + wxFileConfig *m_pConfig; // config object we belong to + wxFileConfigGroup *m_pParent; // parent group (NULL for root group) + ArrayEntries m_aEntries; // entries in this group + ArrayGroups m_aSubgroups; // subgroups + wxString m_strName; // group's name + wxFileConfigLineList *m_pLine; // pointer to our line in the linked list + wxFileConfigEntry *m_pLastEntry; // last entry/subgroup of this group in the + wxFileConfigGroup *m_pLastGroup; // local file (we insert new ones after it) + + // DeleteSubgroupByName helper + bool DeleteSubgroup(wxFileConfigGroup *pGroup); + + // used by Rename() + void UpdateGroupAndSubgroupsLines(); + +public: + // ctor + wxFileConfigGroup(wxFileConfigGroup *pParent, const wxString& strName, wxFileConfig *); + + // dtor deletes all entries and subgroups also + ~wxFileConfigGroup(); + + // simple accessors + const wxString& Name() const { return m_strName; } + wxFileConfigGroup *Parent() const { return m_pParent; } + wxFileConfig *Config() const { return m_pConfig; } + + const ArrayEntries& Entries() const { return m_aEntries; } + const ArrayGroups& Groups() const { return m_aSubgroups; } + bool IsEmpty() const { return Entries().IsEmpty() && Groups().IsEmpty(); } + + // find entry/subgroup (NULL if not found) + wxFileConfigGroup *FindSubgroup(const wxChar *szName) const; + wxFileConfigEntry *FindEntry (const wxChar *szName) const; + + // delete entry/subgroup, return false if doesn't exist + bool DeleteSubgroupByName(const wxChar *szName); + bool DeleteEntry(const wxChar *szName); + + // create new entry/subgroup returning pointer to newly created element + wxFileConfigGroup *AddSubgroup(const wxString& strName); + wxFileConfigEntry *AddEntry (const wxString& strName, int nLine = wxNOT_FOUND); + + void SetLine(wxFileConfigLineList *pLine); + + // rename: no checks are done to ensure that the name is unique! + void Rename(const wxString& newName); + + // + wxString GetFullName() const; + + // get the last line belonging to an entry/subgroup of this group + wxFileConfigLineList *GetGroupLine(); // line which contains [group] + // may be NULL for "/" only + wxFileConfigLineList *GetLastEntryLine(); // after which our subgroups start + wxFileConfigLineList *GetLastGroupLine(); // after which the next group starts + + // called by entries/subgroups when they're created/deleted + void SetLastEntry(wxFileConfigEntry *pEntry); + void SetLastGroup(wxFileConfigGroup *pGroup) + { m_pLastGroup = pGroup; } + + DECLARE_NO_COPY_CLASS(wxFileConfigGroup) +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// static functions +// ---------------------------------------------------------------------------- +wxString wxFileConfig::GetGlobalDir() +{ + wxString strDir; + +#ifdef __VMS__ // Note if __VMS is defined __UNIX is also defined + strDir = wxT("sys$manager:"); +#elif defined(__WXMAC__) + strDir = wxMacFindFolder( (short) kOnSystemDisk, kPreferencesFolderType, kDontCreateFolder ) ; +#elif defined( __UNIX__ ) + strDir = wxT("/etc/"); +#elif defined(__OS2__) + ULONG aulSysInfo[QSV_MAX] = {0}; + UINT drive; + APIRET rc; + + rc = DosQuerySysInfo( 1L, QSV_MAX, (PVOID)aulSysInfo, sizeof(ULONG)*QSV_MAX); + if (rc == 0) + { + drive = aulSysInfo[QSV_BOOT_DRIVE - 1]; + strDir.Printf(wxT("%c:\\OS2\\"), 'A'+drive-1); + } +#elif defined(__WXSTUBS__) + wxFAIL_MSG( wxT("TODO") ); +#elif defined(__DOS__) + // There's no such thing as global cfg dir in MS-DOS, let's return + // current directory (FIXME_MGL?) + strDir = wxT(".\\"); +#elif defined(__WXWINCE__) + strDir = wxT("\\Windows\\"); +#else // Windows + + wxChar szWinDir[MAX_PATH]; + ::GetWindowsDirectory(szWinDir, MAX_PATH); + + strDir = szWinDir; + strDir << wxT('\\'); +#endif // Unix/Windows + + return strDir; +} + +wxString wxFileConfig::GetLocalDir() +{ + wxString strDir; + +#if defined(__WXMAC__) || defined(__DOS__) + // no local dir concept on Mac OS 9 or MS-DOS + strDir << GetGlobalDir() ; +#else + wxGetHomeDir(&strDir); + + #ifdef __UNIX__ + if ( + (strDir.Last() != wxT('/')) + #ifdef __VMS + && (strDir.Last() != wxT(']')) + #endif + ) + strDir << wxT('/'); + #else + if (strDir.Last() != wxT('\\')) + strDir << wxT('\\'); + #endif +#endif + + return strDir; +} + +wxString wxFileConfig::GetGlobalFileName(const wxChar *szFile) +{ + wxString str = GetGlobalDir(); + str << szFile; + + if ( wxStrchr(szFile, wxT('.')) == NULL ) +#if defined( __WXMAC__ ) + str << wxT(" Preferences") ; +#elif defined( __UNIX__ ) + str << wxT(".conf"); +#else // Windows + str << wxT(".ini"); +#endif // UNIX/Win + + return str; +} + +wxString wxFileConfig::GetLocalFileName(const wxChar *szFile) +{ +#ifdef __VMS__ + // On VMS I saw the problem that the home directory was appended + // twice for the configuration file. Does that also happen for + // other platforms? + wxString str = wxT( '.' ); +#else + wxString str = GetLocalDir(); +#endif + +#if defined( __UNIX__ ) && !defined( __VMS ) && !defined( __WXMAC__ ) + str << wxT('.'); +#endif + + str << szFile; + +#if defined(__WINDOWS__) || defined(__DOS__) + if ( wxStrchr(szFile, wxT('.')) == NULL ) + str << wxT(".ini"); +#endif + +#ifdef __WXMAC__ + str << wxT(" Preferences") ; +#endif + + return str; +} + +// ---------------------------------------------------------------------------- +// ctor +// ---------------------------------------------------------------------------- + +void wxFileConfig::Init() +{ + m_pCurrentGroup = + m_pRootGroup = new wxFileConfigGroup(NULL, wxEmptyString, this); + + m_linesHead = + m_linesTail = NULL; + + // It's not an error if (one of the) file(s) doesn't exist. + + // parse the global file + if ( !m_strGlobalFile.empty() && wxFile::Exists(m_strGlobalFile) ) + { + wxTextFile fileGlobal(m_strGlobalFile); + + if ( fileGlobal.Open(*m_conv/*ignored in ANSI build*/) ) + { + Parse(fileGlobal, false /* global */); + SetRootPath(); + } + else + { + wxLogWarning(_("can't open global configuration file '%s'."), m_strGlobalFile.c_str()); + } + } + + // parse the local file + if ( !m_strLocalFile.empty() && wxFile::Exists(m_strLocalFile) ) + { + wxTextFile fileLocal(m_strLocalFile); + if ( fileLocal.Open(*m_conv/*ignored in ANSI build*/) ) + { + Parse(fileLocal, true /* local */); + SetRootPath(); + } + else + { + wxLogWarning(_("can't open user configuration file '%s'."), m_strLocalFile.c_str() ); + } + } + + m_isDirty = false; +} + +// constructor supports creation of wxFileConfig objects of any type +wxFileConfig::wxFileConfig(const wxString& appName, const wxString& vendorName, + const wxString& strLocal, const wxString& strGlobal, + long style, + const wxMBConv& conv) + : wxConfigBase(::GetAppName(appName), vendorName, + strLocal, strGlobal, + style), + m_strLocalFile(strLocal), m_strGlobalFile(strGlobal), + m_conv(conv.Clone()) +{ + // Make up names for files if empty + if ( m_strLocalFile.empty() && (style & wxCONFIG_USE_LOCAL_FILE) ) + { + m_strLocalFile = GetLocalFileName(GetAppName()); +#if defined(__UNIX__) && !defined(__VMS) + if ( style & wxCONFIG_USE_SUBDIR ) + m_strLocalFile << wxFILE_SEP_PATH << GetAppName() << _T(".conf"); +#endif + } + + if ( m_strGlobalFile.empty() && (style & wxCONFIG_USE_GLOBAL_FILE) ) + m_strGlobalFile = GetGlobalFileName(GetAppName()); + + // Check if styles are not supplied, but filenames are, in which case + // add the correct styles. + if ( !m_strLocalFile.empty() ) + SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE); + + if ( !m_strGlobalFile.empty() ) + SetStyle(GetStyle() | wxCONFIG_USE_GLOBAL_FILE); + + // if the path is not absolute, prepend the standard directory to it + // UNLESS wxCONFIG_USE_RELATIVE_PATH style is set + if ( !(style & wxCONFIG_USE_RELATIVE_PATH) ) + { + if ( !m_strLocalFile.empty() && !wxIsAbsolutePath(m_strLocalFile) ) + { + const wxString strLocalOrig = m_strLocalFile; + m_strLocalFile = GetLocalDir(); + m_strLocalFile << strLocalOrig; + } + + if ( !m_strGlobalFile.empty() && !wxIsAbsolutePath(m_strGlobalFile) ) + { + const wxString strGlobalOrig = m_strGlobalFile; + m_strGlobalFile = GetGlobalDir(); + m_strGlobalFile << strGlobalOrig; + } + } + + SetUmask(-1); + + Init(); +} + +#if wxUSE_STREAMS + +wxFileConfig::wxFileConfig(wxInputStream &inStream, const wxMBConv& conv) + : m_conv(conv.Clone()) +{ + // always local_file when this constructor is called (?) + SetStyle(GetStyle() | wxCONFIG_USE_LOCAL_FILE); + + m_pCurrentGroup = + m_pRootGroup = new wxFileConfigGroup(NULL, wxEmptyString, this); + + m_linesHead = + m_linesTail = NULL; + + // read the entire stream contents in memory + wxString str; + { + static const size_t chunkLen = 1024; + + wxMemoryBuffer buf(chunkLen); + do + { + inStream.Read(buf.GetAppendBuf(chunkLen), chunkLen); + buf.UngetAppendBuf(inStream.LastRead()); + + const wxStreamError err = inStream.GetLastError(); + + if ( err != wxSTREAM_NO_ERROR && err != wxSTREAM_EOF ) + { + wxLogError(_("Error reading config options.")); + break; + } + } + while ( !inStream.Eof() ); + +#if wxUSE_UNICODE + size_t len; + str = conv.cMB2WC((char *)buf.GetData(), buf.GetDataLen(), &len); + if ( !len && buf.GetDataLen() ) + { + wxLogError(_("Failed to read config options.")); + } +#else // !wxUSE_UNICODE + // no need for conversion + str.assign((char *)buf.GetData(), buf.GetDataLen()); +#endif // wxUSE_UNICODE/!wxUSE_UNICODE + } + + + // translate everything to the current (platform-dependent) line + // termination character + str = wxTextBuffer::Translate(str); + + wxMemoryText memText; + + // Now we can add the text to the memory text. To do this we extract line + // by line from the translated string, until we've reached the end. + // + // VZ: all this is horribly inefficient, we should do the translation on + // the fly in one pass saving both memory and time (TODO) + + const wxChar *pEOL = wxTextBuffer::GetEOL(wxTextBuffer::typeDefault); + const size_t EOLLen = wxStrlen(pEOL); + + int posLineStart = str.Find(pEOL); + while ( posLineStart != -1 ) + { + wxString line(str.Left(posLineStart)); + + memText.AddLine(line); + + str = str.Mid(posLineStart + EOLLen); + + posLineStart = str.Find(pEOL); + } + + // also add whatever we have left in the translated string. + if ( !str.empty() ) + memText.AddLine(str); + + // Finally we can parse it all. + Parse(memText, true /* local */); + + SetRootPath(); + ResetDirty(); +} + +#endif // wxUSE_STREAMS + +void wxFileConfig::CleanUp() +{ + delete m_pRootGroup; + + wxFileConfigLineList *pCur = m_linesHead; + while ( pCur != NULL ) { + wxFileConfigLineList *pNext = pCur->Next(); + delete pCur; + pCur = pNext; + } +} + +wxFileConfig::~wxFileConfig() +{ + Flush(); + + CleanUp(); + + delete m_conv; +} + +// ---------------------------------------------------------------------------- +// parse a config file +// ---------------------------------------------------------------------------- + +void wxFileConfig::Parse(const wxTextBuffer& buffer, bool bLocal) +{ + const wxChar *pStart; + const wxChar *pEnd; + wxString strLine; + + size_t nLineCount = buffer.GetLineCount(); + + for ( size_t n = 0; n < nLineCount; n++ ) + { + strLine = buffer[n]; + + // add the line to linked list + if ( bLocal ) + LineListAppend(strLine); + + + // skip leading spaces + for ( pStart = strLine; wxIsspace(*pStart); pStart++ ) + ; + + // skip blank/comment lines + if ( *pStart == wxT('\0')|| *pStart == wxT(';') || *pStart == wxT('#') ) + continue; + + if ( *pStart == wxT('[') ) { // a new group + pEnd = pStart; + + while ( *++pEnd != wxT(']') ) { + if ( *pEnd == wxT('\\') ) { + // the next char is escaped, so skip it even if it is ']' + pEnd++; + } + + if ( *pEnd == wxT('\n') || *pEnd == wxT('\0') ) { + // we reached the end of line, break out of the loop + break; + } + } + + if ( *pEnd != wxT(']') ) { + wxLogError(_("file '%s': unexpected character %c at line %d."), + buffer.GetName(), *pEnd, n + 1); + continue; // skip this line + } + + // group name here is always considered as abs path + wxString strGroup; + pStart++; + strGroup << wxCONFIG_PATH_SEPARATOR + << FilterInEntryName(wxString(pStart, pEnd - pStart)); + + // will create it if doesn't yet exist + SetPath(strGroup); + + if ( bLocal ) + { + if ( m_pCurrentGroup->Parent() ) + m_pCurrentGroup->Parent()->SetLastGroup(m_pCurrentGroup); + m_pCurrentGroup->SetLine(m_linesTail); + } + + // check that there is nothing except comments left on this line + bool bCont = true; + while ( *++pEnd != wxT('\0') && bCont ) { + switch ( *pEnd ) { + case wxT('#'): + case wxT(';'): + bCont = false; + break; + + case wxT(' '): + case wxT('\t'): + // ignore whitespace ('\n' impossible here) + break; + + default: + wxLogWarning(_("file '%s', line %d: '%s' ignored after group header."), + buffer.GetName(), n + 1, pEnd); + bCont = false; + } + } + } + else { // a key + pEnd = pStart; + while ( *pEnd && *pEnd != wxT('=') /* && !wxIsspace(*pEnd)*/ ) { + if ( *pEnd == wxT('\\') ) { + // next character may be space or not - still take it because it's + // quoted (unless there is nothing) + pEnd++; + if ( !*pEnd ) { + // the error message will be given below anyhow + break; + } + } + + pEnd++; + } + + wxString strKey(FilterInEntryName(wxString(pStart, pEnd).Trim())); + + // skip whitespace + while ( wxIsspace(*pEnd) ) + pEnd++; + + if ( *pEnd++ != wxT('=') ) { + wxLogError(_("file '%s', line %d: '=' expected."), + buffer.GetName(), n + 1); + } + else { + wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strKey); + + if ( pEntry == NULL ) { + // new entry + pEntry = m_pCurrentGroup->AddEntry(strKey, n); + } + else { + if ( bLocal && pEntry->IsImmutable() ) { + // immutable keys can't be changed by user + wxLogWarning(_("file '%s', line %d: value for immutable key '%s' ignored."), + buffer.GetName(), n + 1, strKey.c_str()); + continue; + } + // the condition below catches the cases (a) and (b) but not (c): + // (a) global key found second time in global file + // (b) key found second (or more) time in local file + // (c) key from global file now found in local one + // which is exactly what we want. + else if ( !bLocal || pEntry->IsLocal() ) { + wxLogWarning(_("file '%s', line %d: key '%s' was first found at line %d."), + buffer.GetName(), n + 1, strKey.c_str(), pEntry->Line()); + + } + } + + if ( bLocal ) + pEntry->SetLine(m_linesTail); + + // skip whitespace + while ( wxIsspace(*pEnd) ) + pEnd++; + + wxString value = pEnd; + if ( !(GetStyle() & wxCONFIG_USE_NO_ESCAPE_CHARACTERS) ) + value = FilterInValue(value); + + pEntry->SetValue(value, false); + } + } + } +} + +// ---------------------------------------------------------------------------- +// set/retrieve path +// ---------------------------------------------------------------------------- + +void wxFileConfig::SetRootPath() +{ + m_strPath.Empty(); + m_pCurrentGroup = m_pRootGroup; +} + +bool +wxFileConfig::DoSetPath(const wxString& strPath, bool createMissingComponents) +{ + wxArrayString aParts; + + if ( strPath.empty() ) { + SetRootPath(); + return true; + } + + if ( strPath[0] == wxCONFIG_PATH_SEPARATOR ) { + // absolute path + wxSplitPath(aParts, strPath); + } + else { + // relative path, combine with current one + wxString strFullPath = m_strPath; + strFullPath << wxCONFIG_PATH_SEPARATOR << strPath; + wxSplitPath(aParts, strFullPath); + } + + // change current group + size_t n; + m_pCurrentGroup = m_pRootGroup; + for ( n = 0; n < aParts.Count(); n++ ) { + wxFileConfigGroup *pNextGroup = m_pCurrentGroup->FindSubgroup(aParts[n]); + if ( pNextGroup == NULL ) + { + if ( !createMissingComponents ) + return false; + + pNextGroup = m_pCurrentGroup->AddSubgroup(aParts[n]); + } + + m_pCurrentGroup = pNextGroup; + } + + // recombine path parts in one variable + m_strPath.Empty(); + for ( n = 0; n < aParts.Count(); n++ ) { + m_strPath << wxCONFIG_PATH_SEPARATOR << aParts[n]; + } + + return true; +} + +void wxFileConfig::SetPath(const wxString& strPath) +{ + DoSetPath(strPath, true /* create missing path components */); +} + +// ---------------------------------------------------------------------------- +// enumeration +// ---------------------------------------------------------------------------- + +bool wxFileConfig::GetFirstGroup(wxString& str, long& lIndex) const +{ + lIndex = 0; + return GetNextGroup(str, lIndex); +} + +bool wxFileConfig::GetNextGroup (wxString& str, long& lIndex) const +{ + if ( size_t(lIndex) < m_pCurrentGroup->Groups().Count() ) { + str = m_pCurrentGroup->Groups()[(size_t)lIndex++]->Name(); + return true; + } + else + return false; +} + +bool wxFileConfig::GetFirstEntry(wxString& str, long& lIndex) const +{ + lIndex = 0; + return GetNextEntry(str, lIndex); +} + +bool wxFileConfig::GetNextEntry (wxString& str, long& lIndex) const +{ + if ( size_t(lIndex) < m_pCurrentGroup->Entries().Count() ) { + str = m_pCurrentGroup->Entries()[(size_t)lIndex++]->Name(); + return true; + } + else + return false; +} + +size_t wxFileConfig::GetNumberOfEntries(bool bRecursive) const +{ + size_t n = m_pCurrentGroup->Entries().Count(); + if ( bRecursive ) { + wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup; + size_t nSubgroups = m_pCurrentGroup->Groups().Count(); + for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) { + CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup]; + n += GetNumberOfEntries(true); + CONST_CAST m_pCurrentGroup = pOldCurrentGroup; + } + } + + return n; +} + +size_t wxFileConfig::GetNumberOfGroups(bool bRecursive) const +{ + size_t n = m_pCurrentGroup->Groups().Count(); + if ( bRecursive ) { + wxFileConfigGroup *pOldCurrentGroup = m_pCurrentGroup; + size_t nSubgroups = m_pCurrentGroup->Groups().Count(); + for ( size_t nGroup = 0; nGroup < nSubgroups; nGroup++ ) { + CONST_CAST m_pCurrentGroup = m_pCurrentGroup->Groups()[nGroup]; + n += GetNumberOfGroups(true); + CONST_CAST m_pCurrentGroup = pOldCurrentGroup; + } + } + + return n; +} + +// ---------------------------------------------------------------------------- +// tests for existence +// ---------------------------------------------------------------------------- + +bool wxFileConfig::HasGroup(const wxString& strName) const +{ + // special case: DoSetPath("") does work as it's equivalent to DoSetPath("/") + // but there is no group with empty name so treat this separately + if ( strName.empty() ) + return false; + + const wxString pathOld = GetPath(); + + wxFileConfig *self = wx_const_cast(wxFileConfig *, this); + const bool + rc = self->DoSetPath(strName, false /* don't create missing components */); + + self->SetPath(pathOld); + + return rc; +} + +bool wxFileConfig::HasEntry(const wxString& entry) const +{ + // path is the part before the last "/" + wxString path = entry.BeforeLast(wxCONFIG_PATH_SEPARATOR); + + // except in the special case of "/keyname" when there is nothing before "/" + if ( path.empty() && *entry.c_str() == wxCONFIG_PATH_SEPARATOR ) + { + path = wxCONFIG_PATH_SEPARATOR; + } + + // change to the path of the entry if necessary and remember the old path + // to restore it later + wxString pathOld; + wxFileConfig * const self = wx_const_cast(wxFileConfig *, this); + if ( !path.empty() ) + { + pathOld = GetPath(); + if ( pathOld.empty() ) + pathOld = wxCONFIG_PATH_SEPARATOR; + + if ( !self->DoSetPath(path, false /* don't create if doesn't exist */) ) + { + return false; + } + } + + // check if the entry exists in this group + const bool exists = m_pCurrentGroup->FindEntry( + entry.AfterLast(wxCONFIG_PATH_SEPARATOR)) != NULL; + + // restore the old path if we changed it above + if ( !pathOld.empty() ) + { + self->SetPath(pathOld); + } + + return exists; +} + +// ---------------------------------------------------------------------------- +// read/write values +// ---------------------------------------------------------------------------- + +bool wxFileConfig::DoReadString(const wxString& key, wxString* pStr) const +{ + wxConfigPathChanger path(this, key); + + wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(path.Name()); + if (pEntry == NULL) { + return false; + } + + *pStr = pEntry->Value(); + + return true; +} + +bool wxFileConfig::DoReadLong(const wxString& key, long *pl) const +{ + wxString str; + if ( !Read(key, &str) ) + return false; + + // extra spaces shouldn't prevent us from reading numeric values + str.Trim(); + + return str.ToLong(pl); +} + +bool wxFileConfig::DoWriteString(const wxString& key, const wxString& szValue) +{ + wxConfigPathChanger path(this, key); + wxString strName = path.Name(); + + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Writing String '%s' = '%s' to Group '%s'"), + strName.c_str(), + szValue.c_str(), + GetPath().c_str() ); + + if ( strName.empty() ) + { + // setting the value of a group is an error + + wxASSERT_MSG( szValue.empty(), wxT("can't set value of a group!") ); + + // ... except if it's empty in which case it's a way to force it's creation + + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Creating group %s"), + m_pCurrentGroup->Name().c_str() ); + + SetDirty(); + + // this will add a line for this group if it didn't have it before (or + // do nothing for the root but it's ok as it always exists anyhow) + (void)m_pCurrentGroup->GetGroupLine(); + } + else + { + // writing an entry check that the name is reasonable + if ( strName[0u] == wxCONFIG_IMMUTABLE_PREFIX ) + { + wxLogError( _("Config entry name cannot start with '%c'."), + wxCONFIG_IMMUTABLE_PREFIX); + return false; + } + + wxFileConfigEntry *pEntry = m_pCurrentGroup->FindEntry(strName); + + if ( pEntry == 0 ) + { + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Adding Entry %s"), + strName.c_str() ); + pEntry = m_pCurrentGroup->AddEntry(strName); + } + + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Setting value %s"), + szValue.c_str() ); + pEntry->SetValue(szValue); + + SetDirty(); + } + + return true; +} + +bool wxFileConfig::DoWriteLong(const wxString& key, long lValue) +{ + return Write(key, wxString::Format(_T("%ld"), lValue)); +} + +bool wxFileConfig::Flush(bool /* bCurrentOnly */) +{ + if ( !IsDirty() || !m_strLocalFile ) + return true; + + // set the umask if needed + wxCHANGE_UMASK(m_umask); + + wxTempFile file(m_strLocalFile); + + if ( !file.IsOpened() ) + { + wxLogError(_("can't open user configuration file.")); + return false; + } + + // write all strings to file + wxString filetext; + filetext.reserve(4096); + for ( wxFileConfigLineList *p = m_linesHead; p != NULL; p = p->Next() ) + { + filetext << p->Text() << wxTextFile::GetEOL(); + } + + if ( !file.Write(filetext, *m_conv) ) + { + wxLogError(_("can't write user configuration file.")); + return false; + } + + if ( !file.Commit() ) + { + wxLogError(_("Failed to update user configuration file.")); + + return false; + } + + ResetDirty(); + +#if defined(__WXMAC__) + wxFileName(m_strLocalFile).MacSetTypeAndCreator('TEXT', 'ttxt'); +#endif // __WXMAC__ + + return true; +} + +#if wxUSE_STREAMS + +bool wxFileConfig::Save(wxOutputStream& os, const wxMBConv& conv) +{ + // save unconditionally, even if not dirty + for ( wxFileConfigLineList *p = m_linesHead; p != NULL; p = p->Next() ) + { + wxString line = p->Text(); + line += wxTextFile::GetEOL(); + + wxCharBuffer buf(line.mb_str(conv)); + if ( !os.Write(buf, strlen(buf)) ) + { + wxLogError(_("Error saving user configuration data.")); + + return false; + } + } + + ResetDirty(); + + return true; +} + +#endif // wxUSE_STREAMS + +// ---------------------------------------------------------------------------- +// renaming groups/entries +// ---------------------------------------------------------------------------- + +bool wxFileConfig::RenameEntry(const wxString& oldName, + const wxString& newName) +{ + wxASSERT_MSG( !wxStrchr(oldName, wxCONFIG_PATH_SEPARATOR), + _T("RenameEntry(): paths are not supported") ); + + // check that the entry exists + wxFileConfigEntry *oldEntry = m_pCurrentGroup->FindEntry(oldName); + if ( !oldEntry ) + return false; + + // check that the new entry doesn't already exist + if ( m_pCurrentGroup->FindEntry(newName) ) + return false; + + // delete the old entry, create the new one + wxString value = oldEntry->Value(); + if ( !m_pCurrentGroup->DeleteEntry(oldName) ) + return false; + + SetDirty(); + + wxFileConfigEntry *newEntry = m_pCurrentGroup->AddEntry(newName); + newEntry->SetValue(value); + + return true; +} + +bool wxFileConfig::RenameGroup(const wxString& oldName, + const wxString& newName) +{ + // check that the group exists + wxFileConfigGroup *group = m_pCurrentGroup->FindSubgroup(oldName); + if ( !group ) + return false; + + // check that the new group doesn't already exist + if ( m_pCurrentGroup->FindSubgroup(newName) ) + return false; + + group->Rename(newName); + + SetDirty(); + + return true; +} + +// ---------------------------------------------------------------------------- +// delete groups/entries +// ---------------------------------------------------------------------------- + +bool wxFileConfig::DeleteEntry(const wxString& key, bool bGroupIfEmptyAlso) +{ + wxConfigPathChanger path(this, key); + + if ( !m_pCurrentGroup->DeleteEntry(path.Name()) ) + return false; + + SetDirty(); + + if ( bGroupIfEmptyAlso && m_pCurrentGroup->IsEmpty() ) { + if ( m_pCurrentGroup != m_pRootGroup ) { + wxFileConfigGroup *pGroup = m_pCurrentGroup; + SetPath(wxT("..")); // changes m_pCurrentGroup! + m_pCurrentGroup->DeleteSubgroupByName(pGroup->Name()); + } + //else: never delete the root group + } + + return true; +} + +bool wxFileConfig::DeleteGroup(const wxString& key) +{ + wxConfigPathChanger path(this, RemoveTrailingSeparator(key)); + + if ( !m_pCurrentGroup->DeleteSubgroupByName(path.Name()) ) + return false; + + path.UpdateIfDeleted(); + + SetDirty(); + + return true; +} + +bool wxFileConfig::DeleteAll() +{ + CleanUp(); + + if ( !m_strLocalFile.empty() ) + { + if ( wxFile::Exists(m_strLocalFile) && wxRemove(m_strLocalFile) == -1 ) + { + wxLogSysError(_("can't delete user configuration file '%s'"), + m_strLocalFile.c_str()); + return false; + } + } + + Init(); + + return true; +} + +// ---------------------------------------------------------------------------- +// linked list functions +// ---------------------------------------------------------------------------- + + // append a new line to the end of the list + +wxFileConfigLineList *wxFileConfig::LineListAppend(const wxString& str) +{ + wxLogTrace( FILECONF_TRACE_MASK, + _T(" ** Adding Line '%s'"), + str.c_str() ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" head: %s"), + ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" tail: %s"), + ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); + + wxFileConfigLineList *pLine = new wxFileConfigLineList(str); + + if ( m_linesTail == NULL ) + { + // list is empty + m_linesHead = pLine; + } + else + { + // adjust pointers + m_linesTail->SetNext(pLine); + pLine->SetPrev(m_linesTail); + } + + m_linesTail = pLine; + + wxLogTrace( FILECONF_TRACE_MASK, + _T(" head: %s"), + ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" tail: %s"), + ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); + + return m_linesTail; +} + +// insert a new line after the given one or in the very beginning if !pLine +wxFileConfigLineList *wxFileConfig::LineListInsert(const wxString& str, + wxFileConfigLineList *pLine) +{ + wxLogTrace( FILECONF_TRACE_MASK, + _T(" ** Inserting Line '%s' after '%s'"), + str.c_str(), + ((pLine) ? pLine->Text().c_str() : wxEmptyString) ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" head: %s"), + ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" tail: %s"), + ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); + + if ( pLine == m_linesTail ) + return LineListAppend(str); + + wxFileConfigLineList *pNewLine = new wxFileConfigLineList(str); + if ( pLine == NULL ) + { + // prepend to the list + pNewLine->SetNext(m_linesHead); + m_linesHead->SetPrev(pNewLine); + m_linesHead = pNewLine; + } + else + { + // insert before pLine + wxFileConfigLineList *pNext = pLine->Next(); + pNewLine->SetNext(pNext); + pNewLine->SetPrev(pLine); + pNext->SetPrev(pNewLine); + pLine->SetNext(pNewLine); + } + + wxLogTrace( FILECONF_TRACE_MASK, + _T(" head: %s"), + ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" tail: %s"), + ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); + + return pNewLine; +} + +void wxFileConfig::LineListRemove(wxFileConfigLineList *pLine) +{ + wxLogTrace( FILECONF_TRACE_MASK, + _T(" ** Removing Line '%s'"), + pLine->Text().c_str() ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" head: %s"), + ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" tail: %s"), + ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); + + wxFileConfigLineList *pPrev = pLine->Prev(), + *pNext = pLine->Next(); + + // first entry? + + if ( pPrev == NULL ) + m_linesHead = pNext; + else + pPrev->SetNext(pNext); + + // last entry? + + if ( pNext == NULL ) + m_linesTail = pPrev; + else + pNext->SetPrev(pPrev); + + if ( m_pRootGroup->GetGroupLine() == pLine ) + m_pRootGroup->SetLine(m_linesHead); + + wxLogTrace( FILECONF_TRACE_MASK, + _T(" head: %s"), + ((m_linesHead) ? m_linesHead->Text().c_str() : wxEmptyString) ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" tail: %s"), + ((m_linesTail) ? m_linesTail->Text().c_str() : wxEmptyString) ); + + delete pLine; +} + +bool wxFileConfig::LineListIsEmpty() +{ + return m_linesHead == NULL; +} + +// ============================================================================ +// wxFileConfig::wxFileConfigGroup +// ============================================================================ + +// ---------------------------------------------------------------------------- +// ctor/dtor +// ---------------------------------------------------------------------------- + +// ctor +wxFileConfigGroup::wxFileConfigGroup(wxFileConfigGroup *pParent, + const wxString& strName, + wxFileConfig *pConfig) + : m_aEntries(CompareEntries), + m_aSubgroups(CompareGroups), + m_strName(strName) +{ + m_pConfig = pConfig; + m_pParent = pParent; + m_pLine = NULL; + + m_pLastEntry = NULL; + m_pLastGroup = NULL; +} + +// dtor deletes all children +wxFileConfigGroup::~wxFileConfigGroup() +{ + // entries + size_t n, nCount = m_aEntries.Count(); + for ( n = 0; n < nCount; n++ ) + delete m_aEntries[n]; + + // subgroups + nCount = m_aSubgroups.Count(); + for ( n = 0; n < nCount; n++ ) + delete m_aSubgroups[n]; +} + +// ---------------------------------------------------------------------------- +// line +// ---------------------------------------------------------------------------- + +void wxFileConfigGroup::SetLine(wxFileConfigLineList *pLine) +{ + // for a normal (i.e. not root) group this method shouldn't be called twice + // unless we are resetting the line + wxASSERT_MSG( !m_pParent || !m_pLine || !pLine, + _T("changing line for a non-root group?") ); + + m_pLine = pLine; +} + +/* + This is a bit complicated, so let me explain it in details. All lines that + were read from the local file (the only one we will ever modify) are stored + in a (doubly) linked list. Our problem is to know at which position in this + list should we insert the new entries/subgroups. To solve it we keep three + variables for each group: m_pLine, m_pLastEntry and m_pLastGroup. + + m_pLine points to the line containing "[group_name]" + m_pLastEntry points to the last entry of this group in the local file. + m_pLastGroup subgroup + + Initially, they're NULL all three. When the group (an entry/subgroup) is read + from the local file, the corresponding variable is set. However, if the group + was read from the global file and then modified or created by the application + these variables are still NULL and we need to create the corresponding lines. + See the following functions (and comments preceding them) for the details of + how we do it. + + Also, when our last entry/group are deleted we need to find the new last + element - the code in DeleteEntry/Subgroup does this by backtracking the list + of lines until it either founds an entry/subgroup (and this is the new last + element) or the m_pLine of the group, in which case there are no more entries + (or subgroups) left and m_pLast becomes NULL. + + NB: This last problem could be avoided for entries if we added new entries + immediately after m_pLine, but in this case the entries would appear + backwards in the config file (OTOH, it's not that important) and as we + would still need to do it for the subgroups the code wouldn't have been + significantly less complicated. +*/ + +// Return the line which contains "[our name]". If we're still not in the list, +// add our line to it immediately after the last line of our parent group if we +// have it or in the very beginning if we're the root group. +wxFileConfigLineList *wxFileConfigGroup::GetGroupLine() +{ + wxLogTrace( FILECONF_TRACE_MASK, + _T(" GetGroupLine() for Group '%s'"), + Name().c_str() ); + + if ( !m_pLine ) + { + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Getting Line item pointer") ); + + wxFileConfigGroup *pParent = Parent(); + + // this group wasn't present in local config file, add it now + if ( pParent ) + { + wxLogTrace( FILECONF_TRACE_MASK, + _T(" checking parent '%s'"), + pParent->Name().c_str() ); + + wxString strFullName; + + // add 1 to the name because we don't want to start with '/' + strFullName << wxT("[") + << FilterOutEntryName(GetFullName().c_str() + 1) + << wxT("]"); + m_pLine = m_pConfig->LineListInsert(strFullName, + pParent->GetLastGroupLine()); + pParent->SetLastGroup(this); // we're surely after all the others + } + //else: this is the root group and so we return NULL because we don't + // have any group line + } + + return m_pLine; +} + +// Return the last line belonging to the subgroups of this group (after which +// we can add a new subgroup), if we don't have any subgroups or entries our +// last line is the group line (m_pLine) itself. +wxFileConfigLineList *wxFileConfigGroup::GetLastGroupLine() +{ + // if we have any subgroups, our last line is the last line of the last + // subgroup + if ( m_pLastGroup ) + { + wxFileConfigLineList *pLine = m_pLastGroup->GetLastGroupLine(); + + wxASSERT_MSG( pLine, _T("last group must have !NULL associated line") ); + + return pLine; + } + + // no subgroups, so the last line is the line of thelast entry (if any) + return GetLastEntryLine(); +} + +// return the last line belonging to the entries of this group (after which +// we can add a new entry), if we don't have any entries we will add the new +// one immediately after the group line itself. +wxFileConfigLineList *wxFileConfigGroup::GetLastEntryLine() +{ + wxLogTrace( FILECONF_TRACE_MASK, + _T(" GetLastEntryLine() for Group '%s'"), + Name().c_str() ); + + if ( m_pLastEntry ) + { + wxFileConfigLineList *pLine = m_pLastEntry->GetLine(); + + wxASSERT_MSG( pLine, _T("last entry must have !NULL associated line") ); + + return pLine; + } + + // no entries: insert after the group header, if any + return GetGroupLine(); +} + +void wxFileConfigGroup::SetLastEntry(wxFileConfigEntry *pEntry) +{ + m_pLastEntry = pEntry; + + if ( !m_pLine ) + { + // the only situation in which a group without its own line can have + // an entry is when the first entry is added to the initially empty + // root pseudo-group + wxASSERT_MSG( !m_pParent, _T("unexpected for non root group") ); + + // let the group know that it does have a line in the file now + m_pLine = pEntry->GetLine(); + } +} + +// ---------------------------------------------------------------------------- +// group name +// ---------------------------------------------------------------------------- + +void wxFileConfigGroup::UpdateGroupAndSubgroupsLines() +{ + // update the line of this group + wxFileConfigLineList *line = GetGroupLine(); + wxCHECK_RET( line, _T("a non root group must have a corresponding line!") ); + + // +1: skip the leading '/' + line->SetText(wxString::Format(_T("[%s]"), GetFullName().c_str() + 1)); + + + // also update all subgroups as they have this groups name in their lines + const size_t nCount = m_aSubgroups.Count(); + for ( size_t n = 0; n < nCount; n++ ) + { + m_aSubgroups[n]->UpdateGroupAndSubgroupsLines(); + } +} + +void wxFileConfigGroup::Rename(const wxString& newName) +{ + wxCHECK_RET( m_pParent, _T("the root group can't be renamed") ); + + if ( newName == m_strName ) + return; + + // we need to remove the group from the parent and it back under the new + // name to keep the parents array of subgroups alphabetically sorted + m_pParent->m_aSubgroups.Remove(this); + + m_strName = newName; + + m_pParent->m_aSubgroups.Add(this); + + // update the group lines recursively + UpdateGroupAndSubgroupsLines(); +} + +wxString wxFileConfigGroup::GetFullName() const +{ + wxString fullname; + if ( Parent() ) + fullname = Parent()->GetFullName() + wxCONFIG_PATH_SEPARATOR + Name(); + + return fullname; +} + +// ---------------------------------------------------------------------------- +// find an item +// ---------------------------------------------------------------------------- + +// use binary search because the array is sorted +wxFileConfigEntry * +wxFileConfigGroup::FindEntry(const wxChar *szName) const +{ + size_t i, + lo = 0, + hi = m_aEntries.Count(); + int res; + wxFileConfigEntry *pEntry; + + while ( lo < hi ) { + i = (lo + hi)/2; + pEntry = m_aEntries[i]; + + #if wxCONFIG_CASE_SENSITIVE + res = wxStrcmp(pEntry->Name(), szName); + #else + res = wxStricmp(pEntry->Name(), szName); + #endif + + if ( res > 0 ) + hi = i; + else if ( res < 0 ) + lo = i + 1; + else + return pEntry; + } + + return NULL; +} + +wxFileConfigGroup * +wxFileConfigGroup::FindSubgroup(const wxChar *szName) const +{ + size_t i, + lo = 0, + hi = m_aSubgroups.Count(); + int res; + wxFileConfigGroup *pGroup; + + while ( lo < hi ) { + i = (lo + hi)/2; + pGroup = m_aSubgroups[i]; + + #if wxCONFIG_CASE_SENSITIVE + res = wxStrcmp(pGroup->Name(), szName); + #else + res = wxStricmp(pGroup->Name(), szName); + #endif + + if ( res > 0 ) + hi = i; + else if ( res < 0 ) + lo = i + 1; + else + return pGroup; + } + + return NULL; +} + +// ---------------------------------------------------------------------------- +// create a new item +// ---------------------------------------------------------------------------- + +// create a new entry and add it to the current group +wxFileConfigEntry *wxFileConfigGroup::AddEntry(const wxString& strName, int nLine) +{ + wxASSERT( FindEntry(strName) == 0 ); + + wxFileConfigEntry *pEntry = new wxFileConfigEntry(this, strName, nLine); + + m_aEntries.Add(pEntry); + return pEntry; +} + +// create a new group and add it to the current group +wxFileConfigGroup *wxFileConfigGroup::AddSubgroup(const wxString& strName) +{ + wxASSERT( FindSubgroup(strName) == 0 ); + + wxFileConfigGroup *pGroup = new wxFileConfigGroup(this, strName, m_pConfig); + + m_aSubgroups.Add(pGroup); + return pGroup; +} + +// ---------------------------------------------------------------------------- +// delete an item +// ---------------------------------------------------------------------------- + +/* + The delete operations are _very_ slow if we delete the last item of this + group (see comments before GetXXXLineXXX functions for more details), + so it's much better to start with the first entry/group if we want to + delete several of them. + */ + +bool wxFileConfigGroup::DeleteSubgroupByName(const wxChar *szName) +{ + wxFileConfigGroup * const pGroup = FindSubgroup(szName); + + return pGroup ? DeleteSubgroup(pGroup) : false; +} + +// Delete the subgroup and remove all references to it from +// other data structures. +bool wxFileConfigGroup::DeleteSubgroup(wxFileConfigGroup *pGroup) +{ + wxCHECK_MSG( pGroup, false, _T("deleting non existing group?") ); + + wxLogTrace( FILECONF_TRACE_MASK, + _T("Deleting group '%s' from '%s'"), + pGroup->Name().c_str(), + Name().c_str() ); + + wxLogTrace( FILECONF_TRACE_MASK, + _T(" (m_pLine) = prev: %p, this %p, next %p"), + m_pLine ? wx_static_cast(void*, m_pLine->Prev()) : 0, + wx_static_cast(void*, m_pLine), + m_pLine ? wx_static_cast(void*, m_pLine->Next()) : 0 ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" text: '%s'"), + m_pLine ? m_pLine->Text().c_str() : wxEmptyString ); + + // delete all entries... + size_t nCount = pGroup->m_aEntries.Count(); + + wxLogTrace(FILECONF_TRACE_MASK, + _T("Removing %lu entries"), (unsigned long)nCount ); + + for ( size_t nEntry = 0; nEntry < nCount; nEntry++ ) + { + wxFileConfigLineList *pLine = pGroup->m_aEntries[nEntry]->GetLine(); + + if ( pLine ) + { + wxLogTrace( FILECONF_TRACE_MASK, + _T(" '%s'"), + pLine->Text().c_str() ); + m_pConfig->LineListRemove(pLine); + } + } + + // ...and subgroups of this subgroup + nCount = pGroup->m_aSubgroups.Count(); + + wxLogTrace( FILECONF_TRACE_MASK, + _T("Removing %lu subgroups"), (unsigned long)nCount ); + + for ( size_t nGroup = 0; nGroup < nCount; nGroup++ ) + { + pGroup->DeleteSubgroup(pGroup->m_aSubgroups[0]); + } + + // and then finally the group itself + wxFileConfigLineList *pLine = pGroup->m_pLine; + if ( pLine ) + { + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Removing line for group '%s' : '%s'"), + pGroup->Name().c_str(), + pLine->Text().c_str() ); + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Removing from group '%s' : '%s'"), + Name().c_str(), + ((m_pLine) ? m_pLine->Text().c_str() : wxEmptyString) ); + + // notice that we may do this test inside the previous "if" + // because the last entry's line is surely !NULL + if ( pGroup == m_pLastGroup ) + { + wxLogTrace( FILECONF_TRACE_MASK, + _T(" Removing last group") ); + + // our last entry is being deleted, so find the last one which + // stays by going back until we find a subgroup or reach the + // group line + const size_t nSubgroups = m_aSubgroups.Count(); + + m_pLastGroup = NULL; + for ( wxFileConfigLineList *pl = pLine->Prev(); + pl && !m_pLastGroup; + pl = pl->Prev() ) + { + // does this line belong to our subgroup? + for ( size_t n = 0; n < nSubgroups; n++ ) + { + // do _not_ call GetGroupLine! we don't want to add it to + // the local file if it's not already there + if ( m_aSubgroups[n]->m_pLine == pl ) + { + m_pLastGroup = m_aSubgroups[n]; + break; + } + } + + if ( pl == m_pLine ) + break; + } + } + + m_pConfig->LineListRemove(pLine); + } + else + { + wxLogTrace( FILECONF_TRACE_MASK, + _T(" No line entry for Group '%s'?"), + pGroup->Name().c_str() ); + } + + m_aSubgroups.Remove(pGroup); + delete pGroup; + + return true; +} + +bool wxFileConfigGroup::DeleteEntry(const wxChar *szName) +{ + wxFileConfigEntry *pEntry = FindEntry(szName); + if ( !pEntry ) + { + // entry doesn't exist, nothing to do + return false; + } + + wxFileConfigLineList *pLine = pEntry->GetLine(); + if ( pLine != NULL ) { + // notice that we may do this test inside the previous "if" because the + // last entry's line is surely !NULL + if ( pEntry == m_pLastEntry ) { + // our last entry is being deleted - find the last one which stays + wxASSERT( m_pLine != NULL ); // if we have an entry with !NULL pLine... + + // find the previous entry (if any) + wxFileConfigEntry *pNewLast = NULL; + const wxFileConfigLineList * const + pNewLastLine = m_pLastEntry->GetLine()->Prev(); + const size_t nEntries = m_aEntries.GetCount(); + for ( size_t n = 0; n < nEntries; n++ ) { + if ( m_aEntries[n]->GetLine() == pNewLastLine ) { + pNewLast = m_aEntries[n]; + break; + } + } + + // pNewLast can be NULL here -- it's ok and can happen if we have no + // entries left + m_pLastEntry = pNewLast; + } + + m_pConfig->LineListRemove(pLine); + } + + m_aEntries.Remove(pEntry); + delete pEntry; + + return true; +} + +// ============================================================================ +// wxFileConfig::wxFileConfigEntry +// ============================================================================ + +// ---------------------------------------------------------------------------- +// ctor +// ---------------------------------------------------------------------------- +wxFileConfigEntry::wxFileConfigEntry(wxFileConfigGroup *pParent, + const wxString& strName, + int nLine) + : m_strName(strName) +{ + wxASSERT( !strName.empty() ); + + m_pParent = pParent; + m_nLine = nLine; + m_pLine = NULL; + + m_bHasValue = false; + + m_bImmutable = strName[0] == wxCONFIG_IMMUTABLE_PREFIX; + if ( m_bImmutable ) + m_strName.erase(0, 1); // remove first character +} + +// ---------------------------------------------------------------------------- +// set value +// ---------------------------------------------------------------------------- + +void wxFileConfigEntry::SetLine(wxFileConfigLineList *pLine) +{ + if ( m_pLine != NULL ) { + wxLogWarning(_("entry '%s' appears more than once in group '%s'"), + Name().c_str(), m_pParent->GetFullName().c_str()); + } + + m_pLine = pLine; + Group()->SetLastEntry(this); +} + +// second parameter is false if we read the value from file and prevents the +// entry from being marked as 'dirty' +void wxFileConfigEntry::SetValue(const wxString& strValue, bool bUser) +{ + if ( bUser && IsImmutable() ) + { + wxLogWarning( _("attempt to change immutable key '%s' ignored."), + Name().c_str()); + return; + } + + // do nothing if it's the same value: but don't test for it if m_bHasValue + // hadn't been set yet or we'd never write empty values to the file + if ( m_bHasValue && strValue == m_strValue ) + return; + + m_bHasValue = true; + m_strValue = strValue; + + if ( bUser ) + { + wxString strValFiltered; + + if ( Group()->Config()->GetStyle() & wxCONFIG_USE_NO_ESCAPE_CHARACTERS ) + { + strValFiltered = strValue; + } + else { + strValFiltered = FilterOutValue(strValue); + } + + wxString strLine; + strLine << FilterOutEntryName(m_strName) << wxT('=') << strValFiltered; + + if ( m_pLine ) + { + // entry was read from the local config file, just modify the line + m_pLine->SetText(strLine); + } + else // this entry didn't exist in the local file + { + // add a new line to the file: note that line returned by + // GetLastEntryLine() may be NULL if we're in the root group and it + // doesn't have any entries yet, but this is ok as passing NULL + // line to LineListInsert() means to prepend new line to the list + wxFileConfigLineList *line = Group()->GetLastEntryLine(); + m_pLine = Group()->Config()->LineListInsert(strLine, line); + + Group()->SetLastEntry(this); + } + } +} + +// ============================================================================ +// global functions +// ============================================================================ + +// ---------------------------------------------------------------------------- +// compare functions for array sorting +// ---------------------------------------------------------------------------- + +int CompareEntries(wxFileConfigEntry *p1, wxFileConfigEntry *p2) +{ +#if wxCONFIG_CASE_SENSITIVE + return wxStrcmp(p1->Name(), p2->Name()); +#else + return wxStricmp(p1->Name(), p2->Name()); +#endif +} + +int CompareGroups(wxFileConfigGroup *p1, wxFileConfigGroup *p2) +{ +#if wxCONFIG_CASE_SENSITIVE + return wxStrcmp(p1->Name(), p2->Name()); +#else + return wxStricmp(p1->Name(), p2->Name()); +#endif +} + +// ---------------------------------------------------------------------------- +// filter functions +// ---------------------------------------------------------------------------- + +// undo FilterOutValue +static wxString FilterInValue(const wxString& str) +{ + wxString strResult; + strResult.Alloc(str.Len()); + + bool bQuoted = !str.empty() && str[0] == '"'; + + for ( size_t n = bQuoted ? 1 : 0; n < str.Len(); n++ ) { + if ( str[n] == wxT('\\') ) { + switch ( str[++n] ) { + case wxT('n'): + strResult += wxT('\n'); + break; + + case wxT('r'): + strResult += wxT('\r'); + break; + + case wxT('t'): + strResult += wxT('\t'); + break; + + case wxT('\\'): + strResult += wxT('\\'); + break; + + case wxT('"'): + strResult += wxT('"'); + break; + } + } + else { + if ( str[n] != wxT('"') || !bQuoted ) + strResult += str[n]; + else if ( n != str.Len() - 1 ) { + wxLogWarning(_("unexpected \" at position %d in '%s'."), + n, str.c_str()); + } + //else: it's the last quote of a quoted string, ok + } + } + + return strResult; +} + +// quote the string before writing it to file +static wxString FilterOutValue(const wxString& str) +{ + if ( !str ) + return str; + + wxString strResult; + strResult.Alloc(str.Len()); + + // quoting is necessary to preserve spaces in the beginning of the string + bool bQuote = wxIsspace(str[0]) || str[0] == wxT('"'); + + if ( bQuote ) + strResult += wxT('"'); + + wxChar c; + for ( size_t n = 0; n < str.Len(); n++ ) { + switch ( str[n] ) { + case wxT('\n'): + c = wxT('n'); + break; + + case wxT('\r'): + c = wxT('r'); + break; + + case wxT('\t'): + c = wxT('t'); + break; + + case wxT('\\'): + c = wxT('\\'); + break; + + case wxT('"'): + if ( bQuote ) { + c = wxT('"'); + break; + } + //else: fall through + + default: + strResult += str[n]; + continue; // nothing special to do + } + + // we get here only for special characters + strResult << wxT('\\') << c; + } + + if ( bQuote ) + strResult += wxT('"'); + + return strResult; +} + +// undo FilterOutEntryName +static wxString FilterInEntryName(const wxString& str) +{ + wxString strResult; + strResult.Alloc(str.Len()); + + for ( const wxChar *pc = str.c_str(); *pc != '\0'; pc++ ) { + if ( *pc == wxT('\\') ) { + // we need to test it here or we'd skip past the NUL in the loop line + if ( *++pc == _T('\0') ) + break; + } + + strResult += *pc; + } + + return strResult; +} + +// sanitize entry or group name: insert '\\' before any special characters +static wxString FilterOutEntryName(const wxString& str) +{ + wxString strResult; + strResult.Alloc(str.Len()); + + for ( const wxChar *pc = str.c_str(); *pc != wxT('\0'); pc++ ) { + const wxChar c = *pc; + + // we explicitly allow some of "safe" chars and 8bit ASCII characters + // which will probably never have special meaning and with which we can't + // use isalnum() anyhow (in ASCII built, in Unicode it's just fine) + // + // NB: note that wxCONFIG_IMMUTABLE_PREFIX and wxCONFIG_PATH_SEPARATOR + // should *not* be quoted + if ( +#if !wxUSE_UNICODE + ((unsigned char)c < 127) && +#endif // ANSI + !wxIsalnum(c) && !wxStrchr(wxT("@_/-!.*%"), c) ) + { + strResult += wxT('\\'); + } + + strResult += c; + } + + return strResult; +} + +// we can't put ?: in the ctor initializer list because it confuses some +// broken compilers (Borland C++) +static wxString GetAppName(const wxString& appName) +{ + if ( !appName && wxTheApp ) + return wxTheApp->GetAppName(); + else + return appName; +} + +#endif // wxUSE_CONFIG diff --git a/Source/3rd Party/wx/src/common/filefn.cpp b/Source/3rd Party/wx/src/common/filefn.cpp index cde0cb4d2..b9700d4c4 100644 --- a/Source/3rd Party/wx/src/common/filefn.cpp +++ b/Source/3rd Party/wx/src/common/filefn.cpp @@ -1,2123 +1,2123 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/filefn.cpp -// Purpose: File- and directory-related functions -// Author: Julian Smart -// Modified by: -// Created: 29/01/98 -// RCS-ID: $Id: filefn.cpp 66990 2011-02-22 12:10:44Z JS $ -// Copyright: (c) 1998 Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/filefn.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" -#endif - -#include "wx/file.h" -#include "wx/filename.h" -#include "wx/dir.h" - -#include "wx/tokenzr.h" - -// there are just too many of those... -#ifdef __VISUALC__ - #pragma warning(disable:4706) // assignment within conditional expression -#endif // VC++ - -#include -#include -#include -#include -#if !wxONLY_WATCOM_EARLIER_THAN(1,4) - #if !(defined(_MSC_VER) && (_MSC_VER > 800)) - #include - #endif -#endif - -#if defined(__WXMAC__) - #include "wx/mac/private.h" // includes mac headers -#endif - -#ifdef __WINDOWS__ - #include "wx/msw/private.h" - #include "wx/msw/mslu.h" - - // sys/cygwin.h is needed for cygwin_conv_to_full_win32_path() - // - // note that it must be included after - #ifdef __GNUWIN32__ - #ifdef __CYGWIN__ - #include - #endif - #endif // __GNUWIN32__ - - // io.h is needed for _get_osfhandle() - // Already included by filefn.h for many Windows compilers - #if defined __MWERKS__ || defined __CYGWIN__ - #include - #endif -#endif // __WINDOWS__ - -#if defined(__VMS__) - #include -#endif - -// TODO: Borland probably has _wgetcwd as well? -#ifdef _MSC_VER - #define HAVE_WGETCWD -#endif - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -#ifndef _MAXPATHLEN - #define _MAXPATHLEN 1024 -#endif - -#ifdef __WXMAC__ -# include "MoreFilesX.h" -#endif - -// ---------------------------------------------------------------------------- -// private globals -// ---------------------------------------------------------------------------- - -// MT-FIXME: get rid of this horror and all code using it -static wxChar wxFileFunctionsBuffer[4*_MAXPATHLEN]; - -#if defined(__VISAGECPP__) && __IBMCPP__ >= 400 -// -// VisualAge C++ V4.0 cannot have any external linkage const decs -// in headers included by more than one primary source -// -const int wxInvalidOffset = -1; -#endif - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- - -// translate the filenames before passing them to OS functions -#define OS_FILENAME(s) (s.fn_str()) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wrappers around standard POSIX functions -// ---------------------------------------------------------------------------- - -#ifdef wxNEED_WX_UNISTD_H - -WXDLLEXPORT int wxStat( const wxChar *file_name, wxStructStat *buf ) -{ - return stat( wxConvFile.cWX2MB( file_name ), buf ); -} - -WXDLLEXPORT int wxLstat( const wxChar *file_name, wxStructStat *buf ) -{ - return lstat( wxConvFile.cWX2MB( file_name ), buf ); -} - -WXDLLEXPORT int wxAccess( const wxChar *pathname, int mode ) -{ - return access( wxConvFile.cWX2MB( pathname ), mode ); -} - -WXDLLEXPORT int wxOpen( const wxChar *pathname, int flags, mode_t mode ) -{ - return open( wxConvFile.cWX2MB( pathname ), flags, mode ); -} - -#endif // wxNEED_WX_UNISTD_H - -#if wxUSE_UNICODE && defined __BORLANDC__ \ - && __BORLANDC__ >= 0x550 && __BORLANDC__ <= 0x551 - -// BCC 5.5 and 5.5.1 have a bug in _wopen where files are created read only -// regardless of the mode parameter. This hack works around the problem by -// setting the mode with _wchmod. -// -int wxOpen(const wchar_t *pathname, int flags, mode_t mode) -{ - int moreflags = 0; - - // we only want to fix the mode when the file is actually created, so - // when creating first try doing it O_EXCL so we can tell if the file - // was already there. - if ((flags & O_CREAT) && !(flags & O_EXCL) && (mode & wxS_IWUSR) != 0) - moreflags = O_EXCL; - - int fd = _wopen(pathname, flags | moreflags, mode); - - // the file was actually created and needs fixing - if (fd != -1 && (flags & O_CREAT) != 0 && (mode & wxS_IWUSR) != 0) - { - close(fd); - _wchmod(pathname, mode); - fd = _wopen(pathname, flags & ~(O_EXCL | O_CREAT)); - } - // the open failed, but it may have been because the added O_EXCL stopped - // the opening of an existing file, so try again without. - else if (fd == -1 && moreflags != 0) - { - fd = _wopen(pathname, flags & ~O_CREAT); - } - - return fd; -} - -#endif - -// ---------------------------------------------------------------------------- -// wxPathList -// ---------------------------------------------------------------------------- - -bool wxPathList::Add(const wxString& path) -{ - // add a path separator to force wxFileName to interpret it always as a directory - // (i.e. if we are called with '/home/user' we want to consider it a folder and - // not, as wxFileName would consider, a filename). - wxFileName fn(path + wxFileName::GetPathSeparator()); - - // add only normalized relative/absolute paths - // NB: we won't do wxPATH_NORM_DOTS in order to avoid problems when trying to - // normalize paths which starts with ".." (which can be normalized only if - // we use also wxPATH_NORM_ABSOLUTE - which we don't want to use). - if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS)) - return false; - - wxString toadd = fn.GetPath(); - if (Index(toadd) == wxNOT_FOUND) - wxArrayString::Add(toadd); // do not add duplicates - - return true; -} - -void wxPathList::Add(const wxArrayString &arr) -{ - for (size_t j=0; j < arr.GetCount(); j++) - Add(arr[j]); -} - -// Add paths e.g. from the PATH environment variable -void wxPathList::AddEnvList (const wxString& WXUNUSED_IN_WINCE(envVariable)) -{ - // No environment variables on WinCE -#ifndef __WXWINCE__ - - // The space has been removed from the tokenizers, otherwise a - // path such as "C:\Program Files" would be split into 2 paths: - // "C:\Program" and "Files"; this is true for both Windows and Unix. - - static const wxChar PATH_TOKS[] = -#if defined(__WINDOWS__) || defined(__OS2__) - wxT(";"); // Don't separate with colon in DOS (used for drive) -#else - wxT(":;"); -#endif - - wxString val; - if ( wxGetEnv(envVariable, &val) ) - { - // split into an array of string the value of the env var - wxArrayString arr = wxStringTokenize(val, PATH_TOKS); - WX_APPEND_ARRAY(*this, arr); - } -#endif // !__WXWINCE__ -} - -// Given a full filename (with path), ensure that that file can -// be accessed again USING FILENAME ONLY by adding the path -// to the list if not already there. -bool wxPathList::EnsureFileAccessible (const wxString& path) -{ - return Add(wxPathOnly(path)); -} - -#if WXWIN_COMPATIBILITY_2_6 -bool wxPathList::Member (const wxString& path) const -{ - return Index(path) != wxNOT_FOUND; -} -#endif - -wxString wxPathList::FindValidPath (const wxString& file) const -{ - // normalize the given string as it could be a path + a filename - // and not only a filename - wxFileName fn(file); - wxString strend; - - // NB: normalize without making absolute otherwise calling this function with - // e.g. "b/c.txt" would result in removing the directory 'b' and the for loop - // below would only add to the paths of this list the 'c.txt' part when doing - // the existence checks... - // NB: we don't use wxPATH_NORM_DOTS here, too (see wxPathList::Add for more info) - if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS)) - return wxEmptyString; - - wxASSERT_MSG(!fn.IsDir(), wxT("Cannot search for directories; only for files")); - if (fn.IsAbsolute()) - strend = fn.GetFullName(); // search for the file name and ignore the path part - else - strend = fn.GetFullPath(); - - for (size_t i=0; i 0) - { - if (buffer[i] == wxT('.')) - { - buffer[i] = 0; - break; - } - i --; - } -} - -void wxStripExtension(wxString& buffer) -{ - //RN: Be careful about the handling the case where - //buffer.length() == 0 - for(size_t i = buffer.length() - 1; i != wxString::npos; --i) - { - if (buffer.GetChar(i) == wxT('.')) - { - buffer = buffer.Left(i); - break; - } - } -} - -// Destructive removal of /./ and /../ stuff -wxChar *wxRealPath (wxChar *path) -{ -#ifdef __WXMSW__ - static const wxChar SEP = wxT('\\'); - wxUnix2DosFilename(path); -#else - static const wxChar SEP = wxT('/'); -#endif - if (path[0] && path[1]) { - /* MATTHEW: special case "/./x" */ - wxChar *p; - if (path[2] == SEP && path[1] == wxT('.')) - p = &path[0]; - else - p = &path[2]; - for (; *p; p++) - { - if (*p == SEP) - { - if (p[1] == wxT('.') && p[2] == wxT('.') && (p[3] == SEP || p[3] == wxT('\0'))) - { - wxChar *q; - for (q = p - 1; q >= path && *q != SEP; q--) - { - // Empty - } - - if (q[0] == SEP && (q[1] != wxT('.') || q[2] != wxT('.') || q[3] != SEP) - && (q - 1 <= path || q[-1] != SEP)) - { - wxStrcpy (q, p + 3); - if (path[0] == wxT('\0')) - { - path[0] = SEP; - path[1] = wxT('\0'); - } -#if defined(__WXMSW__) || defined(__OS2__) - /* Check that path[2] is NULL! */ - else if (path[1] == wxT(':') && !path[2]) - { - path[2] = SEP; - path[3] = wxT('\0'); - } -#endif - p = q - 1; - } - } - else if (p[1] == wxT('.') && (p[2] == SEP || p[2] == wxT('\0'))) - wxStrcpy (p, p + 2); - } - } - } - return path; -} - -wxString wxRealPath(const wxString& path) -{ - wxChar *buf1=MYcopystring(path); - wxChar *buf2=wxRealPath(buf1); - wxString buf(buf2); - delete [] buf1; - return buf; -} - - -// Must be destroyed -wxChar *wxCopyAbsolutePath(const wxString& filename) -{ - if (filename.empty()) - return (wxChar *) NULL; - - if (! wxIsAbsolutePath(wxExpandPath(wxFileFunctionsBuffer, filename))) - { - wxString buf = ::wxGetCwd(); - wxChar ch = buf.Last(); -#ifdef __WXMSW__ - if (ch != wxT('\\') && ch != wxT('/')) - buf << wxT("\\"); -#else - if (ch != wxT('/')) - buf << wxT("/"); -#endif - buf << wxFileFunctionsBuffer; - buf = wxRealPath( buf ); - return MYcopystring( buf ); - } - return MYcopystring( wxFileFunctionsBuffer ); -} - -/*- - Handles: - ~/ => home dir - ~user/ => user's home dir - If the environment variable a = "foo" and b = "bar" then: - Unix: - $a => foo - $a$b => foobar - $a.c => foo.c - xxx$a => xxxfoo - ${a}! => foo! - $(b)! => bar! - \$a => \$a - MSDOS: - $a ==> $a - $(a) ==> foo - $(a)$b ==> foo$b - $(a)$(b)==> foobar - test.$$ ==> test.$$ - */ - -/* input name in name, pathname output to buf. */ - -wxChar *wxExpandPath(wxChar *buf, const wxChar *name) -{ - register wxChar *d, *s, *nm; - wxChar lnm[_MAXPATHLEN]; - int q; - - // Some compilers don't like this line. -// const wxChar trimchars[] = wxT("\n \t"); - - wxChar trimchars[4]; - trimchars[0] = wxT('\n'); - trimchars[1] = wxT(' '); - trimchars[2] = wxT('\t'); - trimchars[3] = 0; - -#ifdef __WXMSW__ - const wxChar SEP = wxT('\\'); -#else - const wxChar SEP = wxT('/'); -#endif - buf[0] = wxT('\0'); - if (name == NULL || *name == wxT('\0')) - return buf; - nm = MYcopystring(name); // Make a scratch copy - wxChar *nm_tmp = nm; - - /* Skip leading whitespace and cr */ - while (wxStrchr((wxChar *)trimchars, *nm) != NULL) - nm++; - /* And strip off trailing whitespace and cr */ - s = nm + (q = wxStrlen(nm)) - 1; - while (q-- && wxStrchr((wxChar *)trimchars, *s) != NULL) - *s = wxT('\0'); - - s = nm; - d = lnm; -#ifdef __WXMSW__ - q = FALSE; -#else - q = nm[0] == wxT('\\') && nm[1] == wxT('~'); -#endif - - /* Expand inline environment variables */ -#ifdef __VISAGECPP__ - while (*d) - { - *d++ = *s; - if(*s == wxT('\\')) - { - *(d - 1) = *++s; - if (*d) - { - s++; - continue; - } - else - break; - } - else -#else - while ((*d++ = *s) != 0) { -# ifndef __WXMSW__ - if (*s == wxT('\\')) { - if ((*(d - 1) = *++s)!=0) { - s++; - continue; - } else - break; - } else -# endif -#endif - // No env variables on WinCE -#ifndef __WXWINCE__ -#ifdef __WXMSW__ - if (*s++ == wxT('$') && (*s == wxT('{') || *s == wxT(')'))) -#else - if (*s++ == wxT('$')) -#endif - { - register wxChar *start = d; - register int braces = (*s == wxT('{') || *s == wxT('(')); - register wxChar *value; - while ((*d++ = *s) != 0) - if (braces ? (*s == wxT('}') || *s == wxT(')')) : !(wxIsalnum(*s) || *s == wxT('_')) ) - break; - else - s++; - *--d = 0; - value = wxGetenv(braces ? start + 1 : start); - if (value) { - for ((d = start - 1); (*d++ = *value++) != 0;) - { - // Empty - } - - d--; - if (braces && *s) - s++; - } - } -#endif - // __WXWINCE__ - } - - /* Expand ~ and ~user */ - nm = lnm; - if (nm[0] == wxT('~') && !q) - { - /* prefix ~ */ - if (nm[1] == SEP || nm[1] == 0) - { /* ~/filename */ - // FIXME: wxGetUserHome could return temporary storage in Unicode mode - if ((s = WXSTRINGCAST wxGetUserHome(wxEmptyString)) != NULL) { - if (*++nm) - nm++; - } - } else - { /* ~user/filename */ - register wxChar *nnm; - register wxChar *home; - for (s = nm; *s && *s != SEP; s++) - { - // Empty - } - int was_sep; /* MATTHEW: Was there a separator, or NULL? */ - was_sep = (*s == SEP); - nnm = *s ? s + 1 : s; - *s = 0; - // FIXME: wxGetUserHome could return temporary storage in Unicode mode - if ((home = WXSTRINGCAST wxGetUserHome(wxString(nm + 1))) == NULL) - { - if (was_sep) /* replace only if it was there: */ - *s = SEP; - s = NULL; - } - else - { - nm = nnm; - s = home; - } - } - } - - d = buf; - if (s && *s) { /* MATTHEW: s could be NULL if user '~' didn't exist */ - /* Copy home dir */ - while (wxT('\0') != (*d++ = *s++)) - /* loop */; - // Handle root home - if (d - 1 > buf && *(d - 2) != SEP) - *(d - 1) = SEP; - } - s = nm; - while ((*d++ = *s++) != 0) - { - // Empty - } - delete[] nm_tmp; // clean up alloc - /* Now clean up the buffer */ - return wxRealPath(buf); -} - -/* Contract Paths to be build upon an environment variable - component: - - example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib - - The call wxExpandPath can convert these back! - */ -wxChar * -wxContractPath (const wxString& filename, - const wxString& WXUNUSED_IN_WINCE(envname), - const wxString& user) -{ - static wxChar dest[_MAXPATHLEN]; - - if (filename.empty()) - return (wxChar *) NULL; - - wxStrcpy (dest, WXSTRINGCAST filename); -#ifdef __WXMSW__ - wxUnix2DosFilename(dest); -#endif - - // Handle environment - const wxChar *val; -#ifndef __WXWINCE__ - wxChar *tcp; - if (!envname.empty() && (val = wxGetenv (WXSTRINGCAST envname)) != NULL && - (tcp = wxStrstr (dest, val)) != NULL) - { - wxStrcpy (wxFileFunctionsBuffer, tcp + wxStrlen (val)); - *tcp++ = wxT('$'); - *tcp++ = wxT('{'); - wxStrcpy (tcp, WXSTRINGCAST envname); - wxStrcat (tcp, wxT("}")); - wxStrcat (tcp, wxFileFunctionsBuffer); - } -#endif - - // Handle User's home (ignore root homes!) - val = wxGetUserHome (user); - if (!val) - return dest; - - const size_t len = wxStrlen(val); - if (len <= 2) - return dest; - - if (wxStrncmp(dest, val, len) == 0) - { - wxStrcpy(wxFileFunctionsBuffer, wxT("~")); - if (!user.empty()) - wxStrcat(wxFileFunctionsBuffer, (const wxChar*) user); - wxStrcat(wxFileFunctionsBuffer, dest + len); - wxStrcpy (dest, wxFileFunctionsBuffer); - } - - return dest; -} - -// Return just the filename, not the path (basename) -wxChar *wxFileNameFromPath (wxChar *path) -{ - wxString p = path; - wxString n = wxFileNameFromPath(p); - - return path + p.length() - n.length(); -} - -wxString wxFileNameFromPath (const wxString& path) -{ - wxString name, ext; - wxFileName::SplitPath(path, NULL, &name, &ext); - - wxString fullname = name; - if ( !ext.empty() ) - { - fullname << wxFILE_SEP_EXT << ext; - } - - return fullname; -} - -// Return just the directory, or NULL if no directory -wxChar * -wxPathOnly (wxChar *path) -{ - if (path && *path) - { - static wxChar buf[_MAXPATHLEN]; - - // Local copy - wxStrcpy (buf, path); - - int l = wxStrlen(path); - int i = l - 1; - - // Search backward for a backward or forward slash - while (i > -1) - { -#if defined(__WXMAC__) && !defined(__DARWIN__) - // Classic or Carbon CodeWarrior like - // Carbon with Apple DevTools is Unix like - if (path[i] == wxT(':') ) - { - buf[i] = 0; - return buf; - } -#else - // Unix like or Windows - if (path[i] == wxT('/') || path[i] == wxT('\\')) - { - buf[i] = 0; - return buf; - } -#endif -#ifdef __VMS__ - if (path[i] == wxT(']')) - { - buf[i+1] = 0; - return buf; - } -#endif - i --; - } - -#if defined(__WXMSW__) || defined(__OS2__) - // Try Drive specifier - if (wxIsalpha (buf[0]) && buf[1] == wxT(':')) - { - // A:junk --> A:. (since A:.\junk Not A:\junk) - buf[2] = wxT('.'); - buf[3] = wxT('\0'); - return buf; - } -#endif - } - return (wxChar *) NULL; -} - -// Return just the directory, or NULL if no directory -wxString wxPathOnly (const wxString& path) -{ - if (!path.empty()) - { - wxChar buf[_MAXPATHLEN]; - - // Local copy - wxStrcpy (buf, WXSTRINGCAST path); - - int l = path.length(); - int i = l - 1; - - // Search backward for a backward or forward slash - while (i > -1) - { -#if defined(__WXMAC__) && !defined(__DARWIN__) - // Classic or Carbon CodeWarrior like - // Carbon with Apple DevTools is Unix like - if (path[i] == wxT(':') ) - { - buf[i] = 0; - return wxString(buf); - } -#else - // Unix like or Windows - if (path[i] == wxT('/') || path[i] == wxT('\\')) - { - // Don't return an empty string - if (i == 0) - i ++; - buf[i] = 0; - return wxString(buf); - } -#endif -#ifdef __VMS__ - if (path[i] == wxT(']')) - { - buf[i+1] = 0; - return wxString(buf); - } -#endif - i --; - } - -#if defined(__WXMSW__) || defined(__OS2__) - // Try Drive specifier - if (wxIsalpha (buf[0]) && buf[1] == wxT(':')) - { - // A:junk --> A:. (since A:.\junk Not A:\junk) - buf[2] = wxT('.'); - buf[3] = wxT('\0'); - return wxString(buf); - } -#endif - } - return wxEmptyString; -} - -// Utility for converting delimiters in DOS filenames to UNIX style -// and back again - or we get nasty problems with delimiters. -// Also, convert to lower case, since case is significant in UNIX. - -#if defined(__WXMAC__) - -#if TARGET_API_MAC_OSX -#define kDefaultPathStyle kCFURLPOSIXPathStyle -#else -#define kDefaultPathStyle kCFURLHFSPathStyle -#endif - -wxString wxMacFSRefToPath( const FSRef *fsRef , CFStringRef additionalPathComponent ) -{ - CFURLRef fullURLRef; - fullURLRef = CFURLCreateFromFSRef(NULL, fsRef); - if ( additionalPathComponent ) - { - CFURLRef parentURLRef = fullURLRef ; - fullURLRef = CFURLCreateCopyAppendingPathComponent(NULL, parentURLRef, - additionalPathComponent,false); - CFRelease( parentURLRef ) ; - } - CFStringRef cfString = CFURLCopyFileSystemPath(fullURLRef, kDefaultPathStyle); - CFRelease( fullURLRef ) ; - CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfString); - CFRelease( cfString ); - CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); - return wxMacCFStringHolder(cfMutableString).AsString(); -} - -OSStatus wxMacPathToFSRef( const wxString&path , FSRef *fsRef ) -{ - OSStatus err = noErr ; - CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, wxMacCFStringHolder(path)); - CFStringNormalize(cfMutableString,kCFStringNormalizationFormD); - CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfMutableString , kDefaultPathStyle, false); - CFRelease( cfMutableString ); - if ( NULL != url ) - { - if ( CFURLGetFSRef(url, fsRef) == false ) - err = fnfErr ; - CFRelease( url ) ; - } - else - { - err = fnfErr ; - } - return err ; -} - -wxString wxMacHFSUniStrToString( ConstHFSUniStr255Param uniname ) -{ - CFStringRef cfname = CFStringCreateWithCharacters( kCFAllocatorDefault, - uniname->unicode, - uniname->length ); - CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfname); - CFRelease( cfname ); - CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); - return wxMacCFStringHolder(cfMutableString).AsString() ; -} - -#ifndef __LP64__ - -wxString wxMacFSSpec2MacFilename( const FSSpec *spec ) -{ - FSRef fsRef ; - if ( FSpMakeFSRef( spec , &fsRef) == noErr ) - { - return wxMacFSRefToPath( &fsRef ) ; - } - return wxEmptyString ; -} - -void wxMacFilename2FSSpec( const wxString& path , FSSpec *spec ) -{ - OSStatus err = noErr ; - FSRef fsRef ; - wxMacPathToFSRef( path , &fsRef ) ; - err = FSRefMakeFSSpec( &fsRef , spec ) ; -} -#endif - -#endif // __WXMAC__ - -void -wxDos2UnixFilename (wxChar *s) -{ - if (s) - while (*s) - { - if (*s == _T('\\')) - *s = _T('/'); -#ifdef __WXMSW__ - else - *s = (wxChar)wxTolower (*s); // Case INDEPENDENT -#endif - s++; - } -} - -void -#if defined(__WXMSW__) || defined(__OS2__) -wxUnix2DosFilename (wxChar *s) -#else -wxUnix2DosFilename (wxChar *WXUNUSED(s) ) -#endif -{ -// Yes, I really mean this to happen under DOS only! JACS -#if defined(__WXMSW__) || defined(__OS2__) - if (s) - while (*s) - { - if (*s == wxT('/')) - *s = wxT('\\'); - s++; - } -#endif -} - -// Concatenate two files to form third -bool -wxConcatFiles (const wxString& file1, const wxString& file2, const wxString& file3) -{ -#if wxUSE_FILE - - wxFile in1(file1), in2(file2); - wxTempFile out(file3); - - if ( !in1.IsOpened() || !in2.IsOpened() || !out.IsOpened() ) - return false; - - ssize_t ofs; - unsigned char buf[1024]; - - for( int i=0; i<2; i++) - { - wxFile *in = i==0 ? &in1 : &in2; - do{ - if ( (ofs = in->Read(buf,WXSIZEOF(buf))) == wxInvalidOffset ) return false; - if ( ofs > 0 ) - if ( !out.Write(buf,ofs) ) - return false; - } while ( ofs == (ssize_t)WXSIZEOF(buf) ); - } - - return out.Commit(); - -#else - - wxUnusedVar(file1); - wxUnusedVar(file2); - wxUnusedVar(file3); - return false; - -#endif -} - -// Copy files -bool -wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite) -{ -#if defined(__WIN32__) && !defined(__WXMICROWIN__) - // CopyFile() copies file attributes and modification time too, so use it - // instead of our code if available - // - // NB: 3rd parameter is bFailIfExists i.e. the inverse of overwrite - if ( !::CopyFile(file1, file2, !overwrite) ) - { - wxLogSysError(_("Failed to copy the file '%s' to '%s'"), - file1.c_str(), file2.c_str()); - - return false; - } -#elif defined(__OS2__) - if ( ::DosCopy((PSZ)file1.c_str(), (PSZ)file2.c_str(), overwrite ? DCPY_EXISTING : 0) != 0 ) - return false; -#elif defined(__PALMOS__) - // TODO with http://www.palmos.com/dev/support/docs/protein_books/Memory_Databases_Files/ - return false; -#elif wxUSE_FILE // !Win32 - - wxStructStat fbuf; - // get permissions of file1 - if ( wxStat( file1.c_str(), &fbuf) != 0 ) - { - // the file probably doesn't exist or we haven't the rights to read - // from it anyhow - wxLogSysError(_("Impossible to get permissions for file '%s'"), - file1.c_str()); - return false; - } - - // open file1 for reading - wxFile fileIn(file1, wxFile::read); - if ( !fileIn.IsOpened() ) - return false; - - // remove file2, if it exists. This is needed for creating - // file2 with the correct permissions in the next step - if ( wxFileExists(file2) && (!overwrite || !wxRemoveFile(file2))) - { - wxLogSysError(_("Impossible to overwrite the file '%s'"), - file2.c_str()); - return false; - } - - // reset the umask as we want to create the file with exactly the same - // permissions as the original one - wxCHANGE_UMASK(0); - - // create file2 with the same permissions than file1 and open it for - // writing - - wxFile fileOut; - if ( !fileOut.Create(file2, overwrite, fbuf.st_mode & 0777) ) - return false; - - // copy contents of file1 to file2 - char buf[4096]; - size_t count; - for ( ;; ) - { - count = fileIn.Read(buf, WXSIZEOF(buf)); - if ( fileIn.Error() ) - return false; - - // end of file? - if ( !count ) - break; - - if ( fileOut.Write(buf, count) < count ) - return false; - } - - // we can expect fileIn to be closed successfully, but we should ensure - // that fileOut was closed as some write errors (disk full) might not be - // detected before doing this - if ( !fileIn.Close() || !fileOut.Close() ) - return false; - -#if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__) - // no chmod in VA. Should be some permission API for HPFS386 partitions - // however - if ( chmod(OS_FILENAME(file2), fbuf.st_mode) != 0 ) - { - wxLogSysError(_("Impossible to set permissions for the file '%s'"), - file2.c_str()); - return false; - } -#endif // OS/2 || Mac - -#else // !Win32 && ! wxUSE_FILE - - // impossible to simulate with wxWidgets API - wxUnusedVar(file1); - wxUnusedVar(file2); - wxUnusedVar(overwrite); - return false; - -#endif // __WXMSW__ && __WIN32__ - - return true; -} - -bool -wxRenameFile(const wxString& file1, const wxString& file2, bool overwrite) -{ - if ( !overwrite && wxFileExists(file2) ) - { - wxLogSysError - ( - _("Failed to rename the file '%s' to '%s' because the destination file already exists."), - file1.c_str(), file2.c_str() - ); - - return false; - } - -#if !defined(__WXWINCE__) && !defined(__WXPALMOS__) - // Normal system call - if ( wxRename (file1, file2) == 0 ) - return true; -#endif - - // Try to copy - if (wxCopyFile(file1, file2, overwrite)) { - wxRemoveFile(file1); - return true; - } - // Give up - return false; -} - -bool wxRemoveFile(const wxString& file) -{ -#if defined(__VISUALC__) \ - || defined(__BORLANDC__) \ - || defined(__WATCOMC__) \ - || defined(__DMC__) \ - || defined(__GNUWIN32__) \ - || (defined(__MWERKS__) && defined(__MSL__)) - int res = wxRemove(file); -#elif defined(__WXMAC__) - int res = unlink(wxFNCONV(file)); -#elif defined(__WXPALMOS__) - int res = 1; - // TODO with VFSFileDelete() -#else - int res = unlink(OS_FILENAME(file)); -#endif - - return res == 0; -} - -bool wxMkdir(const wxString& dir, int perm) -{ -#if defined(__WXPALMOS__) - return false; -#elif defined(__WXMAC__) && !defined(__UNIX__) - return (mkdir( wxFNCONV(dir) , 0 ) == 0); -#else // !Mac - const wxChar *dirname = dir.c_str(); - - // assume mkdir() has 2 args on non Windows-OS/2 platforms and on Windows too - // for the GNU compiler -#if (!(defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__))) || (defined(__GNUWIN32__) && !defined(__MINGW32__)) || defined(__WINE__) || defined(__WXMICROWIN__) - #if defined(MSVCRT) - wxUnusedVar(perm); - if ( mkdir(wxFNCONV(dirname)) != 0 ) - #else - if ( mkdir(wxFNCONV(dirname), perm) != 0 ) - #endif -#elif defined(__OS2__) - wxUnusedVar(perm); - if (::DosCreateDir((PSZ)dirname, NULL) != 0) // enhance for EAB's?? -#elif defined(__DOS__) - #if defined(__WATCOMC__) - (void)perm; - if ( wxMkDir(wxFNSTRINGCAST wxFNCONV(dirname)) != 0 ) - #elif defined(__DJGPP__) - if ( mkdir(wxFNCONV(dirname), perm) != 0 ) - #else - #error "Unsupported DOS compiler!" - #endif -#else // !MSW, !DOS and !OS/2 VAC++ - wxUnusedVar(perm); -#ifdef __WXWINCE__ - if ( !CreateDirectory(dirname, NULL) ) -#else - if ( wxMkDir(dir.fn_str()) != 0 ) -#endif -#endif // !MSW/MSW - { - wxLogSysError(_("Directory '%s' couldn't be created"), dirname); - - return false; - } - - return true; -#endif // Mac/!Mac -} - -bool wxRmdir(const wxString& dir, int WXUNUSED(flags)) -{ -#if defined(__VMS__) - return false; //to be changed since rmdir exists in VMS7.x -#elif defined(__OS2__) - return (::DosDeleteDir((PSZ)dir.c_str()) == 0); -#elif defined(__WXWINCE__) - return (RemoveDirectory(dir) != 0); -#elif defined(__WXPALMOS__) - // TODO with VFSFileRename() - return false; -#else - return (wxRmDir(OS_FILENAME(dir)) == 0); -#endif -} - -// does the path exists? (may have or not '/' or '\\' at the end) -bool wxDirExists(const wxChar *pszPathName) -{ - wxString strPath(pszPathName); - -#if defined(__WINDOWS__) || defined(__OS2__) - // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists, - // so remove all trailing backslashes from the path - but don't do this for - // the paths "d:\" (which are different from "d:") nor for just "\" - while ( wxEndsWithPathSeparator(strPath) ) - { - size_t len = strPath.length(); - if ( len == 1 || (len == 3 && strPath[len - 2] == _T(':')) ) - break; - - strPath.Truncate(len - 1); - } -#endif // __WINDOWS__ - -#ifdef __OS2__ - // OS/2 can't handle "d:", it wants either "d:\" or "d:." - if (strPath.length() == 2 && strPath[1u] == _T(':')) - strPath << _T('.'); -#endif - -#if defined(__WXPALMOS__) - return false; -#elif defined(__WIN32__) && !defined(__WXMICROWIN__) - // stat() can't cope with network paths - DWORD ret = ::GetFileAttributes(strPath); - - return (ret != (DWORD)-1) && (ret & FILE_ATTRIBUTE_DIRECTORY); -#elif defined(__OS2__) - FILESTATUS3 Info = {{0}}; - APIRET rc = ::DosQueryPathInfo((PSZ)(WXSTRINGCAST strPath), FIL_STANDARD, - (void*) &Info, sizeof(FILESTATUS3)); - - return ((rc == NO_ERROR) && (Info.attrFile & FILE_DIRECTORY)) || - (rc == ERROR_SHARING_VIOLATION); - // If we got a sharing violation, there must be something with this name. -#else // !__WIN32__ - - wxStructStat st; -#ifndef __VISAGECPP__ - return wxStat(strPath.c_str(), &st) == 0 && ((st.st_mode & S_IFMT) == S_IFDIR); -#else - // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only - return wxStat(pszPathName, &st) == 0 && (st.st_mode == S_IFDIR); -#endif - -#endif // __WIN32__/!__WIN32__ -} - -// Get a temporary filename, opening and closing the file. -wxChar *wxGetTempFileName(const wxString& prefix, wxChar *buf) -{ - wxString filename; - if ( !wxGetTempFileName(prefix, filename) ) - return NULL; - - if ( buf ) - wxStrcpy(buf, filename); - else - buf = MYcopystring(filename); - - return buf; -} - -bool wxGetTempFileName(const wxString& prefix, wxString& buf) -{ -#if wxUSE_FILE - buf = wxFileName::CreateTempFileName(prefix); - - return !buf.empty(); -#else // !wxUSE_FILE - wxUnusedVar(prefix); - wxUnusedVar(buf); - - return false; -#endif // wxUSE_FILE/!wxUSE_FILE -} - -// Get first file name matching given wild card. - -static wxDir *gs_dir = NULL; -static wxString gs_dirPath; - -wxString wxFindFirstFile(const wxChar *spec, int flags) -{ - wxSplitPath(spec, &gs_dirPath, NULL, NULL); - if ( gs_dirPath.empty() ) - gs_dirPath = wxT("."); - if ( !wxEndsWithPathSeparator(gs_dirPath ) ) - gs_dirPath << wxFILE_SEP_PATH; - - if (gs_dir) - delete gs_dir; - gs_dir = new wxDir(gs_dirPath); - - if ( !gs_dir->IsOpened() ) - { - wxLogSysError(_("Can not enumerate files '%s'"), spec); - return wxEmptyString; - } - - int dirFlags; - switch (flags) - { - case wxDIR: dirFlags = wxDIR_DIRS; break; - case wxFILE: dirFlags = wxDIR_FILES; break; - default: dirFlags = wxDIR_DIRS | wxDIR_FILES; break; - } - - wxString result; - gs_dir->GetFirst(&result, wxFileNameFromPath(wxString(spec)), dirFlags); - if ( result.empty() ) - { - wxDELETE(gs_dir); - return result; - } - - return gs_dirPath + result; -} - -wxString wxFindNextFile() -{ - wxASSERT_MSG( gs_dir, wxT("You must call wxFindFirstFile before!") ); - - wxString result; - gs_dir->GetNext(&result); - - if ( result.empty() ) - { - wxDELETE(gs_dir); - return result; - } - - return gs_dirPath + result; -} - - -// Get current working directory. -// If buf is NULL, allocates space using new, else copies into buf. -// wxGetWorkingDirectory() is obsolete, use wxGetCwd() -// wxDoGetCwd() is their common core to be moved -// to wxGetCwd() once wxGetWorkingDirectory() will be removed. -// Do not expose wxDoGetCwd in headers! - -wxChar *wxDoGetCwd(wxChar *buf, int sz) -{ -#if defined(__WXPALMOS__) - // TODO - if(buf && sz>0) buf[0] = _T('\0'); - return buf; -#elif defined(__WXWINCE__) - // TODO - if(buf && sz>0) buf[0] = _T('\0'); - return buf; -#else - if ( !buf ) - { - buf = new wxChar[sz + 1]; - } - - bool ok wxDUMMY_INITIALIZE(false); - - // for the compilers which have Unicode version of _getcwd(), call it - // directly, for the others call the ANSI version and do the translation -#if !wxUSE_UNICODE - #define cbuf buf -#else // wxUSE_UNICODE - bool needsANSI = true; - - #if !defined(HAVE_WGETCWD) || wxUSE_UNICODE_MSLU - char cbuf[_MAXPATHLEN]; - #endif - - #ifdef HAVE_WGETCWD - #if wxUSE_UNICODE_MSLU - if ( wxGetOsVersion() != wxOS_WINDOWS_9X ) - #else - char *cbuf = NULL; // never really used because needsANSI will always be false - #endif - { - ok = _wgetcwd(buf, sz) != NULL; - needsANSI = false; - } - #endif - - if ( needsANSI ) -#endif // wxUSE_UNICODE - { - #if defined(_MSC_VER) || defined(__MINGW32__) - ok = _getcwd(cbuf, sz) != NULL; - #elif defined(__WXMAC__) && !defined(__DARWIN__) - char lbuf[1024] ; - if ( getcwd( lbuf , sizeof( lbuf ) ) ) - { - wxString res( lbuf , *wxConvCurrent ) ; - wxStrcpy( buf , res ) ; - ok = true; - } - else - ok = false ; - #elif defined(__OS2__) - APIRET rc; - ULONG ulDriveNum = 0; - ULONG ulDriveMap = 0; - rc = ::DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap); - ok = rc == 0; - if (ok) - { - sz -= 3; - rc = ::DosQueryCurrentDir( 0 // current drive - ,(PBYTE)cbuf + 3 - ,(PULONG)&sz - ); - cbuf[0] = char('A' + (ulDriveNum - 1)); - cbuf[1] = ':'; - cbuf[2] = '\\'; - ok = rc == 0; - } - #else // !Win32/VC++ !Mac !OS2 - ok = getcwd(cbuf, sz) != NULL; - #endif // platform - - #if wxUSE_UNICODE && !(defined(__WXMAC__) && !defined(__DARWIN__)) - // finally convert the result to Unicode if needed - wxConvFile.MB2WC(buf, cbuf, sz); - #endif // wxUSE_UNICODE - } - - if ( !ok ) - { - wxLogSysError(_("Failed to get the working directory")); - - // VZ: the old code used to return "." on error which didn't make any - // sense at all to me - empty string is a better error indicator - // (NULL might be even better but I'm afraid this could lead to - // problems with the old code assuming the return is never NULL) - buf[0] = _T('\0'); - } - else // ok, but we might need to massage the path into the right format - { -#ifdef __DJGPP__ - // VS: DJGPP is a strange mix of DOS and UNIX API and returns paths - // with / deliminers. We don't like that. - for (wxChar *ch = buf; *ch; ch++) - { - if (*ch == wxT('/')) - *ch = wxT('\\'); - } -#endif // __DJGPP__ - -// MBN: we hope that in the case the user is compiling a GTK+/Motif app, -// he needs Unix as opposed to Win32 pathnames -#if defined( __CYGWIN__ ) && defined( __WINDOWS__ ) - // another example of DOS/Unix mix (Cygwin) - wxString pathUnix = buf; -#if wxUSE_UNICODE - char bufA[_MAXPATHLEN]; - cygwin_conv_to_full_win32_path(pathUnix.mb_str(wxConvFile), bufA); - wxConvFile.MB2WC(buf, bufA, sz); -#else - cygwin_conv_to_full_win32_path(pathUnix, buf); -#endif // wxUSE_UNICODE -#endif // __CYGWIN__ - } - - return buf; - -#if !wxUSE_UNICODE - #undef cbuf -#endif - -#endif - // __WXWINCE__ -} - -#if WXWIN_COMPATIBILITY_2_6 -wxChar *wxGetWorkingDirectory(wxChar *buf, int sz) -{ - return wxDoGetCwd(buf,sz); -} -#endif // WXWIN_COMPATIBILITY_2_6 - -wxString wxGetCwd() -{ - wxString str; - wxDoGetCwd(wxStringBuffer(str, _MAXPATHLEN), _MAXPATHLEN); - return str; -} - -bool wxSetWorkingDirectory(const wxString& d) -{ -#if defined(__OS2__) - if (d[1] == ':') - { - ::DosSetDefaultDisk(1 + wxToupper(d[0]) - _T('A')); - // do not call DosSetCurrentDir when just changing drive, - // since it requires e.g. "d:." instead of "d:"! - if (d.length() == 2) - return true; - } - return (::DosSetCurrentDir((PSZ)d.c_str()) == 0); -#elif defined(__UNIX__) || defined(__WXMAC__) || defined(__DOS__) - return (chdir(wxFNSTRINGCAST d.fn_str()) == 0); -#elif defined(__WINDOWS__) - -#ifdef __WIN32__ -#ifdef __WXWINCE__ - // No equivalent in WinCE - wxUnusedVar(d); - return false; -#else - return (bool)(SetCurrentDirectory(d) != 0); -#endif -#else - // Must change drive, too. - bool isDriveSpec = ((strlen(d) > 1) && (d[1] == ':')); - if (isDriveSpec) - { - wxChar firstChar = d[0]; - - // To upper case - if (firstChar > 90) - firstChar = firstChar - 32; - - // To a drive number - unsigned int driveNo = firstChar - 64; - if (driveNo > 0) - { - unsigned int noDrives; - _dos_setdrive(driveNo, &noDrives); - } - } - bool success = (chdir(WXSTRINGCAST d) == 0); - - return success; -#endif - -#endif -} - -// Get the OS directory if appropriate (such as the Windows directory). -// On non-Windows platform, probably just return the empty string. -wxString wxGetOSDirectory() -{ -#ifdef __WXWINCE__ - return wxString(wxT("\\Windows")); -#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) - wxChar buf[256]; - GetWindowsDirectory(buf, 256); - return wxString(buf); -#elif defined(__WXMAC__) - return wxMacFindFolder(kOnSystemDisk, 'macs', false); -#else - return wxEmptyString; -#endif -} - -bool wxEndsWithPathSeparator(const wxChar *pszFileName) -{ - size_t len = wxStrlen(pszFileName); - - return len && wxIsPathSeparator(pszFileName[len - 1]); -} - -// find a file in a list of directories, returns false if not found -bool wxFindFileInPath(wxString *pStr, const wxChar *pszPath, const wxChar *pszFile) -{ - // we assume that it's not empty - wxCHECK_MSG( !wxIsEmpty(pszFile), false, - _T("empty file name in wxFindFileInPath")); - - // skip path separator in the beginning of the file name if present - if ( wxIsPathSeparator(*pszFile) ) - pszFile++; - - // copy the path (strtok will modify it) - wxChar *szPath = new wxChar[wxStrlen(pszPath) + 1]; - wxStrcpy(szPath, pszPath); - - wxString strFile; - wxChar *pc, *save_ptr; - for ( pc = wxStrtok(szPath, wxPATH_SEP, &save_ptr); - pc != NULL; - pc = wxStrtok((wxChar *) NULL, wxPATH_SEP, &save_ptr) ) - { - // search for the file in this directory - strFile = pc; - if ( !wxEndsWithPathSeparator(pc) ) - strFile += wxFILE_SEP_PATH; - strFile += pszFile; - - if ( wxFileExists(strFile) ) { - *pStr = strFile; - break; - } - } - - // suppress warning about unused variable save_ptr when wxStrtok() is a - // macro which throws away its third argument - save_ptr = pc; - - delete [] szPath; - - return pc != NULL; // if true => we breaked from the loop -} - -void WXDLLEXPORT wxSplitPath(const wxChar *pszFileName, - wxString *pstrPath, - wxString *pstrName, - wxString *pstrExt) -{ - // it can be empty, but it shouldn't be NULL - wxCHECK_RET( pszFileName, wxT("NULL file name in wxSplitPath") ); - - wxFileName::SplitPath(pszFileName, pstrPath, pstrName, pstrExt); -} - -#if wxUSE_DATETIME - -time_t WXDLLEXPORT wxFileModificationTime(const wxString& filename) -{ - wxDateTime mtime; - if ( !wxFileName(filename).GetTimes(NULL, &mtime, NULL) ) - return (time_t)-1; - - return mtime.GetTicks(); -} - -#endif // wxUSE_DATETIME - - -// Parses the filterStr, returning the number of filters. -// Returns 0 if none or if there's a problem. -// filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpeg" - -int WXDLLEXPORT wxParseCommonDialogsFilter(const wxString& filterStr, - wxArrayString& descriptions, - wxArrayString& filters) -{ - descriptions.Clear(); - filters.Clear(); - - wxString str(filterStr); - - wxString description, filter; - int pos = 0; - while( pos != wxNOT_FOUND ) - { - pos = str.Find(wxT('|')); - if ( pos == wxNOT_FOUND ) - { - // if there are no '|'s at all in the string just take the entire - // string as filter and make description empty for later autocompletion - if ( filters.IsEmpty() ) - { - descriptions.Add(wxEmptyString); - filters.Add(filterStr); - } - else - { - wxFAIL_MSG( _T("missing '|' in the wildcard string!") ); - } - - break; - } - - description = str.Left(pos); - str = str.Mid(pos + 1); - pos = str.Find(wxT('|')); - if ( pos == wxNOT_FOUND ) - { - filter = str; - } - else - { - filter = str.Left(pos); - str = str.Mid(pos + 1); - } - - descriptions.Add(description); - filters.Add(filter); - } - -#if defined(__WXMOTIF__) - // split it so there is one wildcard per entry - for( size_t i = 0 ; i < descriptions.GetCount() ; i++ ) - { - pos = filters[i].Find(wxT(';')); - if (pos != wxNOT_FOUND) - { - // first split only filters - descriptions.Insert(descriptions[i],i+1); - filters.Insert(filters[i].Mid(pos+1),i+1); - filters[i]=filters[i].Left(pos); - - // autoreplace new filter in description with pattern: - // C/C++ Files(*.cpp;*.c;*.h)|*.cpp;*.c;*.h - // cause split into: - // C/C++ Files(*.cpp)|*.cpp - // C/C++ Files(*.c;*.h)|*.c;*.h - // and next iteration cause another split into: - // C/C++ Files(*.cpp)|*.cpp - // C/C++ Files(*.c)|*.c - // C/C++ Files(*.h)|*.h - for ( size_t k=i;kbefore.Find(_T(')'),true)) - { - before = before.Left(pos+1); - before << filters[k]; - pos = after.Find(_T(')')); - int pos1 = after.Find(_T('(')); - if (pos != wxNOT_FOUND && (pos -* -* The match procedure is public domain code (from ircII's reg.c) -* but modified to suit our tastes (RN: No "%" syntax I guess) -*/ - -bool wxMatchWild( const wxString& pat, const wxString& text, bool dot_special ) -{ - if (text.empty()) - { - /* Match if both are empty. */ - return pat.empty(); - } - - const wxChar *m = pat.c_str(), - *n = text.c_str(), - *ma = NULL, - *na = NULL; - int just = 0, - acount = 0, - count = 0; - - if (dot_special && (*n == wxT('.'))) - { - /* Never match so that hidden Unix files - * are never found. */ - return false; - } - - for (;;) - { - if (*m == wxT('*')) - { - ma = ++m; - na = n; - just = 1; - acount = count; - } - else if (*m == wxT('?')) - { - m++; - if (!*n++) - return false; - } - else - { - if (*m == wxT('\\')) - { - m++; - /* Quoting "nothing" is a bad thing */ - if (!*m) - return false; - } - if (!*m) - { - /* - * If we are out of both strings or we just - * saw a wildcard, then we can say we have a - * match - */ - if (!*n) - return true; - if (just) - return true; - just = 0; - goto not_matched; - } - /* - * We could check for *n == NULL at this point, but - * since it's more common to have a character there, - * check to see if they match first (m and n) and - * then if they don't match, THEN we can check for - * the NULL of n - */ - just = 0; - if (*m == *n) - { - m++; - count++; - n++; - } - else - { - - not_matched: - - /* - * If there are no more characters in the - * string, but we still need to find another - * character (*m != NULL), then it will be - * impossible to match it - */ - if (!*n) - return false; - - if (ma) - { - m = ma; - n = ++na; - count = acount; - } - else - return false; - } - } - } -} - -#ifdef __VISUALC__ - #pragma warning(default:4706) // assignment within conditional expression -#endif // VC++ +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/filefn.cpp +// Purpose: File- and directory-related functions +// Author: Julian Smart +// Modified by: +// Created: 29/01/98 +// RCS-ID: $Id: filefn.cpp 66990 2011-02-22 12:10:44Z JS $ +// Copyright: (c) 1998 Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/filefn.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" +#endif + +#include "wx/file.h" +#include "wx/filename.h" +#include "wx/dir.h" + +#include "wx/tokenzr.h" + +// there are just too many of those... +#ifdef __VISUALC__ + #pragma warning(disable:4706) // assignment within conditional expression +#endif // VC++ + +#include +#include +#include +#include +#if !wxONLY_WATCOM_EARLIER_THAN(1,4) + #if !(defined(_MSC_VER) && (_MSC_VER > 800)) + #include + #endif +#endif + +#if defined(__WXMAC__) + #include "wx/mac/private.h" // includes mac headers +#endif + +#ifdef __WINDOWS__ + #include "wx/msw/private.h" + #include "wx/msw/mslu.h" + + // sys/cygwin.h is needed for cygwin_conv_to_full_win32_path() + // + // note that it must be included after + #ifdef __GNUWIN32__ + #ifdef __CYGWIN__ + #include + #endif + #endif // __GNUWIN32__ + + // io.h is needed for _get_osfhandle() + // Already included by filefn.h for many Windows compilers + #if defined __MWERKS__ || defined __CYGWIN__ + #include + #endif +#endif // __WINDOWS__ + +#if defined(__VMS__) + #include +#endif + +// TODO: Borland probably has _wgetcwd as well? +#ifdef _MSC_VER + #define HAVE_WGETCWD +#endif + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +#ifndef _MAXPATHLEN + #define _MAXPATHLEN 1024 +#endif + +#ifdef __WXMAC__ +# include "MoreFilesX.h" +#endif + +// ---------------------------------------------------------------------------- +// private globals +// ---------------------------------------------------------------------------- + +// MT-FIXME: get rid of this horror and all code using it +static wxChar wxFileFunctionsBuffer[4*_MAXPATHLEN]; + +#if defined(__VISAGECPP__) && __IBMCPP__ >= 400 +// +// VisualAge C++ V4.0 cannot have any external linkage const decs +// in headers included by more than one primary source +// +const int wxInvalidOffset = -1; +#endif + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +// translate the filenames before passing them to OS functions +#define OS_FILENAME(s) (s.fn_str()) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wrappers around standard POSIX functions +// ---------------------------------------------------------------------------- + +#ifdef wxNEED_WX_UNISTD_H + +WXDLLEXPORT int wxStat( const wxChar *file_name, wxStructStat *buf ) +{ + return stat( wxConvFile.cWX2MB( file_name ), buf ); +} + +WXDLLEXPORT int wxLstat( const wxChar *file_name, wxStructStat *buf ) +{ + return lstat( wxConvFile.cWX2MB( file_name ), buf ); +} + +WXDLLEXPORT int wxAccess( const wxChar *pathname, int mode ) +{ + return access( wxConvFile.cWX2MB( pathname ), mode ); +} + +WXDLLEXPORT int wxOpen( const wxChar *pathname, int flags, mode_t mode ) +{ + return open( wxConvFile.cWX2MB( pathname ), flags, mode ); +} + +#endif // wxNEED_WX_UNISTD_H + +#if wxUSE_UNICODE && defined __BORLANDC__ \ + && __BORLANDC__ >= 0x550 && __BORLANDC__ <= 0x551 + +// BCC 5.5 and 5.5.1 have a bug in _wopen where files are created read only +// regardless of the mode parameter. This hack works around the problem by +// setting the mode with _wchmod. +// +int wxOpen(const wchar_t *pathname, int flags, mode_t mode) +{ + int moreflags = 0; + + // we only want to fix the mode when the file is actually created, so + // when creating first try doing it O_EXCL so we can tell if the file + // was already there. + if ((flags & O_CREAT) && !(flags & O_EXCL) && (mode & wxS_IWUSR) != 0) + moreflags = O_EXCL; + + int fd = _wopen(pathname, flags | moreflags, mode); + + // the file was actually created and needs fixing + if (fd != -1 && (flags & O_CREAT) != 0 && (mode & wxS_IWUSR) != 0) + { + close(fd); + _wchmod(pathname, mode); + fd = _wopen(pathname, flags & ~(O_EXCL | O_CREAT)); + } + // the open failed, but it may have been because the added O_EXCL stopped + // the opening of an existing file, so try again without. + else if (fd == -1 && moreflags != 0) + { + fd = _wopen(pathname, flags & ~O_CREAT); + } + + return fd; +} + +#endif + +// ---------------------------------------------------------------------------- +// wxPathList +// ---------------------------------------------------------------------------- + +bool wxPathList::Add(const wxString& path) +{ + // add a path separator to force wxFileName to interpret it always as a directory + // (i.e. if we are called with '/home/user' we want to consider it a folder and + // not, as wxFileName would consider, a filename). + wxFileName fn(path + wxFileName::GetPathSeparator()); + + // add only normalized relative/absolute paths + // NB: we won't do wxPATH_NORM_DOTS in order to avoid problems when trying to + // normalize paths which starts with ".." (which can be normalized only if + // we use also wxPATH_NORM_ABSOLUTE - which we don't want to use). + if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS)) + return false; + + wxString toadd = fn.GetPath(); + if (Index(toadd) == wxNOT_FOUND) + wxArrayString::Add(toadd); // do not add duplicates + + return true; +} + +void wxPathList::Add(const wxArrayString &arr) +{ + for (size_t j=0; j < arr.GetCount(); j++) + Add(arr[j]); +} + +// Add paths e.g. from the PATH environment variable +void wxPathList::AddEnvList (const wxString& WXUNUSED_IN_WINCE(envVariable)) +{ + // No environment variables on WinCE +#ifndef __WXWINCE__ + + // The space has been removed from the tokenizers, otherwise a + // path such as "C:\Program Files" would be split into 2 paths: + // "C:\Program" and "Files"; this is true for both Windows and Unix. + + static const wxChar PATH_TOKS[] = +#if defined(__WINDOWS__) || defined(__OS2__) + wxT(";"); // Don't separate with colon in DOS (used for drive) +#else + wxT(":;"); +#endif + + wxString val; + if ( wxGetEnv(envVariable, &val) ) + { + // split into an array of string the value of the env var + wxArrayString arr = wxStringTokenize(val, PATH_TOKS); + WX_APPEND_ARRAY(*this, arr); + } +#endif // !__WXWINCE__ +} + +// Given a full filename (with path), ensure that that file can +// be accessed again USING FILENAME ONLY by adding the path +// to the list if not already there. +bool wxPathList::EnsureFileAccessible (const wxString& path) +{ + return Add(wxPathOnly(path)); +} + +#if WXWIN_COMPATIBILITY_2_6 +bool wxPathList::Member (const wxString& path) const +{ + return Index(path) != wxNOT_FOUND; +} +#endif + +wxString wxPathList::FindValidPath (const wxString& file) const +{ + // normalize the given string as it could be a path + a filename + // and not only a filename + wxFileName fn(file); + wxString strend; + + // NB: normalize without making absolute otherwise calling this function with + // e.g. "b/c.txt" would result in removing the directory 'b' and the for loop + // below would only add to the paths of this list the 'c.txt' part when doing + // the existence checks... + // NB: we don't use wxPATH_NORM_DOTS here, too (see wxPathList::Add for more info) + if (!fn.Normalize(wxPATH_NORM_TILDE|wxPATH_NORM_LONG|wxPATH_NORM_ENV_VARS)) + return wxEmptyString; + + wxASSERT_MSG(!fn.IsDir(), wxT("Cannot search for directories; only for files")); + if (fn.IsAbsolute()) + strend = fn.GetFullName(); // search for the file name and ignore the path part + else + strend = fn.GetFullPath(); + + for (size_t i=0; i 0) + { + if (buffer[i] == wxT('.')) + { + buffer[i] = 0; + break; + } + i --; + } +} + +void wxStripExtension(wxString& buffer) +{ + //RN: Be careful about the handling the case where + //buffer.length() == 0 + for(size_t i = buffer.length() - 1; i != wxString::npos; --i) + { + if (buffer.GetChar(i) == wxT('.')) + { + buffer = buffer.Left(i); + break; + } + } +} + +// Destructive removal of /./ and /../ stuff +wxChar *wxRealPath (wxChar *path) +{ +#ifdef __WXMSW__ + static const wxChar SEP = wxT('\\'); + wxUnix2DosFilename(path); +#else + static const wxChar SEP = wxT('/'); +#endif + if (path[0] && path[1]) { + /* MATTHEW: special case "/./x" */ + wxChar *p; + if (path[2] == SEP && path[1] == wxT('.')) + p = &path[0]; + else + p = &path[2]; + for (; *p; p++) + { + if (*p == SEP) + { + if (p[1] == wxT('.') && p[2] == wxT('.') && (p[3] == SEP || p[3] == wxT('\0'))) + { + wxChar *q; + for (q = p - 1; q >= path && *q != SEP; q--) + { + // Empty + } + + if (q[0] == SEP && (q[1] != wxT('.') || q[2] != wxT('.') || q[3] != SEP) + && (q - 1 <= path || q[-1] != SEP)) + { + wxStrcpy (q, p + 3); + if (path[0] == wxT('\0')) + { + path[0] = SEP; + path[1] = wxT('\0'); + } +#if defined(__WXMSW__) || defined(__OS2__) + /* Check that path[2] is NULL! */ + else if (path[1] == wxT(':') && !path[2]) + { + path[2] = SEP; + path[3] = wxT('\0'); + } +#endif + p = q - 1; + } + } + else if (p[1] == wxT('.') && (p[2] == SEP || p[2] == wxT('\0'))) + wxStrcpy (p, p + 2); + } + } + } + return path; +} + +wxString wxRealPath(const wxString& path) +{ + wxChar *buf1=MYcopystring(path); + wxChar *buf2=wxRealPath(buf1); + wxString buf(buf2); + delete [] buf1; + return buf; +} + + +// Must be destroyed +wxChar *wxCopyAbsolutePath(const wxString& filename) +{ + if (filename.empty()) + return (wxChar *) NULL; + + if (! wxIsAbsolutePath(wxExpandPath(wxFileFunctionsBuffer, filename))) + { + wxString buf = ::wxGetCwd(); + wxChar ch = buf.Last(); +#ifdef __WXMSW__ + if (ch != wxT('\\') && ch != wxT('/')) + buf << wxT("\\"); +#else + if (ch != wxT('/')) + buf << wxT("/"); +#endif + buf << wxFileFunctionsBuffer; + buf = wxRealPath( buf ); + return MYcopystring( buf ); + } + return MYcopystring( wxFileFunctionsBuffer ); +} + +/*- + Handles: + ~/ => home dir + ~user/ => user's home dir + If the environment variable a = "foo" and b = "bar" then: + Unix: + $a => foo + $a$b => foobar + $a.c => foo.c + xxx$a => xxxfoo + ${a}! => foo! + $(b)! => bar! + \$a => \$a + MSDOS: + $a ==> $a + $(a) ==> foo + $(a)$b ==> foo$b + $(a)$(b)==> foobar + test.$$ ==> test.$$ + */ + +/* input name in name, pathname output to buf. */ + +wxChar *wxExpandPath(wxChar *buf, const wxChar *name) +{ + register wxChar *d, *s, *nm; + wxChar lnm[_MAXPATHLEN]; + int q; + + // Some compilers don't like this line. +// const wxChar trimchars[] = wxT("\n \t"); + + wxChar trimchars[4]; + trimchars[0] = wxT('\n'); + trimchars[1] = wxT(' '); + trimchars[2] = wxT('\t'); + trimchars[3] = 0; + +#ifdef __WXMSW__ + const wxChar SEP = wxT('\\'); +#else + const wxChar SEP = wxT('/'); +#endif + buf[0] = wxT('\0'); + if (name == NULL || *name == wxT('\0')) + return buf; + nm = MYcopystring(name); // Make a scratch copy + wxChar *nm_tmp = nm; + + /* Skip leading whitespace and cr */ + while (wxStrchr((wxChar *)trimchars, *nm) != NULL) + nm++; + /* And strip off trailing whitespace and cr */ + s = nm + (q = wxStrlen(nm)) - 1; + while (q-- && wxStrchr((wxChar *)trimchars, *s) != NULL) + *s = wxT('\0'); + + s = nm; + d = lnm; +#ifdef __WXMSW__ + q = FALSE; +#else + q = nm[0] == wxT('\\') && nm[1] == wxT('~'); +#endif + + /* Expand inline environment variables */ +#ifdef __VISAGECPP__ + while (*d) + { + *d++ = *s; + if(*s == wxT('\\')) + { + *(d - 1) = *++s; + if (*d) + { + s++; + continue; + } + else + break; + } + else +#else + while ((*d++ = *s) != 0) { +# ifndef __WXMSW__ + if (*s == wxT('\\')) { + if ((*(d - 1) = *++s)!=0) { + s++; + continue; + } else + break; + } else +# endif +#endif + // No env variables on WinCE +#ifndef __WXWINCE__ +#ifdef __WXMSW__ + if (*s++ == wxT('$') && (*s == wxT('{') || *s == wxT(')'))) +#else + if (*s++ == wxT('$')) +#endif + { + register wxChar *start = d; + register int braces = (*s == wxT('{') || *s == wxT('(')); + register wxChar *value; + while ((*d++ = *s) != 0) + if (braces ? (*s == wxT('}') || *s == wxT(')')) : !(wxIsalnum(*s) || *s == wxT('_')) ) + break; + else + s++; + *--d = 0; + value = wxGetenv(braces ? start + 1 : start); + if (value) { + for ((d = start - 1); (*d++ = *value++) != 0;) + { + // Empty + } + + d--; + if (braces && *s) + s++; + } + } +#endif + // __WXWINCE__ + } + + /* Expand ~ and ~user */ + nm = lnm; + if (nm[0] == wxT('~') && !q) + { + /* prefix ~ */ + if (nm[1] == SEP || nm[1] == 0) + { /* ~/filename */ + // FIXME: wxGetUserHome could return temporary storage in Unicode mode + if ((s = WXSTRINGCAST wxGetUserHome(wxEmptyString)) != NULL) { + if (*++nm) + nm++; + } + } else + { /* ~user/filename */ + register wxChar *nnm; + register wxChar *home; + for (s = nm; *s && *s != SEP; s++) + { + // Empty + } + int was_sep; /* MATTHEW: Was there a separator, or NULL? */ + was_sep = (*s == SEP); + nnm = *s ? s + 1 : s; + *s = 0; + // FIXME: wxGetUserHome could return temporary storage in Unicode mode + if ((home = WXSTRINGCAST wxGetUserHome(wxString(nm + 1))) == NULL) + { + if (was_sep) /* replace only if it was there: */ + *s = SEP; + s = NULL; + } + else + { + nm = nnm; + s = home; + } + } + } + + d = buf; + if (s && *s) { /* MATTHEW: s could be NULL if user '~' didn't exist */ + /* Copy home dir */ + while (wxT('\0') != (*d++ = *s++)) + /* loop */; + // Handle root home + if (d - 1 > buf && *(d - 2) != SEP) + *(d - 1) = SEP; + } + s = nm; + while ((*d++ = *s++) != 0) + { + // Empty + } + delete[] nm_tmp; // clean up alloc + /* Now clean up the buffer */ + return wxRealPath(buf); +} + +/* Contract Paths to be build upon an environment variable + component: + + example: "/usr/openwin/lib", OPENWINHOME --> ${OPENWINHOME}/lib + + The call wxExpandPath can convert these back! + */ +wxChar * +wxContractPath (const wxString& filename, + const wxString& WXUNUSED_IN_WINCE(envname), + const wxString& user) +{ + static wxChar dest[_MAXPATHLEN]; + + if (filename.empty()) + return (wxChar *) NULL; + + wxStrcpy (dest, WXSTRINGCAST filename); +#ifdef __WXMSW__ + wxUnix2DosFilename(dest); +#endif + + // Handle environment + const wxChar *val; +#ifndef __WXWINCE__ + wxChar *tcp; + if (!envname.empty() && (val = wxGetenv (WXSTRINGCAST envname)) != NULL && + (tcp = wxStrstr (dest, val)) != NULL) + { + wxStrcpy (wxFileFunctionsBuffer, tcp + wxStrlen (val)); + *tcp++ = wxT('$'); + *tcp++ = wxT('{'); + wxStrcpy (tcp, WXSTRINGCAST envname); + wxStrcat (tcp, wxT("}")); + wxStrcat (tcp, wxFileFunctionsBuffer); + } +#endif + + // Handle User's home (ignore root homes!) + val = wxGetUserHome (user); + if (!val) + return dest; + + const size_t len = wxStrlen(val); + if (len <= 2) + return dest; + + if (wxStrncmp(dest, val, len) == 0) + { + wxStrcpy(wxFileFunctionsBuffer, wxT("~")); + if (!user.empty()) + wxStrcat(wxFileFunctionsBuffer, (const wxChar*) user); + wxStrcat(wxFileFunctionsBuffer, dest + len); + wxStrcpy (dest, wxFileFunctionsBuffer); + } + + return dest; +} + +// Return just the filename, not the path (basename) +wxChar *wxFileNameFromPath (wxChar *path) +{ + wxString p = path; + wxString n = wxFileNameFromPath(p); + + return path + p.length() - n.length(); +} + +wxString wxFileNameFromPath (const wxString& path) +{ + wxString name, ext; + wxFileName::SplitPath(path, NULL, &name, &ext); + + wxString fullname = name; + if ( !ext.empty() ) + { + fullname << wxFILE_SEP_EXT << ext; + } + + return fullname; +} + +// Return just the directory, or NULL if no directory +wxChar * +wxPathOnly (wxChar *path) +{ + if (path && *path) + { + static wxChar buf[_MAXPATHLEN]; + + // Local copy + wxStrcpy (buf, path); + + int l = wxStrlen(path); + int i = l - 1; + + // Search backward for a backward or forward slash + while (i > -1) + { +#if defined(__WXMAC__) && !defined(__DARWIN__) + // Classic or Carbon CodeWarrior like + // Carbon with Apple DevTools is Unix like + if (path[i] == wxT(':') ) + { + buf[i] = 0; + return buf; + } +#else + // Unix like or Windows + if (path[i] == wxT('/') || path[i] == wxT('\\')) + { + buf[i] = 0; + return buf; + } +#endif +#ifdef __VMS__ + if (path[i] == wxT(']')) + { + buf[i+1] = 0; + return buf; + } +#endif + i --; + } + +#if defined(__WXMSW__) || defined(__OS2__) + // Try Drive specifier + if (wxIsalpha (buf[0]) && buf[1] == wxT(':')) + { + // A:junk --> A:. (since A:.\junk Not A:\junk) + buf[2] = wxT('.'); + buf[3] = wxT('\0'); + return buf; + } +#endif + } + return (wxChar *) NULL; +} + +// Return just the directory, or NULL if no directory +wxString wxPathOnly (const wxString& path) +{ + if (!path.empty()) + { + wxChar buf[_MAXPATHLEN]; + + // Local copy + wxStrcpy (buf, WXSTRINGCAST path); + + int l = path.length(); + int i = l - 1; + + // Search backward for a backward or forward slash + while (i > -1) + { +#if defined(__WXMAC__) && !defined(__DARWIN__) + // Classic or Carbon CodeWarrior like + // Carbon with Apple DevTools is Unix like + if (path[i] == wxT(':') ) + { + buf[i] = 0; + return wxString(buf); + } +#else + // Unix like or Windows + if (path[i] == wxT('/') || path[i] == wxT('\\')) + { + // Don't return an empty string + if (i == 0) + i ++; + buf[i] = 0; + return wxString(buf); + } +#endif +#ifdef __VMS__ + if (path[i] == wxT(']')) + { + buf[i+1] = 0; + return wxString(buf); + } +#endif + i --; + } + +#if defined(__WXMSW__) || defined(__OS2__) + // Try Drive specifier + if (wxIsalpha (buf[0]) && buf[1] == wxT(':')) + { + // A:junk --> A:. (since A:.\junk Not A:\junk) + buf[2] = wxT('.'); + buf[3] = wxT('\0'); + return wxString(buf); + } +#endif + } + return wxEmptyString; +} + +// Utility for converting delimiters in DOS filenames to UNIX style +// and back again - or we get nasty problems with delimiters. +// Also, convert to lower case, since case is significant in UNIX. + +#if defined(__WXMAC__) + +#if TARGET_API_MAC_OSX +#define kDefaultPathStyle kCFURLPOSIXPathStyle +#else +#define kDefaultPathStyle kCFURLHFSPathStyle +#endif + +wxString wxMacFSRefToPath( const FSRef *fsRef , CFStringRef additionalPathComponent ) +{ + CFURLRef fullURLRef; + fullURLRef = CFURLCreateFromFSRef(NULL, fsRef); + if ( additionalPathComponent ) + { + CFURLRef parentURLRef = fullURLRef ; + fullURLRef = CFURLCreateCopyAppendingPathComponent(NULL, parentURLRef, + additionalPathComponent,false); + CFRelease( parentURLRef ) ; + } + CFStringRef cfString = CFURLCopyFileSystemPath(fullURLRef, kDefaultPathStyle); + CFRelease( fullURLRef ) ; + CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfString); + CFRelease( cfString ); + CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); + return wxMacCFStringHolder(cfMutableString).AsString(); +} + +OSStatus wxMacPathToFSRef( const wxString&path , FSRef *fsRef ) +{ + OSStatus err = noErr ; + CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, wxMacCFStringHolder(path)); + CFStringNormalize(cfMutableString,kCFStringNormalizationFormD); + CFURLRef url = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, cfMutableString , kDefaultPathStyle, false); + CFRelease( cfMutableString ); + if ( NULL != url ) + { + if ( CFURLGetFSRef(url, fsRef) == false ) + err = fnfErr ; + CFRelease( url ) ; + } + else + { + err = fnfErr ; + } + return err ; +} + +wxString wxMacHFSUniStrToString( ConstHFSUniStr255Param uniname ) +{ + CFStringRef cfname = CFStringCreateWithCharacters( kCFAllocatorDefault, + uniname->unicode, + uniname->length ); + CFMutableStringRef cfMutableString = CFStringCreateMutableCopy(NULL, 0, cfname); + CFRelease( cfname ); + CFStringNormalize(cfMutableString,kCFStringNormalizationFormC); + return wxMacCFStringHolder(cfMutableString).AsString() ; +} + +#ifndef __LP64__ + +wxString wxMacFSSpec2MacFilename( const FSSpec *spec ) +{ + FSRef fsRef ; + if ( FSpMakeFSRef( spec , &fsRef) == noErr ) + { + return wxMacFSRefToPath( &fsRef ) ; + } + return wxEmptyString ; +} + +void wxMacFilename2FSSpec( const wxString& path , FSSpec *spec ) +{ + OSStatus err = noErr ; + FSRef fsRef ; + wxMacPathToFSRef( path , &fsRef ) ; + err = FSRefMakeFSSpec( &fsRef , spec ) ; +} +#endif + +#endif // __WXMAC__ + +void +wxDos2UnixFilename (wxChar *s) +{ + if (s) + while (*s) + { + if (*s == _T('\\')) + *s = _T('/'); +#ifdef __WXMSW__ + else + *s = (wxChar)wxTolower (*s); // Case INDEPENDENT +#endif + s++; + } +} + +void +#if defined(__WXMSW__) || defined(__OS2__) +wxUnix2DosFilename (wxChar *s) +#else +wxUnix2DosFilename (wxChar *WXUNUSED(s) ) +#endif +{ +// Yes, I really mean this to happen under DOS only! JACS +#if defined(__WXMSW__) || defined(__OS2__) + if (s) + while (*s) + { + if (*s == wxT('/')) + *s = wxT('\\'); + s++; + } +#endif +} + +// Concatenate two files to form third +bool +wxConcatFiles (const wxString& file1, const wxString& file2, const wxString& file3) +{ +#if wxUSE_FILE + + wxFile in1(file1), in2(file2); + wxTempFile out(file3); + + if ( !in1.IsOpened() || !in2.IsOpened() || !out.IsOpened() ) + return false; + + ssize_t ofs; + unsigned char buf[1024]; + + for( int i=0; i<2; i++) + { + wxFile *in = i==0 ? &in1 : &in2; + do{ + if ( (ofs = in->Read(buf,WXSIZEOF(buf))) == wxInvalidOffset ) return false; + if ( ofs > 0 ) + if ( !out.Write(buf,ofs) ) + return false; + } while ( ofs == (ssize_t)WXSIZEOF(buf) ); + } + + return out.Commit(); + +#else + + wxUnusedVar(file1); + wxUnusedVar(file2); + wxUnusedVar(file3); + return false; + +#endif +} + +// Copy files +bool +wxCopyFile (const wxString& file1, const wxString& file2, bool overwrite) +{ +#if defined(__WIN32__) && !defined(__WXMICROWIN__) + // CopyFile() copies file attributes and modification time too, so use it + // instead of our code if available + // + // NB: 3rd parameter is bFailIfExists i.e. the inverse of overwrite + if ( !::CopyFile(file1, file2, !overwrite) ) + { + wxLogSysError(_("Failed to copy the file '%s' to '%s'"), + file1.c_str(), file2.c_str()); + + return false; + } +#elif defined(__OS2__) + if ( ::DosCopy((PSZ)file1.c_str(), (PSZ)file2.c_str(), overwrite ? DCPY_EXISTING : 0) != 0 ) + return false; +#elif defined(__PALMOS__) + // TODO with http://www.palmos.com/dev/support/docs/protein_books/Memory_Databases_Files/ + return false; +#elif wxUSE_FILE // !Win32 + + wxStructStat fbuf; + // get permissions of file1 + if ( wxStat( file1.c_str(), &fbuf) != 0 ) + { + // the file probably doesn't exist or we haven't the rights to read + // from it anyhow + wxLogSysError(_("Impossible to get permissions for file '%s'"), + file1.c_str()); + return false; + } + + // open file1 for reading + wxFile fileIn(file1, wxFile::read); + if ( !fileIn.IsOpened() ) + return false; + + // remove file2, if it exists. This is needed for creating + // file2 with the correct permissions in the next step + if ( wxFileExists(file2) && (!overwrite || !wxRemoveFile(file2))) + { + wxLogSysError(_("Impossible to overwrite the file '%s'"), + file2.c_str()); + return false; + } + + // reset the umask as we want to create the file with exactly the same + // permissions as the original one + wxCHANGE_UMASK(0); + + // create file2 with the same permissions than file1 and open it for + // writing + + wxFile fileOut; + if ( !fileOut.Create(file2, overwrite, fbuf.st_mode & 0777) ) + return false; + + // copy contents of file1 to file2 + char buf[4096]; + size_t count; + for ( ;; ) + { + count = fileIn.Read(buf, WXSIZEOF(buf)); + if ( fileIn.Error() ) + return false; + + // end of file? + if ( !count ) + break; + + if ( fileOut.Write(buf, count) < count ) + return false; + } + + // we can expect fileIn to be closed successfully, but we should ensure + // that fileOut was closed as some write errors (disk full) might not be + // detected before doing this + if ( !fileIn.Close() || !fileOut.Close() ) + return false; + +#if !defined(__VISAGECPP__) && !defined(__WXMAC__) || defined(__UNIX__) + // no chmod in VA. Should be some permission API for HPFS386 partitions + // however + if ( chmod(OS_FILENAME(file2), fbuf.st_mode) != 0 ) + { + wxLogSysError(_("Impossible to set permissions for the file '%s'"), + file2.c_str()); + return false; + } +#endif // OS/2 || Mac + +#else // !Win32 && ! wxUSE_FILE + + // impossible to simulate with wxWidgets API + wxUnusedVar(file1); + wxUnusedVar(file2); + wxUnusedVar(overwrite); + return false; + +#endif // __WXMSW__ && __WIN32__ + + return true; +} + +bool +wxRenameFile(const wxString& file1, const wxString& file2, bool overwrite) +{ + if ( !overwrite && wxFileExists(file2) ) + { + wxLogSysError + ( + _("Failed to rename the file '%s' to '%s' because the destination file already exists."), + file1.c_str(), file2.c_str() + ); + + return false; + } + +#if !defined(__WXWINCE__) && !defined(__WXPALMOS__) + // Normal system call + if ( wxRename (file1, file2) == 0 ) + return true; +#endif + + // Try to copy + if (wxCopyFile(file1, file2, overwrite)) { + wxRemoveFile(file1); + return true; + } + // Give up + return false; +} + +bool wxRemoveFile(const wxString& file) +{ +#if defined(__VISUALC__) \ + || defined(__BORLANDC__) \ + || defined(__WATCOMC__) \ + || defined(__DMC__) \ + || defined(__GNUWIN32__) \ + || (defined(__MWERKS__) && defined(__MSL__)) + int res = wxRemove(file); +#elif defined(__WXMAC__) + int res = unlink(wxFNCONV(file)); +#elif defined(__WXPALMOS__) + int res = 1; + // TODO with VFSFileDelete() +#else + int res = unlink(OS_FILENAME(file)); +#endif + + return res == 0; +} + +bool wxMkdir(const wxString& dir, int perm) +{ +#if defined(__WXPALMOS__) + return false; +#elif defined(__WXMAC__) && !defined(__UNIX__) + return (mkdir( wxFNCONV(dir) , 0 ) == 0); +#else // !Mac + const wxChar *dirname = dir.c_str(); + + // assume mkdir() has 2 args on non Windows-OS/2 platforms and on Windows too + // for the GNU compiler +#if (!(defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__))) || (defined(__GNUWIN32__) && !defined(__MINGW32__)) || defined(__WINE__) || defined(__WXMICROWIN__) + #if defined(MSVCRT) + wxUnusedVar(perm); + if ( mkdir(wxFNCONV(dirname)) != 0 ) + #else + if ( mkdir(wxFNCONV(dirname), perm) != 0 ) + #endif +#elif defined(__OS2__) + wxUnusedVar(perm); + if (::DosCreateDir((PSZ)dirname, NULL) != 0) // enhance for EAB's?? +#elif defined(__DOS__) + #if defined(__WATCOMC__) + (void)perm; + if ( wxMkDir(wxFNSTRINGCAST wxFNCONV(dirname)) != 0 ) + #elif defined(__DJGPP__) + if ( mkdir(wxFNCONV(dirname), perm) != 0 ) + #else + #error "Unsupported DOS compiler!" + #endif +#else // !MSW, !DOS and !OS/2 VAC++ + wxUnusedVar(perm); +#ifdef __WXWINCE__ + if ( !CreateDirectory(dirname, NULL) ) +#else + if ( wxMkDir(dir.fn_str()) != 0 ) +#endif +#endif // !MSW/MSW + { + wxLogSysError(_("Directory '%s' couldn't be created"), dirname); + + return false; + } + + return true; +#endif // Mac/!Mac +} + +bool wxRmdir(const wxString& dir, int WXUNUSED(flags)) +{ +#if defined(__VMS__) + return false; //to be changed since rmdir exists in VMS7.x +#elif defined(__OS2__) + return (::DosDeleteDir((PSZ)dir.c_str()) == 0); +#elif defined(__WXWINCE__) + return (RemoveDirectory(dir) != 0); +#elif defined(__WXPALMOS__) + // TODO with VFSFileRename() + return false; +#else + return (wxRmDir(OS_FILENAME(dir)) == 0); +#endif +} + +// does the path exists? (may have or not '/' or '\\' at the end) +bool wxDirExists(const wxChar *pszPathName) +{ + wxString strPath(pszPathName); + +#if defined(__WINDOWS__) || defined(__OS2__) + // Windows fails to find directory named "c:\dir\" even if "c:\dir" exists, + // so remove all trailing backslashes from the path - but don't do this for + // the paths "d:\" (which are different from "d:") nor for just "\" + while ( wxEndsWithPathSeparator(strPath) ) + { + size_t len = strPath.length(); + if ( len == 1 || (len == 3 && strPath[len - 2] == _T(':')) ) + break; + + strPath.Truncate(len - 1); + } +#endif // __WINDOWS__ + +#ifdef __OS2__ + // OS/2 can't handle "d:", it wants either "d:\" or "d:." + if (strPath.length() == 2 && strPath[1u] == _T(':')) + strPath << _T('.'); +#endif + +#if defined(__WXPALMOS__) + return false; +#elif defined(__WIN32__) && !defined(__WXMICROWIN__) + // stat() can't cope with network paths + DWORD ret = ::GetFileAttributes(strPath); + + return (ret != (DWORD)-1) && (ret & FILE_ATTRIBUTE_DIRECTORY); +#elif defined(__OS2__) + FILESTATUS3 Info = {{0}}; + APIRET rc = ::DosQueryPathInfo((PSZ)(WXSTRINGCAST strPath), FIL_STANDARD, + (void*) &Info, sizeof(FILESTATUS3)); + + return ((rc == NO_ERROR) && (Info.attrFile & FILE_DIRECTORY)) || + (rc == ERROR_SHARING_VIOLATION); + // If we got a sharing violation, there must be something with this name. +#else // !__WIN32__ + + wxStructStat st; +#ifndef __VISAGECPP__ + return wxStat(strPath.c_str(), &st) == 0 && ((st.st_mode & S_IFMT) == S_IFDIR); +#else + // S_IFMT not supported in VA compilers.. st_mode is a 2byte value only + return wxStat(pszPathName, &st) == 0 && (st.st_mode == S_IFDIR); +#endif + +#endif // __WIN32__/!__WIN32__ +} + +// Get a temporary filename, opening and closing the file. +wxChar *wxGetTempFileName(const wxString& prefix, wxChar *buf) +{ + wxString filename; + if ( !wxGetTempFileName(prefix, filename) ) + return NULL; + + if ( buf ) + wxStrcpy(buf, filename); + else + buf = MYcopystring(filename); + + return buf; +} + +bool wxGetTempFileName(const wxString& prefix, wxString& buf) +{ +#if wxUSE_FILE + buf = wxFileName::CreateTempFileName(prefix); + + return !buf.empty(); +#else // !wxUSE_FILE + wxUnusedVar(prefix); + wxUnusedVar(buf); + + return false; +#endif // wxUSE_FILE/!wxUSE_FILE +} + +// Get first file name matching given wild card. + +static wxDir *gs_dir = NULL; +static wxString gs_dirPath; + +wxString wxFindFirstFile(const wxChar *spec, int flags) +{ + wxSplitPath(spec, &gs_dirPath, NULL, NULL); + if ( gs_dirPath.empty() ) + gs_dirPath = wxT("."); + if ( !wxEndsWithPathSeparator(gs_dirPath ) ) + gs_dirPath << wxFILE_SEP_PATH; + + if (gs_dir) + delete gs_dir; + gs_dir = new wxDir(gs_dirPath); + + if ( !gs_dir->IsOpened() ) + { + wxLogSysError(_("Can not enumerate files '%s'"), spec); + return wxEmptyString; + } + + int dirFlags; + switch (flags) + { + case wxDIR: dirFlags = wxDIR_DIRS; break; + case wxFILE: dirFlags = wxDIR_FILES; break; + default: dirFlags = wxDIR_DIRS | wxDIR_FILES; break; + } + + wxString result; + gs_dir->GetFirst(&result, wxFileNameFromPath(wxString(spec)), dirFlags); + if ( result.empty() ) + { + wxDELETE(gs_dir); + return result; + } + + return gs_dirPath + result; +} + +wxString wxFindNextFile() +{ + wxASSERT_MSG( gs_dir, wxT("You must call wxFindFirstFile before!") ); + + wxString result; + gs_dir->GetNext(&result); + + if ( result.empty() ) + { + wxDELETE(gs_dir); + return result; + } + + return gs_dirPath + result; +} + + +// Get current working directory. +// If buf is NULL, allocates space using new, else copies into buf. +// wxGetWorkingDirectory() is obsolete, use wxGetCwd() +// wxDoGetCwd() is their common core to be moved +// to wxGetCwd() once wxGetWorkingDirectory() will be removed. +// Do not expose wxDoGetCwd in headers! + +wxChar *wxDoGetCwd(wxChar *buf, int sz) +{ +#if defined(__WXPALMOS__) + // TODO + if(buf && sz>0) buf[0] = _T('\0'); + return buf; +#elif defined(__WXWINCE__) + // TODO + if(buf && sz>0) buf[0] = _T('\0'); + return buf; +#else + if ( !buf ) + { + buf = new wxChar[sz + 1]; + } + + bool ok wxDUMMY_INITIALIZE(false); + + // for the compilers which have Unicode version of _getcwd(), call it + // directly, for the others call the ANSI version and do the translation +#if !wxUSE_UNICODE + #define cbuf buf +#else // wxUSE_UNICODE + bool needsANSI = true; + + #if !defined(HAVE_WGETCWD) || wxUSE_UNICODE_MSLU + char cbuf[_MAXPATHLEN]; + #endif + + #ifdef HAVE_WGETCWD + #if wxUSE_UNICODE_MSLU + if ( wxGetOsVersion() != wxOS_WINDOWS_9X ) + #else + char *cbuf = NULL; // never really used because needsANSI will always be false + #endif + { + ok = _wgetcwd(buf, sz) != NULL; + needsANSI = false; + } + #endif + + if ( needsANSI ) +#endif // wxUSE_UNICODE + { + #if defined(_MSC_VER) || defined(__MINGW32__) + ok = _getcwd(cbuf, sz) != NULL; + #elif defined(__WXMAC__) && !defined(__DARWIN__) + char lbuf[1024] ; + if ( getcwd( lbuf , sizeof( lbuf ) ) ) + { + wxString res( lbuf , *wxConvCurrent ) ; + wxStrcpy( buf , res ) ; + ok = true; + } + else + ok = false ; + #elif defined(__OS2__) + APIRET rc; + ULONG ulDriveNum = 0; + ULONG ulDriveMap = 0; + rc = ::DosQueryCurrentDisk(&ulDriveNum, &ulDriveMap); + ok = rc == 0; + if (ok) + { + sz -= 3; + rc = ::DosQueryCurrentDir( 0 // current drive + ,(PBYTE)cbuf + 3 + ,(PULONG)&sz + ); + cbuf[0] = char('A' + (ulDriveNum - 1)); + cbuf[1] = ':'; + cbuf[2] = '\\'; + ok = rc == 0; + } + #else // !Win32/VC++ !Mac !OS2 + ok = getcwd(cbuf, sz) != NULL; + #endif // platform + + #if wxUSE_UNICODE && !(defined(__WXMAC__) && !defined(__DARWIN__)) + // finally convert the result to Unicode if needed + wxConvFile.MB2WC(buf, cbuf, sz); + #endif // wxUSE_UNICODE + } + + if ( !ok ) + { + wxLogSysError(_("Failed to get the working directory")); + + // VZ: the old code used to return "." on error which didn't make any + // sense at all to me - empty string is a better error indicator + // (NULL might be even better but I'm afraid this could lead to + // problems with the old code assuming the return is never NULL) + buf[0] = _T('\0'); + } + else // ok, but we might need to massage the path into the right format + { +#ifdef __DJGPP__ + // VS: DJGPP is a strange mix of DOS and UNIX API and returns paths + // with / deliminers. We don't like that. + for (wxChar *ch = buf; *ch; ch++) + { + if (*ch == wxT('/')) + *ch = wxT('\\'); + } +#endif // __DJGPP__ + +// MBN: we hope that in the case the user is compiling a GTK+/Motif app, +// he needs Unix as opposed to Win32 pathnames +#if defined( __CYGWIN__ ) && defined( __WINDOWS__ ) + // another example of DOS/Unix mix (Cygwin) + wxString pathUnix = buf; +#if wxUSE_UNICODE + char bufA[_MAXPATHLEN]; + cygwin_conv_to_full_win32_path(pathUnix.mb_str(wxConvFile), bufA); + wxConvFile.MB2WC(buf, bufA, sz); +#else + cygwin_conv_to_full_win32_path(pathUnix, buf); +#endif // wxUSE_UNICODE +#endif // __CYGWIN__ + } + + return buf; + +#if !wxUSE_UNICODE + #undef cbuf +#endif + +#endif + // __WXWINCE__ +} + +#if WXWIN_COMPATIBILITY_2_6 +wxChar *wxGetWorkingDirectory(wxChar *buf, int sz) +{ + return wxDoGetCwd(buf,sz); +} +#endif // WXWIN_COMPATIBILITY_2_6 + +wxString wxGetCwd() +{ + wxString str; + wxDoGetCwd(wxStringBuffer(str, _MAXPATHLEN), _MAXPATHLEN); + return str; +} + +bool wxSetWorkingDirectory(const wxString& d) +{ +#if defined(__OS2__) + if (d[1] == ':') + { + ::DosSetDefaultDisk(1 + wxToupper(d[0]) - _T('A')); + // do not call DosSetCurrentDir when just changing drive, + // since it requires e.g. "d:." instead of "d:"! + if (d.length() == 2) + return true; + } + return (::DosSetCurrentDir((PSZ)d.c_str()) == 0); +#elif defined(__UNIX__) || defined(__WXMAC__) || defined(__DOS__) + return (chdir(wxFNSTRINGCAST d.fn_str()) == 0); +#elif defined(__WINDOWS__) + +#ifdef __WIN32__ +#ifdef __WXWINCE__ + // No equivalent in WinCE + wxUnusedVar(d); + return false; +#else + return (bool)(SetCurrentDirectory(d) != 0); +#endif +#else + // Must change drive, too. + bool isDriveSpec = ((strlen(d) > 1) && (d[1] == ':')); + if (isDriveSpec) + { + wxChar firstChar = d[0]; + + // To upper case + if (firstChar > 90) + firstChar = firstChar - 32; + + // To a drive number + unsigned int driveNo = firstChar - 64; + if (driveNo > 0) + { + unsigned int noDrives; + _dos_setdrive(driveNo, &noDrives); + } + } + bool success = (chdir(WXSTRINGCAST d) == 0); + + return success; +#endif + +#endif +} + +// Get the OS directory if appropriate (such as the Windows directory). +// On non-Windows platform, probably just return the empty string. +wxString wxGetOSDirectory() +{ +#ifdef __WXWINCE__ + return wxString(wxT("\\Windows")); +#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) + wxChar buf[256]; + GetWindowsDirectory(buf, 256); + return wxString(buf); +#elif defined(__WXMAC__) + return wxMacFindFolder(kOnSystemDisk, 'macs', false); +#else + return wxEmptyString; +#endif +} + +bool wxEndsWithPathSeparator(const wxChar *pszFileName) +{ + size_t len = wxStrlen(pszFileName); + + return len && wxIsPathSeparator(pszFileName[len - 1]); +} + +// find a file in a list of directories, returns false if not found +bool wxFindFileInPath(wxString *pStr, const wxChar *pszPath, const wxChar *pszFile) +{ + // we assume that it's not empty + wxCHECK_MSG( !wxIsEmpty(pszFile), false, + _T("empty file name in wxFindFileInPath")); + + // skip path separator in the beginning of the file name if present + if ( wxIsPathSeparator(*pszFile) ) + pszFile++; + + // copy the path (strtok will modify it) + wxChar *szPath = new wxChar[wxStrlen(pszPath) + 1]; + wxStrcpy(szPath, pszPath); + + wxString strFile; + wxChar *pc, *save_ptr; + for ( pc = wxStrtok(szPath, wxPATH_SEP, &save_ptr); + pc != NULL; + pc = wxStrtok((wxChar *) NULL, wxPATH_SEP, &save_ptr) ) + { + // search for the file in this directory + strFile = pc; + if ( !wxEndsWithPathSeparator(pc) ) + strFile += wxFILE_SEP_PATH; + strFile += pszFile; + + if ( wxFileExists(strFile) ) { + *pStr = strFile; + break; + } + } + + // suppress warning about unused variable save_ptr when wxStrtok() is a + // macro which throws away its third argument + save_ptr = pc; + + delete [] szPath; + + return pc != NULL; // if true => we breaked from the loop +} + +void WXDLLEXPORT wxSplitPath(const wxChar *pszFileName, + wxString *pstrPath, + wxString *pstrName, + wxString *pstrExt) +{ + // it can be empty, but it shouldn't be NULL + wxCHECK_RET( pszFileName, wxT("NULL file name in wxSplitPath") ); + + wxFileName::SplitPath(pszFileName, pstrPath, pstrName, pstrExt); +} + +#if wxUSE_DATETIME + +time_t WXDLLEXPORT wxFileModificationTime(const wxString& filename) +{ + wxDateTime mtime; + if ( !wxFileName(filename).GetTimes(NULL, &mtime, NULL) ) + return (time_t)-1; + + return mtime.GetTicks(); +} + +#endif // wxUSE_DATETIME + + +// Parses the filterStr, returning the number of filters. +// Returns 0 if none or if there's a problem. +// filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpeg" + +int WXDLLEXPORT wxParseCommonDialogsFilter(const wxString& filterStr, + wxArrayString& descriptions, + wxArrayString& filters) +{ + descriptions.Clear(); + filters.Clear(); + + wxString str(filterStr); + + wxString description, filter; + int pos = 0; + while( pos != wxNOT_FOUND ) + { + pos = str.Find(wxT('|')); + if ( pos == wxNOT_FOUND ) + { + // if there are no '|'s at all in the string just take the entire + // string as filter and make description empty for later autocompletion + if ( filters.IsEmpty() ) + { + descriptions.Add(wxEmptyString); + filters.Add(filterStr); + } + else + { + wxFAIL_MSG( _T("missing '|' in the wildcard string!") ); + } + + break; + } + + description = str.Left(pos); + str = str.Mid(pos + 1); + pos = str.Find(wxT('|')); + if ( pos == wxNOT_FOUND ) + { + filter = str; + } + else + { + filter = str.Left(pos); + str = str.Mid(pos + 1); + } + + descriptions.Add(description); + filters.Add(filter); + } + +#if defined(__WXMOTIF__) + // split it so there is one wildcard per entry + for( size_t i = 0 ; i < descriptions.GetCount() ; i++ ) + { + pos = filters[i].Find(wxT(';')); + if (pos != wxNOT_FOUND) + { + // first split only filters + descriptions.Insert(descriptions[i],i+1); + filters.Insert(filters[i].Mid(pos+1),i+1); + filters[i]=filters[i].Left(pos); + + // autoreplace new filter in description with pattern: + // C/C++ Files(*.cpp;*.c;*.h)|*.cpp;*.c;*.h + // cause split into: + // C/C++ Files(*.cpp)|*.cpp + // C/C++ Files(*.c;*.h)|*.c;*.h + // and next iteration cause another split into: + // C/C++ Files(*.cpp)|*.cpp + // C/C++ Files(*.c)|*.c + // C/C++ Files(*.h)|*.h + for ( size_t k=i;kbefore.Find(_T(')'),true)) + { + before = before.Left(pos+1); + before << filters[k]; + pos = after.Find(_T(')')); + int pos1 = after.Find(_T('(')); + if (pos != wxNOT_FOUND && (pos +* +* The match procedure is public domain code (from ircII's reg.c) +* but modified to suit our tastes (RN: No "%" syntax I guess) +*/ + +bool wxMatchWild( const wxString& pat, const wxString& text, bool dot_special ) +{ + if (text.empty()) + { + /* Match if both are empty. */ + return pat.empty(); + } + + const wxChar *m = pat.c_str(), + *n = text.c_str(), + *ma = NULL, + *na = NULL; + int just = 0, + acount = 0, + count = 0; + + if (dot_special && (*n == wxT('.'))) + { + /* Never match so that hidden Unix files + * are never found. */ + return false; + } + + for (;;) + { + if (*m == wxT('*')) + { + ma = ++m; + na = n; + just = 1; + acount = count; + } + else if (*m == wxT('?')) + { + m++; + if (!*n++) + return false; + } + else + { + if (*m == wxT('\\')) + { + m++; + /* Quoting "nothing" is a bad thing */ + if (!*m) + return false; + } + if (!*m) + { + /* + * If we are out of both strings or we just + * saw a wildcard, then we can say we have a + * match + */ + if (!*n) + return true; + if (just) + return true; + just = 0; + goto not_matched; + } + /* + * We could check for *n == NULL at this point, but + * since it's more common to have a character there, + * check to see if they match first (m and n) and + * then if they don't match, THEN we can check for + * the NULL of n + */ + just = 0; + if (*m == *n) + { + m++; + count++; + n++; + } + else + { + + not_matched: + + /* + * If there are no more characters in the + * string, but we still need to find another + * character (*m != NULL), then it will be + * impossible to match it + */ + if (!*n) + return false; + + if (ma) + { + m = ma; + n = ++na; + count = acount; + } + else + return false; + } + } + } +} + +#ifdef __VISUALC__ + #pragma warning(default:4706) // assignment within conditional expression +#endif // VC++ diff --git a/Source/3rd Party/wx/src/common/filename.cpp b/Source/3rd Party/wx/src/common/filename.cpp index 7f87eb0b0..f50c40927 100644 --- a/Source/3rd Party/wx/src/common/filename.cpp +++ b/Source/3rd Party/wx/src/common/filename.cpp @@ -1,2558 +1,2558 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/filename.cpp -// Purpose: wxFileName - encapsulates a file path -// Author: Robert Roebling, Vadim Zeitlin -// Modified by: -// Created: 28.12.2000 -// RCS-ID: $Id: filename.cpp 66915 2011-02-16 21:46:49Z JS $ -// Copyright: (c) 2000 Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -/* - Here are brief descriptions of the filename formats supported by this class: - - wxPATH_UNIX: standard Unix format, used under Darwin as well, absolute file - names have the form: - /dir1/dir2/.../dirN/filename, "." and ".." stand for the - current and parent directory respectively, "~" is parsed as the - user HOME and "~username" as the HOME of that user - - wxPATH_DOS: DOS/Windows format, absolute file names have the form: - drive:\dir1\dir2\...\dirN\filename.ext where drive is a single - letter. "." and ".." as for Unix but no "~". - - There are also UNC names of the form \\share\fullpath - - wxPATH_MAC: Mac OS 8/9 and Mac OS X under CodeWarrior 7 format, absolute file - names have the form - volume:dir1:...:dirN:filename - and the relative file names are either - :dir1:...:dirN:filename - or just - filename - (although :filename works as well). - Since the volume is just part of the file path, it is not - treated like a separate entity as it is done under DOS and - VMS, it is just treated as another dir. - - wxPATH_VMS: VMS native format, absolute file names have the form - :[dir1.dir2.dir3]file.txt - or - :[000000.dir1.dir2.dir3]file.txt - - the is the physical device (i.e. disk). 000000 is the - root directory on the device which can be omitted. - - Note that VMS uses different separators unlike Unix: - : always after the device. If the path does not contain : than - the default (the device of the current directory) is assumed. - [ start of directory specification - . separator between directory and subdirectory - ] between directory and file - */ - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/wrapwin.h" // For GetShort/LongPathName - #endif - #include "wx/dynarray.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" -#endif - -#include "wx/filename.h" -#include "wx/private/filename.h" -#include "wx/tokenzr.h" -#include "wx/config.h" // for wxExpandEnvVars -#include "wx/dynlib.h" - -#if defined(__WIN32__) && defined(__MINGW32__) - #include "wx/msw/gccpriv.h" -#endif - -#ifdef __WXWINCE__ -#include "wx/msw/private.h" -#endif - -#if defined(__WXMAC__) - #include "wx/mac/private.h" // includes mac headers -#endif - -// utime() is POSIX so should normally be available on all Unices -#ifdef __UNIX_LIKE__ -#include -#include -#include -#include -#endif - -#ifdef __DJGPP__ -#include -#endif - -#ifdef __MWERKS__ -#ifdef __MACH__ -#include -#include -#include -#include -#else -#include -#include -#include -#endif -#endif - -#ifdef __WATCOMC__ -#include -#include -#include -#endif - -#ifdef __VISAGECPP__ -#ifndef MAX_PATH -#define MAX_PATH 256 -#endif -#endif - -#ifdef __EMX__ -#include -#define MAX_PATH _MAX_PATH -#endif - - -wxULongLong wxInvalidSize = (unsigned)-1; - - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -// small helper class which opens and closes the file - we use it just to get -// a file handle for the given file name to pass it to some Win32 API function -#if defined(__WIN32__) && !defined(__WXMICROWIN__) - -class wxFileHandle -{ -public: - enum OpenMode - { - Read, - Write - }; - - wxFileHandle(const wxString& filename, OpenMode mode, int flags = 0) - { - m_hFile = ::CreateFile - ( - filename, // name - mode == Read ? GENERIC_READ // access mask - : GENERIC_WRITE, - FILE_SHARE_READ | // sharing mode - FILE_SHARE_WRITE, // (allow everything) - NULL, // no secutity attr - OPEN_EXISTING, // creation disposition - flags, // flags - NULL // no template file - ); - - if ( m_hFile == INVALID_HANDLE_VALUE ) - { - wxLogSysError(_("Failed to open '%s' for %s"), - filename.c_str(), - mode == Read ? _("reading") : _("writing")); - } - } - - ~wxFileHandle() - { - if ( m_hFile != INVALID_HANDLE_VALUE ) - { - if ( !::CloseHandle(m_hFile) ) - { - wxLogSysError(_("Failed to close file handle")); - } - } - } - - // return true only if the file could be opened successfully - bool IsOk() const { return m_hFile != INVALID_HANDLE_VALUE; } - - // get the handle - operator HANDLE() const { return m_hFile; } - -private: - HANDLE m_hFile; -}; - -#endif // __WIN32__ - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -#if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__) - -// convert between wxDateTime and FILETIME which is a 64-bit value representing -// the number of 100-nanosecond intervals since January 1, 1601. - -static void ConvertFileTimeToWx(wxDateTime *dt, const FILETIME &ft) -{ - FILETIME ftcopy = ft; - FILETIME ftLocal; - if ( !::FileTimeToLocalFileTime(&ftcopy, &ftLocal) ) - { - wxLogLastError(_T("FileTimeToLocalFileTime")); - } - - SYSTEMTIME st; - if ( !::FileTimeToSystemTime(&ftLocal, &st) ) - { - wxLogLastError(_T("FileTimeToSystemTime")); - } - - dt->Set(st.wDay, wxDateTime::Month(st.wMonth - 1), st.wYear, - st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); -} - -static void ConvertWxToFileTime(FILETIME *ft, const wxDateTime& dt) -{ - SYSTEMTIME st; - st.wDay = dt.GetDay(); - st.wMonth = (WORD)(dt.GetMonth() + 1); - st.wYear = (WORD)dt.GetYear(); - st.wHour = dt.GetHour(); - st.wMinute = dt.GetMinute(); - st.wSecond = dt.GetSecond(); - st.wMilliseconds = dt.GetMillisecond(); - - FILETIME ftLocal; - if ( !::SystemTimeToFileTime(&st, &ftLocal) ) - { - wxLogLastError(_T("SystemTimeToFileTime")); - } - - if ( !::LocalFileTimeToFileTime(&ftLocal, ft) ) - { - wxLogLastError(_T("LocalFileTimeToFileTime")); - } -} - -#endif // wxUSE_DATETIME && __WIN32__ - -// return a string with the volume par -static wxString wxGetVolumeString(const wxString& volume, wxPathFormat format) -{ - wxString path; - - if ( !volume.empty() ) - { - format = wxFileName::GetFormat(format); - - // Special Windows UNC paths hack, part 2: undo what we did in - // SplitPath() and make an UNC path if we have a drive which is not a - // single letter (hopefully the network shares can't be one letter only - // although I didn't find any authoritative docs on this) - if ( format == wxPATH_DOS && volume.length() > 1 ) - { - path << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_DOS << volume; - } - else if ( format == wxPATH_DOS || format == wxPATH_VMS ) - { - path << volume << wxFileName::GetVolumeSeparator(format); - } - // else ignore - } - - return path; -} - -// return true if the character is a DOS path separator i.e. either a slash or -// a backslash -inline bool IsDOSPathSep(wxChar ch) -{ - return ch == wxFILE_SEP_PATH_DOS || ch == wxFILE_SEP_PATH_UNIX; -} - -// return true if the format used is the DOS/Windows one and the string looks -// like a UNC path -static bool IsUNCPath(const wxString& path, wxPathFormat format) -{ - return format == wxPATH_DOS && - path.length() >= 4 && // "\\a" can't be a UNC path - IsDOSPathSep(path[0u]) && - IsDOSPathSep(path[1u]) && - !IsDOSPathSep(path[2u]); -} - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxFileName construction -// ---------------------------------------------------------------------------- - -void wxFileName::Assign( const wxFileName &filepath ) -{ - if ( &filepath == this ) - return; - - m_volume = filepath.GetVolume(); - m_dirs = filepath.GetDirs(); - m_name = filepath.GetName(); - m_ext = filepath.GetExt(); - m_relative = filepath.m_relative; - m_hasExt = filepath.m_hasExt; -} - -void wxFileName::Assign(const wxString& volume, - const wxString& path, - const wxString& name, - const wxString& ext, - bool hasExt, - wxPathFormat format) -{ - // we should ignore paths which look like UNC shares because we already - // have the volume here and the UNC notation (\\server\path) is only valid - // for paths which don't start with a volume, so prevent SetPath() from - // recognizing "\\foo\bar" in "c:\\foo\bar" as an UNC path - // - // note also that this is a rather ugly way to do what we want (passing - // some kind of flag telling to ignore UNC paths to SetPath() would be - // better) but this is the safest thing to do to avoid breaking backwards - // compatibility in 2.8 - if ( IsUNCPath(path, format) ) - { - // remove one of the 2 leading backslashes to ensure that it's not - // recognized as an UNC path by SetPath() - wxString pathNonUNC(path, 1, wxString::npos); - SetPath(pathNonUNC, format); - } - else // no UNC complications - { - SetPath(path, format); - } - - m_volume = volume; - m_ext = ext; - m_name = name; - - m_hasExt = hasExt; -} - -void wxFileName::SetPath( const wxString& pathOrig, wxPathFormat format ) -{ - m_dirs.Clear(); - - if ( pathOrig.empty() ) - { - // no path at all - m_relative = true; - - return; - } - - format = GetFormat( format ); - - // 0) deal with possible volume part first - wxString volume, - path; - SplitVolume(pathOrig, &volume, &path, format); - if ( !volume.empty() ) - { - m_relative = false; - - SetVolume(volume); - } - - // 1) Determine if the path is relative or absolute. - wxChar leadingChar = path[0u]; - - switch (format) - { - case wxPATH_MAC: - m_relative = leadingChar == wxT(':'); - - // We then remove a leading ":". The reason is in our - // storage form for relative paths: - // ":dir:file.txt" actually means "./dir/file.txt" in - // DOS notation and should get stored as - // (relative) (dir) (file.txt) - // "::dir:file.txt" actually means "../dir/file.txt" - // stored as (relative) (..) (dir) (file.txt) - // This is important only for the Mac as an empty dir - // actually means , whereas under DOS, double - // slashes can be ignored: "\\\\" is the same as "\\". - if (m_relative) - path.erase( 0, 1 ); - break; - - case wxPATH_VMS: - // TODO: what is the relative path format here? - m_relative = false; - break; - - default: - wxFAIL_MSG( _T("Unknown path format") ); - // !! Fall through !! - - case wxPATH_UNIX: - // the paths of the form "~" or "~username" are absolute - m_relative = leadingChar != wxT('/') && leadingChar != _T('~'); - break; - - case wxPATH_DOS: - m_relative = !IsPathSeparator(leadingChar, format); - break; - - } - - // 2) Break up the path into its members. If the original path - // was just "/" or "\\", m_dirs will be empty. We know from - // the m_relative field, if this means "nothing" or "root dir". - - wxStringTokenizer tn( path, GetPathSeparators(format) ); - - while ( tn.HasMoreTokens() ) - { - wxString token = tn.GetNextToken(); - - // Remove empty token under DOS and Unix, interpret them - // as .. under Mac. - if (token.empty()) - { - if (format == wxPATH_MAC) - m_dirs.Add( wxT("..") ); - // else ignore - } - else - { - m_dirs.Add( token ); - } - } -} - -void wxFileName::Assign(const wxString& fullpath, - wxPathFormat format) -{ - wxString volume, path, name, ext; - bool hasExt; - SplitPath(fullpath, &volume, &path, &name, &ext, &hasExt, format); - - Assign(volume, path, name, ext, hasExt, format); -} - -void wxFileName::Assign(const wxString& fullpathOrig, - const wxString& fullname, - wxPathFormat format) -{ - // always recognize fullpath as directory, even if it doesn't end with a - // slash - wxString fullpath = fullpathOrig; - if ( !fullpath.empty() && !wxEndsWithPathSeparator(fullpath) ) - { - fullpath += GetPathSeparator(format); - } - - wxString volume, path, name, ext; - bool hasExt; - - // do some consistency checks in debug mode: the name should be really just - // the filename and the path should be really just a path -#ifdef __WXDEBUG__ - wxString volDummy, pathDummy, nameDummy, extDummy; - - SplitPath(fullname, &volDummy, &pathDummy, &name, &ext, &hasExt, format); - - wxASSERT_MSG( volDummy.empty() && pathDummy.empty(), - _T("the file name shouldn't contain the path") ); - - SplitPath(fullpath, &volume, &path, &nameDummy, &extDummy, format); - - wxASSERT_MSG( nameDummy.empty() && extDummy.empty(), - _T("the path shouldn't contain file name nor extension") ); - -#else // !__WXDEBUG__ - SplitPath(fullname, NULL /* no volume */, NULL /* no path */, - &name, &ext, &hasExt, format); - SplitPath(fullpath, &volume, &path, NULL, NULL, format); -#endif // __WXDEBUG__/!__WXDEBUG__ - - Assign(volume, path, name, ext, hasExt, format); -} - -void wxFileName::Assign(const wxString& pathOrig, - const wxString& name, - const wxString& ext, - wxPathFormat format) -{ - wxString volume, - path; - SplitVolume(pathOrig, &volume, &path, format); - - Assign(volume, path, name, ext, format); -} - -void wxFileName::AssignDir(const wxString& dir, wxPathFormat format) -{ - Assign(dir, wxEmptyString, format); -} - -void wxFileName::Clear() -{ - m_dirs.Clear(); - - m_volume = - m_name = - m_ext = wxEmptyString; - - // we don't have any absolute path for now - m_relative = true; - - // nor any extension - m_hasExt = false; -} - -/* static */ -wxFileName wxFileName::FileName(const wxString& file, wxPathFormat format) -{ - return wxFileName(file, format); -} - -/* static */ -wxFileName wxFileName::DirName(const wxString& dir, wxPathFormat format) -{ - wxFileName fn; - fn.AssignDir(dir, format); - return fn; -} - -// ---------------------------------------------------------------------------- -// existence tests -// ---------------------------------------------------------------------------- - -bool wxFileName::FileExists() const -{ - return wxFileName::FileExists( GetFullPath() ); -} - -bool wxFileName::FileExists( const wxString &file ) -{ - return ::wxFileExists( file ); -} - -bool wxFileName::DirExists() const -{ - return wxFileName::DirExists( GetPath() ); -} - -bool wxFileName::DirExists( const wxString &dir ) -{ - return ::wxDirExists( dir ); -} - -// ---------------------------------------------------------------------------- -// CWD and HOME stuff -// ---------------------------------------------------------------------------- - -void wxFileName::AssignCwd(const wxString& volume) -{ - AssignDir(wxFileName::GetCwd(volume)); -} - -/* static */ -wxString wxFileName::GetCwd(const wxString& volume) -{ - // if we have the volume, we must get the current directory on this drive - // and to do this we have to chdir to this volume - at least under Windows, - // I don't know how to get the current drive on another volume elsewhere - // (TODO) - wxString cwdOld; - if ( !volume.empty() ) - { - cwdOld = wxGetCwd(); - SetCwd(volume + GetVolumeSeparator()); - } - - wxString cwd = ::wxGetCwd(); - - if ( !volume.empty() ) - { - SetCwd(cwdOld); - } - - return cwd; -} - -bool wxFileName::SetCwd() -{ - return wxFileName::SetCwd( GetPath() ); -} - -bool wxFileName::SetCwd( const wxString &cwd ) -{ - return ::wxSetWorkingDirectory( cwd ); -} - -void wxFileName::AssignHomeDir() -{ - AssignDir(wxFileName::GetHomeDir()); -} - -wxString wxFileName::GetHomeDir() -{ - return ::wxGetHomeDir(); -} - - -// ---------------------------------------------------------------------------- -// CreateTempFileName -// ---------------------------------------------------------------------------- - -#if wxUSE_FILE || wxUSE_FFILE - - -#if !defined wx_fdopen && defined HAVE_FDOPEN - #define wx_fdopen fdopen -#endif - -// NB: GetTempFileName() under Windows creates the file, so using -// O_EXCL there would fail -#ifdef __WINDOWS__ - #define wxOPEN_EXCL 0 -#else - #define wxOPEN_EXCL O_EXCL -#endif - - -#ifdef wxOpenOSFHandle -#define WX_HAVE_DELETE_ON_CLOSE -// On Windows create a file with the FILE_FLAGS_DELETE_ON_CLOSE flags. -// -static int wxOpenWithDeleteOnClose(const wxString& filename) -{ - DWORD access = GENERIC_READ | GENERIC_WRITE; - - DWORD disposition = OPEN_ALWAYS; - - DWORD attributes = FILE_ATTRIBUTE_TEMPORARY | - FILE_FLAG_DELETE_ON_CLOSE; - - HANDLE h = ::CreateFile(filename, access, 0, NULL, - disposition, attributes, NULL); - - return wxOpenOSFHandle(h, wxO_BINARY); -} -#endif // wxOpenOSFHandle - - -// Helper to open the file -// -static int wxTempOpen(const wxString& path, bool *deleteOnClose) -{ -#ifdef WX_HAVE_DELETE_ON_CLOSE - if (*deleteOnClose) - return wxOpenWithDeleteOnClose(path); -#endif - - *deleteOnClose = false; - - return wxOpen(path, wxO_BINARY | O_RDWR | O_CREAT | wxOPEN_EXCL, 0600); -} - - -#if wxUSE_FFILE -// Helper to open the file and attach it to the wxFFile -// -static bool wxTempOpen(wxFFile *file, const wxString& path, bool *deleteOnClose) -{ -#ifndef wx_fdopen - *deleteOnClose = false; - return file->Open(path, _T("w+b")); -#else // wx_fdopen - int fd = wxTempOpen(path, deleteOnClose); - if (fd == -1) - return false; - file->Attach(wx_fdopen(fd, "w+b")); - return file->IsOpened(); -#endif // wx_fdopen -} -#endif // wxUSE_FFILE - - -#if !wxUSE_FILE - #define WXFILEARGS(x, y) y -#elif !wxUSE_FFILE - #define WXFILEARGS(x, y) x -#else - #define WXFILEARGS(x, y) x, y -#endif - - -// Implementation of wxFileName::CreateTempFileName(). -// -static wxString wxCreateTempImpl( - const wxString& prefix, - WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp), - bool *deleteOnClose = NULL) -{ -#if wxUSE_FILE && wxUSE_FFILE - wxASSERT(fileTemp == NULL || ffileTemp == NULL); -#endif - wxString path, dir, name; - bool wantDeleteOnClose = false; - - if (deleteOnClose) - { - // set the result to false initially - wantDeleteOnClose = *deleteOnClose; - *deleteOnClose = false; - } - else - { - // easier if it alwasys points to something - deleteOnClose = &wantDeleteOnClose; - } - - // use the directory specified by the prefix - wxFileName::SplitPath(prefix, &dir, &name, NULL /* extension */); - - if (dir.empty()) - { - dir = wxFileName::GetTempDir(); - } - -#if defined(__WXWINCE__) - path = dir + wxT("\\") + name; - int i = 1; - while (wxFileName::FileExists(path)) - { - path = dir + wxT("\\") + name ; - path << i; - i ++; - } - -#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) - if ( !::GetTempFileName(dir, name, 0, wxStringBuffer(path, MAX_PATH + 1)) ) - { - wxLogLastError(_T("GetTempFileName")); - - path.clear(); - } - -#else // !Windows - path = dir; - - if ( !wxEndsWithPathSeparator(dir) && - (name.empty() || !wxIsPathSeparator(name[0u])) ) - { - path += wxFILE_SEP_PATH; - } - - path += name; - -#if defined(HAVE_MKSTEMP) - // scratch space for mkstemp() - path += _T("XXXXXX"); - - // we need to copy the path to the buffer in which mkstemp() can modify it - wxCharBuffer buf( wxConvFile.cWX2MB( path ) ); - - // cast is safe because the string length doesn't change - int fdTemp = mkstemp( (char*)(const char*) buf ); - if ( fdTemp == -1 ) - { - // this might be not necessary as mkstemp() on most systems should have - // already done it but it doesn't hurt neither... - path.clear(); - } - else // mkstemp() succeeded - { - path = wxConvFile.cMB2WX( (const char*) buf ); - - #if wxUSE_FILE - // avoid leaking the fd - if ( fileTemp ) - { - fileTemp->Attach(fdTemp); - } - else - #endif - - #if wxUSE_FFILE - if ( ffileTemp ) - { - #ifdef wx_fdopen - ffileTemp->Attach(wx_fdopen(fdTemp, "r+b")); - #else - ffileTemp->Open(path, _T("r+b")); - close(fdTemp); - #endif - } - else - #endif - - { - close(fdTemp); - } - } -#else // !HAVE_MKSTEMP - -#ifdef HAVE_MKTEMP - // same as above - path += _T("XXXXXX"); - - wxCharBuffer buf = wxConvFile.cWX2MB( path ); - if ( !mktemp( (char*)(const char*) buf ) ) - { - path.clear(); - } - else - { - path = wxConvFile.cMB2WX( (const char*) buf ); - } -#else // !HAVE_MKTEMP (includes __DOS__) - // generate the unique file name ourselves - #if !defined(__DOS__) && !defined(__PALMOS__) && (!defined(__MWERKS__) || defined(__DARWIN__) ) - path << (unsigned int)getpid(); - #endif - - wxString pathTry; - - static const size_t numTries = 1000; - for ( size_t n = 0; n < numTries; n++ ) - { - // 3 hex digits is enough for numTries == 1000 < 4096 - pathTry = path + wxString::Format(_T("%.03x"), (unsigned int) n); - if ( !wxFileName::FileExists(pathTry) ) - { - break; - } - - pathTry.clear(); - } - - path = pathTry; -#endif // HAVE_MKTEMP/!HAVE_MKTEMP - -#endif // HAVE_MKSTEMP/!HAVE_MKSTEMP - -#endif // Windows/!Windows - - if ( path.empty() ) - { - wxLogSysError(_("Failed to create a temporary file name")); - } - else - { - bool ok = true; - - // open the file - of course, there is a race condition here, this is - // why we always prefer using mkstemp()... - #if wxUSE_FILE - if ( fileTemp && !fileTemp->IsOpened() ) - { - *deleteOnClose = wantDeleteOnClose; - int fd = wxTempOpen(path, deleteOnClose); - if (fd != -1) - fileTemp->Attach(fd); - else - ok = false; - } - #endif - - #if wxUSE_FFILE - if ( ffileTemp && !ffileTemp->IsOpened() ) - { - *deleteOnClose = wantDeleteOnClose; - ok = wxTempOpen(ffileTemp, path, deleteOnClose); - } - #endif - - if ( !ok ) - { - // FIXME: If !ok here should we loop and try again with another - // file name? That is the standard recourse if open(O_EXCL) - // fails, though of course it should be protected against - // possible infinite looping too. - - wxLogError(_("Failed to open temporary file.")); - - path.clear(); - } - } - - return path; -} - - -static bool wxCreateTempImpl( - const wxString& prefix, - WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp), - wxString *name) -{ - bool deleteOnClose = true; - - *name = wxCreateTempImpl(prefix, - WXFILEARGS(fileTemp, ffileTemp), - &deleteOnClose); - - bool ok = !name->empty(); - - if (deleteOnClose) - name->clear(); -#ifdef __UNIX__ - else if (ok && wxRemoveFile(*name)) - name->clear(); -#endif - - return ok; -} - - -static void wxAssignTempImpl( - wxFileName *fn, - const wxString& prefix, - WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp)) -{ - wxString tempname; - tempname = wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, ffileTemp)); - - if ( tempname.empty() ) - { - // error, failed to get temp file name - fn->Clear(); - } - else // ok - { - fn->Assign(tempname); - } -} - - -void wxFileName::AssignTempFileName(const wxString& prefix) -{ - wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, NULL)); -} - -/* static */ -wxString wxFileName::CreateTempFileName(const wxString& prefix) -{ - return wxCreateTempImpl(prefix, WXFILEARGS(NULL, NULL)); -} - -#endif // wxUSE_FILE || wxUSE_FFILE - - -#if wxUSE_FILE - -wxString wxCreateTempFileName(const wxString& prefix, - wxFile *fileTemp, - bool *deleteOnClose) -{ - return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), deleteOnClose); -} - -bool wxCreateTempFile(const wxString& prefix, - wxFile *fileTemp, - wxString *name) -{ - return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), name); -} - -void wxFileName::AssignTempFileName(const wxString& prefix, wxFile *fileTemp) -{ - wxAssignTempImpl(this, prefix, WXFILEARGS(fileTemp, NULL)); -} - -/* static */ -wxString -wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) -{ - return wxCreateTempFileName(prefix, fileTemp); -} - -#endif // wxUSE_FILE - - -#if wxUSE_FFILE - -wxString wxCreateTempFileName(const wxString& prefix, - wxFFile *fileTemp, - bool *deleteOnClose) -{ - return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), deleteOnClose); -} - -bool wxCreateTempFile(const wxString& prefix, - wxFFile *fileTemp, - wxString *name) -{ - return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), name); - -} - -void wxFileName::AssignTempFileName(const wxString& prefix, wxFFile *fileTemp) -{ - wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, fileTemp)); -} - -/* static */ -wxString -wxFileName::CreateTempFileName(const wxString& prefix, wxFFile *fileTemp) -{ - return wxCreateTempFileName(prefix, fileTemp); -} - -#endif // wxUSE_FFILE - - -// ---------------------------------------------------------------------------- -// directory operations -// ---------------------------------------------------------------------------- - -wxString wxFileName::GetTempDir() -{ - wxString dir; - dir = wxGetenv(_T("TMPDIR")); - if (dir.empty()) - { - dir = wxGetenv(_T("TMP")); - if (dir.empty()) - { - dir = wxGetenv(_T("TEMP")); - } - } - -#if defined(__WXWINCE__) - if (dir.empty()) - { - // FIXME. Create \temp dir? - if (DirExists(wxT("\\temp"))) - dir = wxT("\\temp"); - } -#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) - - if ( dir.empty() ) - { - if ( !::GetTempPath(MAX_PATH, wxStringBuffer(dir, MAX_PATH + 1)) ) - { - wxLogLastError(_T("GetTempPath")); - } - - if ( dir.empty() ) - { - // GetTempFileName() fails if we pass it an empty string - dir = _T('.'); - } - } -#else // !Windows - - if ( dir.empty() ) - { - // default -#if defined(__DOS__) || defined(__OS2__) - dir = _T("."); -#elif defined(__WXMAC__) - dir = wxMacFindFolder(short(kOnSystemDisk), kTemporaryFolderType, kCreateFolder); -#else - dir = _T("/tmp"); -#endif - } -#endif - - return dir; -} - -bool wxFileName::Mkdir( int perm, int flags ) -{ - return wxFileName::Mkdir(GetPath(), perm, flags); -} - -bool wxFileName::Mkdir( const wxString& dir, int perm, int flags ) -{ - if ( flags & wxPATH_MKDIR_FULL ) - { - // split the path in components - wxFileName filename; - filename.AssignDir(dir); - - wxString currPath; - if ( filename.HasVolume()) - { - currPath << wxGetVolumeString(filename.GetVolume(), wxPATH_NATIVE); - } - - wxArrayString dirs = filename.GetDirs(); - size_t count = dirs.GetCount(); - for ( size_t i = 0; i < count; i++ ) - { - if ( i > 0 || -#if defined(__WXMAC__) && !defined(__DARWIN__) - // relative pathnames are exactely the other way round under mac... - !filename.IsAbsolute() -#else - filename.IsAbsolute() -#endif - ) - currPath += wxFILE_SEP_PATH; - currPath += dirs[i]; - - if (!DirExists(currPath)) - { - if (!wxMkdir(currPath, perm)) - { - // no need to try creating further directories - return false; - } - } - } - - return true; - - } - - return ::wxMkdir( dir, perm ); -} - -bool wxFileName::Rmdir() -{ - return wxFileName::Rmdir( GetPath() ); -} - -bool wxFileName::Rmdir( const wxString &dir ) -{ - return ::wxRmdir( dir ); -} - -// ---------------------------------------------------------------------------- -// path normalization -// ---------------------------------------------------------------------------- - -bool wxFileName::Normalize(int flags, - const wxString& cwd, - wxPathFormat format) -{ - // deal with env vars renaming first as this may seriously change the path - if ( flags & wxPATH_NORM_ENV_VARS ) - { - wxString pathOrig = GetFullPath(format); - wxString path = wxExpandEnvVars(pathOrig); - if ( path != pathOrig ) - { - Assign(path); - } - } - - - // the existing path components - wxArrayString dirs = GetDirs(); - - // the path to prepend in front to make the path absolute - wxFileName curDir; - - format = GetFormat(format); - - // set up the directory to use for making the path absolute later - if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute(format) ) - { - if ( cwd.empty() ) - { - curDir.AssignCwd(GetVolume()); - } - else // cwd provided - { - curDir.AssignDir(cwd); - } - } - - // handle ~ stuff under Unix only - if ( (format == wxPATH_UNIX) && (flags & wxPATH_NORM_TILDE) ) - { - if ( !dirs.IsEmpty() ) - { - wxString dir = dirs[0u]; - if ( !dir.empty() && dir[0u] == _T('~') ) - { - // to make the path absolute use the home directory - curDir.AssignDir(wxGetUserHome(dir.c_str() + 1)); - - // if we are expanding the tilde, then this path - // *should* be already relative (since we checked for - // the tilde only in the first char of the first dir); - // if m_relative==false, it's because it was initialized - // from a string which started with /~; in that case - // we reach this point but then need m_relative=true - // for relative->absolute expansion later - m_relative = true; - - dirs.RemoveAt(0u); - } - } - } - - // transform relative path into abs one - if ( curDir.IsOk() ) - { - // this path may be relative because it doesn't have the volume name - // and still have m_relative=true; in this case we shouldn't modify - // our directory components but just set the current volume - if ( !HasVolume() && curDir.HasVolume() ) - { - SetVolume(curDir.GetVolume()); - - if ( !m_relative ) - { - // yes, it was the case - we don't need curDir then - curDir.Clear(); - } - } - - // finally, prepend curDir to the dirs array - wxArrayString dirsNew = curDir.GetDirs(); - WX_PREPEND_ARRAY(dirs, dirsNew); - - // if we used e.g. tilde expansion previously and wxGetUserHome didn't - // return for some reason an absolute path, then curDir maybe not be absolute! - if ( curDir.IsAbsolute(format) ) - { - // we have prepended an absolute path and thus we are now an absolute - // file name too - m_relative = false; - } - // else if (flags & wxPATH_NORM_ABSOLUTE): - // should we warn the user that we didn't manage to make the path absolute? - } - - // now deal with ".", ".." and the rest - m_dirs.Empty(); - size_t count = dirs.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - wxString dir = dirs[n]; - - if ( flags & wxPATH_NORM_DOTS ) - { - if ( dir == wxT(".") ) - { - // just ignore - continue; - } - - if ( dir == wxT("..") ) - { - if ( m_dirs.IsEmpty() ) - { - wxLogError(_("The path '%s' contains too many \"..\"!"), - GetFullPath().c_str()); - return false; - } - - m_dirs.RemoveAt(m_dirs.GetCount() - 1); - continue; - } - } - - m_dirs.Add(dir); - } - -#if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE - if ( (flags & wxPATH_NORM_SHORTCUT) ) - { - wxString filename; - if (GetShortcutTarget(GetFullPath(format), filename)) - { - m_relative = false; - Assign(filename); - } - } -#endif - -#if defined(__WIN32__) - if ( (flags & wxPATH_NORM_LONG) && (format == wxPATH_DOS) ) - { - Assign(GetLongPath()); - } -#endif // Win32 - - // Change case (this should be kept at the end of the function, to ensure - // that the path doesn't change any more after we normalize its case) - if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) ) - { - m_volume.MakeLower(); - m_name.MakeLower(); - m_ext.MakeLower(); - - // directory entries must be made lower case as well - count = m_dirs.GetCount(); - for ( size_t i = 0; i < count; i++ ) - { - m_dirs[i].MakeLower(); - } - } - - return true; -} - -// ---------------------------------------------------------------------------- -// get the shortcut target -// ---------------------------------------------------------------------------- - -// WinCE (3) doesn't have CLSID_ShellLink, IID_IShellLink definitions. -// The .lnk file is a plain text file so it should be easy to -// make it work. Hint from Google Groups: -// "If you open up a lnk file, you'll see a -// number, followed by a pound sign (#), followed by more text. The -// number is the number of characters that follows the pound sign. The -// characters after the pound sign are the command line (which _can_ -// include arguments) to be executed. Any path (e.g. \windows\program -// files\myapp.exe) that includes spaces needs to be enclosed in -// quotation marks." - -#if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE -// The following lines are necessary under WinCE -// #include "wx/msw/private.h" -// #include -#include -#if defined(__WXWINCE__) -#include -#endif - -bool wxFileName::GetShortcutTarget(const wxString& shortcutPath, - wxString& targetFilename, - wxString* arguments) -{ - wxString path, file, ext; - wxSplitPath(shortcutPath, & path, & file, & ext); - - HRESULT hres; - IShellLink* psl; - bool success = false; - - // Assume it's not a shortcut if it doesn't end with lnk - if (ext.CmpNoCase(wxT("lnk"))!=0) - return false; - - // create a ShellLink object - hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, - IID_IShellLink, (LPVOID*) &psl); - - if (SUCCEEDED(hres)) - { - IPersistFile* ppf; - hres = psl->QueryInterface( IID_IPersistFile, (LPVOID *) &ppf); - if (SUCCEEDED(hres)) - { - WCHAR wsz[MAX_PATH]; - - MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, shortcutPath.mb_str(), -1, wsz, - MAX_PATH); - - hres = ppf->Load(wsz, 0); - ppf->Release(); - - if (SUCCEEDED(hres)) - { - wxChar buf[2048]; - // Wrong prototype in early versions -#if defined(__MINGW32__) && !wxCHECK_W32API_VERSION(2, 2) - psl->GetPath((CHAR*) buf, 2048, NULL, SLGP_UNCPRIORITY); -#else - psl->GetPath(buf, 2048, NULL, SLGP_UNCPRIORITY); -#endif - targetFilename = wxString(buf); - success = (shortcutPath != targetFilename); - - psl->GetArguments(buf, 2048); - wxString args(buf); - if (!args.empty() && arguments) - { - *arguments = args; - } - } - } - - psl->Release(); - } - return success; -} - -#endif // __WIN32__ && !__WXWINCE__ - - -// ---------------------------------------------------------------------------- -// absolute/relative paths -// ---------------------------------------------------------------------------- - -bool wxFileName::IsAbsolute(wxPathFormat format) const -{ - // if our path doesn't start with a path separator, it's not an absolute - // path - if ( m_relative ) - return false; - - if ( !GetVolumeSeparator(format).empty() ) - { - // this format has volumes and an absolute path must have one, it's not - // enough to have the full path to bean absolute file under Windows - if ( GetVolume().empty() ) - return false; - } - - return true; -} - -bool wxFileName::MakeRelativeTo(const wxString& pathBase, wxPathFormat format) -{ - wxFileName fnBase = wxFileName::DirName(pathBase, format); - - // get cwd only once - small time saving - wxString cwd = wxGetCwd(); - Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format); - fnBase.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format); - - bool withCase = IsCaseSensitive(format); - - // we can't do anything if the files live on different volumes - if ( !GetVolume().IsSameAs(fnBase.GetVolume(), withCase) ) - { - // nothing done - return false; - } - - // same drive, so we don't need our volume - m_volume.clear(); - - // remove common directories starting at the top - while ( !m_dirs.IsEmpty() && !fnBase.m_dirs.IsEmpty() && - m_dirs[0u].IsSameAs(fnBase.m_dirs[0u], withCase) ) - { - m_dirs.RemoveAt(0); - fnBase.m_dirs.RemoveAt(0); - } - - // add as many ".." as needed - size_t count = fnBase.m_dirs.GetCount(); - for ( size_t i = 0; i < count; i++ ) - { - m_dirs.Insert(wxT(".."), 0u); - } - - if ( format == wxPATH_UNIX || format == wxPATH_DOS ) - { - // a directory made relative with respect to itself is '.' under Unix - // and DOS, by definition (but we don't have to insert "./" for the - // files) - if ( m_dirs.IsEmpty() && IsDir() ) - { - m_dirs.Add(_T('.')); - } - } - - m_relative = true; - - // we were modified - return true; -} - -// ---------------------------------------------------------------------------- -// filename kind tests -// ---------------------------------------------------------------------------- - -bool wxFileName::SameAs(const wxFileName& filepath, wxPathFormat format) const -{ - wxFileName fn1 = *this, - fn2 = filepath; - - // get cwd only once - small time saving - wxString cwd = wxGetCwd(); - fn1.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format); - fn2.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format); - - if ( fn1.GetFullPath() == fn2.GetFullPath() ) - return true; - - // TODO: compare inodes for Unix, this works even when filenames are - // different but files are the same (symlinks) (VZ) - - return false; -} - -/* static */ -bool wxFileName::IsCaseSensitive( wxPathFormat format ) -{ - // only Unix filenames are truely case-sensitive - return GetFormat(format) == wxPATH_UNIX; -} - -/* static */ -wxString wxFileName::GetForbiddenChars(wxPathFormat format) -{ - // Inits to forbidden characters that are common to (almost) all platforms. - wxString strForbiddenChars = wxT("*?"); - - // If asserts, wxPathFormat has been changed. In case of a new path format - // addition, the following code might have to be updated. - wxCOMPILE_TIME_ASSERT(wxPATH_MAX == 5, wxPathFormatChanged); - switch ( GetFormat(format) ) - { - default : - wxFAIL_MSG( wxT("Unknown path format") ); - // !! Fall through !! - - case wxPATH_UNIX: - break; - - case wxPATH_MAC: - // On a Mac even names with * and ? are allowed (Tested with OS - // 9.2.1 and OS X 10.2.5) - strForbiddenChars = wxEmptyString; - break; - - case wxPATH_DOS: - strForbiddenChars += wxT("\\/:\"<>|"); - break; - - case wxPATH_VMS: - break; - } - - return strForbiddenChars; -} - -/* static */ -wxString wxFileName::GetVolumeSeparator(wxPathFormat WXUNUSED_IN_WINCE(format)) -{ -#ifdef __WXWINCE__ - return wxEmptyString; -#else - wxString sepVol; - - if ( (GetFormat(format) == wxPATH_DOS) || - (GetFormat(format) == wxPATH_VMS) ) - { - sepVol = wxFILE_SEP_DSK; - } - //else: leave empty - - return sepVol; -#endif -} - -/* static */ -wxString wxFileName::GetPathSeparators(wxPathFormat format) -{ - wxString seps; - switch ( GetFormat(format) ) - { - case wxPATH_DOS: - // accept both as native APIs do but put the native one first as - // this is the one we use in GetFullPath() - seps << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_UNIX; - break; - - default: - wxFAIL_MSG( _T("Unknown wxPATH_XXX style") ); - // fall through - - case wxPATH_UNIX: - seps = wxFILE_SEP_PATH_UNIX; - break; - - case wxPATH_MAC: - seps = wxFILE_SEP_PATH_MAC; - break; - - case wxPATH_VMS: - seps = wxFILE_SEP_PATH_VMS; - break; - } - - return seps; -} - -/* static */ -wxString wxFileName::GetPathTerminators(wxPathFormat format) -{ - format = GetFormat(format); - - // under VMS the end of the path is ']', not the path separator used to - // separate the components - return format == wxPATH_VMS ? wxString(_T(']')) : GetPathSeparators(format); -} - -/* static */ -bool wxFileName::IsPathSeparator(wxChar ch, wxPathFormat format) -{ - // wxString::Find() doesn't work as expected with NUL - it will always find - // it, so test for it separately - return ch != _T('\0') && GetPathSeparators(format).Find(ch) != wxNOT_FOUND; -} - -// ---------------------------------------------------------------------------- -// path components manipulation -// ---------------------------------------------------------------------------- - -/* static */ bool wxFileName::IsValidDirComponent(const wxString& dir) -{ - if ( dir.empty() ) - { - wxFAIL_MSG( _T("empty directory passed to wxFileName::InsertDir()") ); - - return false; - } - - const size_t len = dir.length(); - for ( size_t n = 0; n < len; n++ ) - { - if ( dir[n] == GetVolumeSeparator() || IsPathSeparator(dir[n]) ) - { - wxFAIL_MSG( _T("invalid directory component in wxFileName") ); - - return false; - } - } - - return true; -} - -void wxFileName::AppendDir( const wxString& dir ) -{ - if ( IsValidDirComponent(dir) ) - m_dirs.Add( dir ); -} - -void wxFileName::PrependDir( const wxString& dir ) -{ - InsertDir(0, dir); -} - -void wxFileName::InsertDir(size_t before, const wxString& dir) -{ - if ( IsValidDirComponent(dir) ) - m_dirs.Insert(dir, before); -} - -void wxFileName::RemoveDir(size_t pos) -{ - m_dirs.RemoveAt(pos); -} - -// ---------------------------------------------------------------------------- -// accessors -// ---------------------------------------------------------------------------- - -void wxFileName::SetFullName(const wxString& fullname) -{ - SplitPath(fullname, NULL /* no volume */, NULL /* no path */, - &m_name, &m_ext, &m_hasExt); -} - -wxString wxFileName::GetFullName() const -{ - wxString fullname = m_name; - if ( m_hasExt ) - { - fullname << wxFILE_SEP_EXT << m_ext; - } - - return fullname; -} - -wxString wxFileName::GetPath( int flags, wxPathFormat format ) const -{ - format = GetFormat( format ); - - wxString fullpath; - - // return the volume with the path as well if requested - if ( flags & wxPATH_GET_VOLUME ) - { - fullpath += wxGetVolumeString(GetVolume(), format); - } - - // the leading character - switch ( format ) - { - case wxPATH_MAC: - if ( m_relative ) - fullpath += wxFILE_SEP_PATH_MAC; - break; - - case wxPATH_DOS: - if ( !m_relative ) - fullpath += wxFILE_SEP_PATH_DOS; - break; - - default: - wxFAIL_MSG( wxT("Unknown path format") ); - // fall through - - case wxPATH_UNIX: - if ( !m_relative ) - { - // normally the absolute file names start with a slash - // with one exception: the ones like "~/foo.bar" don't - // have it - if ( m_dirs.IsEmpty() || m_dirs[0u] != _T('~') ) - { - fullpath += wxFILE_SEP_PATH_UNIX; - } - } - break; - - case wxPATH_VMS: - // no leading character here but use this place to unset - // wxPATH_GET_SEPARATOR flag: under VMS it doesn't make sense - // as, if I understand correctly, there should never be a dot - // before the closing bracket - flags &= ~wxPATH_GET_SEPARATOR; - } - - if ( m_dirs.empty() ) - { - // there is nothing more - return fullpath; - } - - // then concatenate all the path components using the path separator - if ( format == wxPATH_VMS ) - { - fullpath += wxT('['); - } - - const size_t dirCount = m_dirs.GetCount(); - for ( size_t i = 0; i < dirCount; i++ ) - { - switch (format) - { - case wxPATH_MAC: - if ( m_dirs[i] == wxT(".") ) - { - // skip appending ':', this shouldn't be done in this - // case as "::" is interpreted as ".." under Unix - continue; - } - - // convert back from ".." to nothing - if ( !m_dirs[i].IsSameAs(wxT("..")) ) - fullpath += m_dirs[i]; - break; - - default: - wxFAIL_MSG( wxT("Unexpected path format") ); - // still fall through - - case wxPATH_DOS: - case wxPATH_UNIX: - fullpath += m_dirs[i]; - break; - - case wxPATH_VMS: - // TODO: What to do with ".." under VMS - - // convert back from ".." to nothing - if ( !m_dirs[i].IsSameAs(wxT("..")) ) - fullpath += m_dirs[i]; - break; - } - - if ( (flags & wxPATH_GET_SEPARATOR) || (i != dirCount - 1) ) - fullpath += GetPathSeparator(format); - } - - if ( format == wxPATH_VMS ) - { - fullpath += wxT(']'); - } - - return fullpath; -} - -wxString wxFileName::GetFullPath( wxPathFormat format ) const -{ - // we already have a function to get the path - wxString fullpath = GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR, - format); - - // now just add the file name and extension to it - fullpath += GetFullName(); - - return fullpath; -} - -// Return the short form of the path (returns identity on non-Windows platforms) -wxString wxFileName::GetShortPath() const -{ - wxString path(GetFullPath()); - -#if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) - DWORD sz = ::GetShortPathName(path, NULL, 0); - if ( sz != 0 ) - { - wxString pathOut; - if ( ::GetShortPathName - ( - path, - wxStringBuffer(pathOut, sz), - sz - ) != 0 ) - { - return pathOut; - } - } -#endif // Windows - - return path; -} - -// Return the long form of the path (returns identity on non-Windows platforms) -wxString wxFileName::GetLongPath() const -{ - wxString pathOut, - path = GetFullPath(); - -#if defined(__WIN32__) && !defined(__WXWINCE__) && !defined(__WXMICROWIN__) - -#if wxUSE_DYNLIB_CLASS - typedef DWORD (WINAPI *GET_LONG_PATH_NAME)(const wxChar *, wxChar *, DWORD); - - // this is MT-safe as in the worst case we're going to resolve the function - // twice -- but as the result is the same in both threads, it's ok - static GET_LONG_PATH_NAME s_pfnGetLongPathName = NULL; - if ( !s_pfnGetLongPathName ) - { - static bool s_triedToLoad = false; - - if ( !s_triedToLoad ) - { - s_triedToLoad = true; - - wxDynamicLibrary dllKernel(_T("kernel32")); - - const wxChar* GetLongPathName = _T("GetLongPathName") -#if wxUSE_UNICODE - _T("W"); -#else // ANSI - _T("A"); -#endif // Unicode/ANSI - - if ( dllKernel.HasSymbol(GetLongPathName) ) - { - s_pfnGetLongPathName = (GET_LONG_PATH_NAME) - dllKernel.GetSymbol(GetLongPathName); - } - - // note that kernel32.dll can be unloaded, it stays in memory - // anyhow as all Win32 programs link to it and so it's safe to call - // GetLongPathName() even after unloading it - } - } - - if ( s_pfnGetLongPathName ) - { - DWORD dwSize = (*s_pfnGetLongPathName)(path, NULL, 0); - if ( dwSize > 0 ) - { - if ( (*s_pfnGetLongPathName) - ( - path, - wxStringBuffer(pathOut, dwSize), - dwSize - ) != 0 ) - { - return pathOut; - } - } - } -#endif // wxUSE_DYNLIB_CLASS - - // The OS didn't support GetLongPathName, or some other error. - // We need to call FindFirstFile on each component in turn. - - WIN32_FIND_DATA findFileData; - HANDLE hFind; - - if ( HasVolume() ) - pathOut = GetVolume() + - GetVolumeSeparator(wxPATH_DOS) + - GetPathSeparator(wxPATH_DOS); - else - pathOut = wxEmptyString; - - wxArrayString dirs = GetDirs(); - dirs.Add(GetFullName()); - - wxString tmpPath; - - size_t count = dirs.GetCount(); - for ( size_t i = 0; i < count; i++ ) - { - // We're using pathOut to collect the long-name path, but using a - // temporary for appending the last path component which may be - // short-name - tmpPath = pathOut + dirs[i]; - - if ( tmpPath.empty() ) - continue; - - // can't see this being necessary? MF - if ( tmpPath.Last() == GetVolumeSeparator(wxPATH_DOS) ) - { - // Can't pass a drive and root dir to FindFirstFile, - // so continue to next dir - tmpPath += wxFILE_SEP_PATH; - pathOut = tmpPath; - continue; - } - - hFind = ::FindFirstFile(tmpPath, &findFileData); - if (hFind == INVALID_HANDLE_VALUE) - { - // Error: most likely reason is that path doesn't exist, so - // append any unprocessed parts and return - for ( i += 1; i < count; i++ ) - tmpPath += wxFILE_SEP_PATH + dirs[i]; - - return tmpPath; - } - - pathOut += findFileData.cFileName; - if ( (i < (count-1)) ) - pathOut += wxFILE_SEP_PATH; - - ::FindClose(hFind); - } -#else // !Win32 - pathOut = path; -#endif // Win32/!Win32 - - return pathOut; -} - -wxPathFormat wxFileName::GetFormat( wxPathFormat format ) -{ - if (format == wxPATH_NATIVE) - { -#if defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__) - format = wxPATH_DOS; -#elif defined(__WXMAC__) && !defined(__DARWIN__) - format = wxPATH_MAC; -#elif defined(__VMS) - format = wxPATH_VMS; -#else - format = wxPATH_UNIX; -#endif - } - return format; -} - -// ---------------------------------------------------------------------------- -// path splitting function -// ---------------------------------------------------------------------------- - -/* static */ -void -wxFileName::SplitVolume(const wxString& fullpathWithVolume, - wxString *pstrVolume, - wxString *pstrPath, - wxPathFormat format) -{ - format = GetFormat(format); - - wxString fullpath = fullpathWithVolume; - - // special Windows UNC paths hack: transform \\share\path into share:path - if ( IsUNCPath(fullpath, format) ) - { - fullpath.erase(0, 2); - - size_t posFirstSlash = - fullpath.find_first_of(GetPathTerminators(format)); - if ( posFirstSlash != wxString::npos ) - { - fullpath[posFirstSlash] = wxFILE_SEP_DSK; - - // UNC paths are always absolute, right? (FIXME) - fullpath.insert(posFirstSlash + 1, 1, wxFILE_SEP_PATH_DOS); - } - } - - // We separate the volume here - if ( format == wxPATH_DOS || format == wxPATH_VMS ) - { - wxString sepVol = GetVolumeSeparator(format); - - size_t posFirstColon = fullpath.find_first_of(sepVol); - if ( posFirstColon != wxString::npos ) - { - if ( pstrVolume ) - { - *pstrVolume = fullpath.Left(posFirstColon); - } - - // remove the volume name and the separator from the full path - fullpath.erase(0, posFirstColon + sepVol.length()); - } - } - - if ( pstrPath ) - *pstrPath = fullpath; -} - -/* static */ -void wxFileName::SplitPath(const wxString& fullpathWithVolume, - wxString *pstrVolume, - wxString *pstrPath, - wxString *pstrName, - wxString *pstrExt, - bool *hasExt, - wxPathFormat format) -{ - format = GetFormat(format); - - wxString fullpath; - SplitVolume(fullpathWithVolume, pstrVolume, &fullpath, format); - - // find the positions of the last dot and last path separator in the path - size_t posLastDot = fullpath.find_last_of(wxFILE_SEP_EXT); - size_t posLastSlash = fullpath.find_last_of(GetPathTerminators(format)); - - // check whether this dot occurs at the very beginning of a path component - if ( (posLastDot != wxString::npos) && - (posLastDot == 0 || - IsPathSeparator(fullpath[posLastDot - 1]) || - (format == wxPATH_VMS && fullpath[posLastDot - 1] == _T(']'))) ) - { - // dot may be (and commonly -- at least under Unix -- is) the first - // character of the filename, don't treat the entire filename as - // extension in this case - posLastDot = wxString::npos; - } - - // if we do have a dot and a slash, check that the dot is in the name part - if ( (posLastDot != wxString::npos) && - (posLastSlash != wxString::npos) && - (posLastDot < posLastSlash) ) - { - // the dot is part of the path, not the start of the extension - posLastDot = wxString::npos; - } - - // now fill in the variables provided by user - if ( pstrPath ) - { - if ( posLastSlash == wxString::npos ) - { - // no path at all - pstrPath->Empty(); - } - else - { - // take everything up to the path separator but take care to make - // the path equal to something like '/', not empty, for the files - // immediately under root directory - size_t len = posLastSlash; - - // this rule does not apply to mac since we do not start with colons (sep) - // except for relative paths - if ( !len && format != wxPATH_MAC) - len++; - - *pstrPath = fullpath.Left(len); - - // special VMS hack: remove the initial bracket - if ( format == wxPATH_VMS ) - { - if ( (*pstrPath)[0u] == _T('[') ) - pstrPath->erase(0, 1); - } - } - } - - if ( pstrName ) - { - // take all characters starting from the one after the last slash and - // up to, but excluding, the last dot - size_t nStart = posLastSlash == wxString::npos ? 0 : posLastSlash + 1; - size_t count; - if ( posLastDot == wxString::npos ) - { - // take all until the end - count = wxString::npos; - } - else if ( posLastSlash == wxString::npos ) - { - count = posLastDot; - } - else // have both dot and slash - { - count = posLastDot - posLastSlash - 1; - } - - *pstrName = fullpath.Mid(nStart, count); - } - - // finally deal with the extension here: we have an added complication that - // extension may be empty (but present) as in "foo." where trailing dot - // indicates the empty extension at the end -- and hence we must remember - // that we have it independently of pstrExt - if ( posLastDot == wxString::npos ) - { - // no extension - if ( pstrExt ) - pstrExt->clear(); - if ( hasExt ) - *hasExt = false; - } - else - { - // take everything after the dot - if ( pstrExt ) - *pstrExt = fullpath.Mid(posLastDot + 1); - if ( hasExt ) - *hasExt = true; - } -} - -/* static */ -void wxFileName::SplitPath(const wxString& fullpath, - wxString *path, - wxString *name, - wxString *ext, - wxPathFormat format) -{ - wxString volume; - SplitPath(fullpath, &volume, path, name, ext, format); - - if ( path ) - { - path->Prepend(wxGetVolumeString(volume, format)); - } -} - -/* static */ -wxString wxFileName::StripExtension(const wxString& fullpath) -{ - wxFileName fn(fullpath); - fn.SetExt(_T("")); - return fn.GetFullPath(); -} - -// ---------------------------------------------------------------------------- -// time functions -// ---------------------------------------------------------------------------- - -#if wxUSE_DATETIME - -bool wxFileName::SetTimes(const wxDateTime *dtAccess, - const wxDateTime *dtMod, - const wxDateTime *dtCreate) -{ -#if defined(__WIN32__) - FILETIME ftAccess, ftCreate, ftWrite; - - if ( dtCreate ) - ConvertWxToFileTime(&ftCreate, *dtCreate); - if ( dtAccess ) - ConvertWxToFileTime(&ftAccess, *dtAccess); - if ( dtMod ) - ConvertWxToFileTime(&ftWrite, *dtMod); - - wxString path; - int flags; - if ( IsDir() ) - { - if ( wxGetOsVersion() == wxOS_WINDOWS_9X ) - { - wxLogError(_("Setting directory access times is not supported under this OS version")); - return false; - } - - path = GetPath(); - flags = FILE_FLAG_BACKUP_SEMANTICS; - } - else // file - { - path = GetFullPath(); - flags = 0; - } - - wxFileHandle fh(path, wxFileHandle::Write, flags); - if ( fh.IsOk() ) - { - if ( ::SetFileTime(fh, - dtCreate ? &ftCreate : NULL, - dtAccess ? &ftAccess : NULL, - dtMod ? &ftWrite : NULL) ) - { - return true; - } - } -#elif defined(__UNIX_LIKE__) || (defined(__DOS__) && defined(__WATCOMC__)) - wxUnusedVar(dtCreate); - - if ( !dtAccess && !dtMod ) - { - // can't modify the creation time anyhow, don't try - return true; - } - - // if dtAccess or dtMod is not specified, use the other one (which must be - // non NULL because of the test above) for both times - utimbuf utm; - utm.actime = dtAccess ? dtAccess->GetTicks() : dtMod->GetTicks(); - utm.modtime = dtMod ? dtMod->GetTicks() : dtAccess->GetTicks(); - if ( utime(GetFullPath().fn_str(), &utm) == 0 ) - { - return true; - } -#else // other platform - wxUnusedVar(dtAccess); - wxUnusedVar(dtMod); - wxUnusedVar(dtCreate); -#endif // platforms - - wxLogSysError(_("Failed to modify file times for '%s'"), - GetFullPath().c_str()); - - return false; -} - -bool wxFileName::Touch() -{ -#if defined(__UNIX_LIKE__) - // under Unix touching file is simple: just pass NULL to utime() - if ( utime(GetFullPath().fn_str(), NULL) == 0 ) - { - return true; - } - - wxLogSysError(_("Failed to touch the file '%s'"), GetFullPath().c_str()); - - return false; -#else // other platform - wxDateTime dtNow = wxDateTime::Now(); - - return SetTimes(&dtNow, &dtNow, NULL /* don't change create time */); -#endif // platforms -} - -#ifdef wxNEED_WX_UNISTD_H - -static int wxStat( const char *file_name, wxStructStat *buf ) -{ - return stat( file_name , buf ); -} - -#endif - -bool wxFileName::GetTimes(wxDateTime *dtAccess, - wxDateTime *dtMod, - wxDateTime *dtCreate) const -{ -#if defined(__WIN32__) - // we must use different methods for the files and directories under - // Windows as CreateFile(GENERIC_READ) doesn't work for the directories and - // CreateFile(FILE_FLAG_BACKUP_SEMANTICS) works -- but only under NT and - // not 9x - bool ok; - FILETIME ftAccess, ftCreate, ftWrite; - if ( IsDir() ) - { - // implemented in msw/dir.cpp - extern bool wxGetDirectoryTimes(const wxString& dirname, - FILETIME *, FILETIME *, FILETIME *); - - // we should pass the path without the trailing separator to - // wxGetDirectoryTimes() - ok = wxGetDirectoryTimes(GetPath(wxPATH_GET_VOLUME), - &ftAccess, &ftCreate, &ftWrite); - } - else // file - { - wxFileHandle fh(GetFullPath(), wxFileHandle::Read); - if ( fh.IsOk() ) - { - ok = ::GetFileTime(fh, - dtCreate ? &ftCreate : NULL, - dtAccess ? &ftAccess : NULL, - dtMod ? &ftWrite : NULL) != 0; - } - else - { - ok = false; - } - } - - if ( ok ) - { - if ( dtCreate ) - ConvertFileTimeToWx(dtCreate, ftCreate); - if ( dtAccess ) - ConvertFileTimeToWx(dtAccess, ftAccess); - if ( dtMod ) - ConvertFileTimeToWx(dtMod, ftWrite); - - return true; - } -#elif defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__OS2__) || (defined(__DOS__) && defined(__WATCOMC__)) - // no need to test for IsDir() here - wxStructStat stBuf; - if ( wxStat( GetFullPath().fn_str(), &stBuf) == 0 ) - { - if ( dtAccess ) - dtAccess->Set(stBuf.st_atime); - if ( dtMod ) - dtMod->Set(stBuf.st_mtime); - if ( dtCreate ) - dtCreate->Set(stBuf.st_ctime); - - return true; - } -#else // other platform - wxUnusedVar(dtAccess); - wxUnusedVar(dtMod); - wxUnusedVar(dtCreate); -#endif // platforms - - wxLogSysError(_("Failed to retrieve file times for '%s'"), - GetFullPath().c_str()); - - return false; -} - -#endif // wxUSE_DATETIME - - -// ---------------------------------------------------------------------------- -// file size functions -// ---------------------------------------------------------------------------- - -/* static */ -wxULongLong wxFileName::GetSize(const wxString &filename) -{ - if (!wxFileExists(filename)) - return wxInvalidSize; - -#if defined(__WXPALMOS__) - // TODO - return wxInvalidSize; -#elif defined(__WIN32__) - wxFileHandle f(filename, wxFileHandle::Read); - if (!f.IsOk()) - return wxInvalidSize; - - DWORD lpFileSizeHigh; - DWORD ret = GetFileSize(f, &lpFileSizeHigh); - if ( ret == INVALID_FILE_SIZE && ::GetLastError() != NO_ERROR ) - return wxInvalidSize; - - return wxULongLong(lpFileSizeHigh, ret); -#else // ! __WIN32__ - wxStructStat st; -#ifndef wxNEED_WX_UNISTD_H - if (wxStat( filename.fn_str() , &st) != 0) -#else - if (wxStat( filename, &st) != 0) -#endif - return wxInvalidSize; - return wxULongLong(st.st_size); -#endif -} - -/* static */ -wxString wxFileName::GetHumanReadableSize(const wxULongLong &bs, - const wxString &nullsize, - int precision) -{ - static const double KILOBYTESIZE = 1024.0; - static const double MEGABYTESIZE = 1024.0*KILOBYTESIZE; - static const double GIGABYTESIZE = 1024.0*MEGABYTESIZE; - static const double TERABYTESIZE = 1024.0*GIGABYTESIZE; - - if (bs == 0 || bs == wxInvalidSize) - return nullsize; - - double bytesize = bs.ToDouble(); - if (bytesize < KILOBYTESIZE) - return wxString::Format(_("%s B"), bs.ToString().c_str()); - if (bytesize < MEGABYTESIZE) - return wxString::Format(_("%.*f kB"), precision, bytesize/KILOBYTESIZE); - if (bytesize < GIGABYTESIZE) - return wxString::Format(_("%.*f MB"), precision, bytesize/MEGABYTESIZE); - if (bytesize < TERABYTESIZE) - return wxString::Format(_("%.*f GB"), precision, bytesize/GIGABYTESIZE); - - return wxString::Format(_("%.*f TB"), precision, bytesize/TERABYTESIZE); -} - -wxULongLong wxFileName::GetSize() const -{ - return GetSize(GetFullPath()); -} - -wxString wxFileName::GetHumanReadableSize(const wxString &failmsg, int precision) const -{ - return GetHumanReadableSize(GetSize(), failmsg, precision); -} - - -// ---------------------------------------------------------------------------- -// Mac-specific functions -// ---------------------------------------------------------------------------- - -#ifdef __WXMAC__ - -const short kMacExtensionMaxLength = 16 ; -class MacDefaultExtensionRecord -{ -public : - MacDefaultExtensionRecord() - { - m_ext[0] = 0 ; - m_type = m_creator = 0 ; - } - MacDefaultExtensionRecord( const MacDefaultExtensionRecord& from ) - { - wxStrcpy( m_ext , from.m_ext ) ; - m_type = from.m_type ; - m_creator = from.m_creator ; - } - MacDefaultExtensionRecord( const wxChar * extension , OSType type , OSType creator ) - { - wxStrncpy( m_ext , extension , kMacExtensionMaxLength ) ; - m_ext[kMacExtensionMaxLength] = 0 ; - m_type = type ; - m_creator = creator ; - } - wxChar m_ext[kMacExtensionMaxLength] ; - OSType m_type ; - OSType m_creator ; -} ; - -WX_DECLARE_OBJARRAY(MacDefaultExtensionRecord, MacDefaultExtensionArray) ; - -bool gMacDefaultExtensionsInited = false ; - -#include "wx/arrimpl.cpp" - -WX_DEFINE_EXPORTED_OBJARRAY(MacDefaultExtensionArray) ; - -MacDefaultExtensionArray gMacDefaultExtensions ; - -// load the default extensions -MacDefaultExtensionRecord gDefaults[] = -{ - MacDefaultExtensionRecord( wxT("txt") , 'TEXT' , 'ttxt' ) , - MacDefaultExtensionRecord( wxT("tif") , 'TIFF' , '****' ) , - MacDefaultExtensionRecord( wxT("jpg") , 'JPEG' , '****' ) , -} ; - -static void MacEnsureDefaultExtensionsLoaded() -{ - if ( !gMacDefaultExtensionsInited ) - { - // we could load the pc exchange prefs here too - for ( size_t i = 0 ; i < WXSIZEOF( gDefaults ) ; ++i ) - { - gMacDefaultExtensions.Add( gDefaults[i] ) ; - } - gMacDefaultExtensionsInited = true ; - } -} - -bool wxFileName::MacSetTypeAndCreator( wxUint32 type , wxUint32 creator ) -{ - FSRef fsRef ; - FSCatalogInfo catInfo; - FileInfo *finfo ; - - if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr ) - { - if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr ) - { - finfo = (FileInfo*)&catInfo.finderInfo; - finfo->fileType = type ; - finfo->fileCreator = creator ; - FSSetCatalogInfo( &fsRef, kFSCatInfoFinderInfo, &catInfo ) ; - return true ; - } - } - return false ; -} - -bool wxFileName::MacGetTypeAndCreator( wxUint32 *type , wxUint32 *creator ) -{ - FSRef fsRef ; - FSCatalogInfo catInfo; - FileInfo *finfo ; - - if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr ) - { - if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr ) - { - finfo = (FileInfo*)&catInfo.finderInfo; - *type = finfo->fileType ; - *creator = finfo->fileCreator ; - return true ; - } - } - return false ; -} - -bool wxFileName::MacSetDefaultTypeAndCreator() -{ - wxUint32 type , creator ; - if ( wxFileName::MacFindDefaultTypeAndCreator(GetExt() , &type , - &creator ) ) - { - return MacSetTypeAndCreator( type , creator ) ; - } - return false; -} - -bool wxFileName::MacFindDefaultTypeAndCreator( const wxString& ext , wxUint32 *type , wxUint32 *creator ) -{ - MacEnsureDefaultExtensionsLoaded() ; - wxString extl = ext.Lower() ; - for( int i = gMacDefaultExtensions.Count() - 1 ; i >= 0 ; --i ) - { - if ( gMacDefaultExtensions.Item(i).m_ext == extl ) - { - *type = gMacDefaultExtensions.Item(i).m_type ; - *creator = gMacDefaultExtensions.Item(i).m_creator ; - return true ; - } - } - return false ; -} - -void wxFileName::MacRegisterDefaultTypeAndCreator( const wxString& ext , wxUint32 type , wxUint32 creator ) -{ - MacEnsureDefaultExtensionsLoaded() ; - MacDefaultExtensionRecord rec ; - rec.m_type = type ; - rec.m_creator = creator ; - wxStrncpy( rec.m_ext , ext.Lower().c_str() , kMacExtensionMaxLength ) ; - gMacDefaultExtensions.Add( rec ) ; -} -#endif +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/filename.cpp +// Purpose: wxFileName - encapsulates a file path +// Author: Robert Roebling, Vadim Zeitlin +// Modified by: +// Created: 28.12.2000 +// RCS-ID: $Id: filename.cpp 66915 2011-02-16 21:46:49Z JS $ +// Copyright: (c) 2000 Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +/* + Here are brief descriptions of the filename formats supported by this class: + + wxPATH_UNIX: standard Unix format, used under Darwin as well, absolute file + names have the form: + /dir1/dir2/.../dirN/filename, "." and ".." stand for the + current and parent directory respectively, "~" is parsed as the + user HOME and "~username" as the HOME of that user + + wxPATH_DOS: DOS/Windows format, absolute file names have the form: + drive:\dir1\dir2\...\dirN\filename.ext where drive is a single + letter. "." and ".." as for Unix but no "~". + + There are also UNC names of the form \\share\fullpath + + wxPATH_MAC: Mac OS 8/9 and Mac OS X under CodeWarrior 7 format, absolute file + names have the form + volume:dir1:...:dirN:filename + and the relative file names are either + :dir1:...:dirN:filename + or just + filename + (although :filename works as well). + Since the volume is just part of the file path, it is not + treated like a separate entity as it is done under DOS and + VMS, it is just treated as another dir. + + wxPATH_VMS: VMS native format, absolute file names have the form + :[dir1.dir2.dir3]file.txt + or + :[000000.dir1.dir2.dir3]file.txt + + the is the physical device (i.e. disk). 000000 is the + root directory on the device which can be omitted. + + Note that VMS uses different separators unlike Unix: + : always after the device. If the path does not contain : than + the default (the device of the current directory) is assumed. + [ start of directory specification + . separator between directory and subdirectory + ] between directory and file + */ + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" // For GetShort/LongPathName + #endif + #include "wx/dynarray.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" +#endif + +#include "wx/filename.h" +#include "wx/private/filename.h" +#include "wx/tokenzr.h" +#include "wx/config.h" // for wxExpandEnvVars +#include "wx/dynlib.h" + +#if defined(__WIN32__) && defined(__MINGW32__) + #include "wx/msw/gccpriv.h" +#endif + +#ifdef __WXWINCE__ +#include "wx/msw/private.h" +#endif + +#if defined(__WXMAC__) + #include "wx/mac/private.h" // includes mac headers +#endif + +// utime() is POSIX so should normally be available on all Unices +#ifdef __UNIX_LIKE__ +#include +#include +#include +#include +#endif + +#ifdef __DJGPP__ +#include +#endif + +#ifdef __MWERKS__ +#ifdef __MACH__ +#include +#include +#include +#include +#else +#include +#include +#include +#endif +#endif + +#ifdef __WATCOMC__ +#include +#include +#include +#endif + +#ifdef __VISAGECPP__ +#ifndef MAX_PATH +#define MAX_PATH 256 +#endif +#endif + +#ifdef __EMX__ +#include +#define MAX_PATH _MAX_PATH +#endif + + +wxULongLong wxInvalidSize = (unsigned)-1; + + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// small helper class which opens and closes the file - we use it just to get +// a file handle for the given file name to pass it to some Win32 API function +#if defined(__WIN32__) && !defined(__WXMICROWIN__) + +class wxFileHandle +{ +public: + enum OpenMode + { + Read, + Write + }; + + wxFileHandle(const wxString& filename, OpenMode mode, int flags = 0) + { + m_hFile = ::CreateFile + ( + filename, // name + mode == Read ? GENERIC_READ // access mask + : GENERIC_WRITE, + FILE_SHARE_READ | // sharing mode + FILE_SHARE_WRITE, // (allow everything) + NULL, // no secutity attr + OPEN_EXISTING, // creation disposition + flags, // flags + NULL // no template file + ); + + if ( m_hFile == INVALID_HANDLE_VALUE ) + { + wxLogSysError(_("Failed to open '%s' for %s"), + filename.c_str(), + mode == Read ? _("reading") : _("writing")); + } + } + + ~wxFileHandle() + { + if ( m_hFile != INVALID_HANDLE_VALUE ) + { + if ( !::CloseHandle(m_hFile) ) + { + wxLogSysError(_("Failed to close file handle")); + } + } + } + + // return true only if the file could be opened successfully + bool IsOk() const { return m_hFile != INVALID_HANDLE_VALUE; } + + // get the handle + operator HANDLE() const { return m_hFile; } + +private: + HANDLE m_hFile; +}; + +#endif // __WIN32__ + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +#if wxUSE_DATETIME && defined(__WIN32__) && !defined(__WXMICROWIN__) + +// convert between wxDateTime and FILETIME which is a 64-bit value representing +// the number of 100-nanosecond intervals since January 1, 1601. + +static void ConvertFileTimeToWx(wxDateTime *dt, const FILETIME &ft) +{ + FILETIME ftcopy = ft; + FILETIME ftLocal; + if ( !::FileTimeToLocalFileTime(&ftcopy, &ftLocal) ) + { + wxLogLastError(_T("FileTimeToLocalFileTime")); + } + + SYSTEMTIME st; + if ( !::FileTimeToSystemTime(&ftLocal, &st) ) + { + wxLogLastError(_T("FileTimeToSystemTime")); + } + + dt->Set(st.wDay, wxDateTime::Month(st.wMonth - 1), st.wYear, + st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); +} + +static void ConvertWxToFileTime(FILETIME *ft, const wxDateTime& dt) +{ + SYSTEMTIME st; + st.wDay = dt.GetDay(); + st.wMonth = (WORD)(dt.GetMonth() + 1); + st.wYear = (WORD)dt.GetYear(); + st.wHour = dt.GetHour(); + st.wMinute = dt.GetMinute(); + st.wSecond = dt.GetSecond(); + st.wMilliseconds = dt.GetMillisecond(); + + FILETIME ftLocal; + if ( !::SystemTimeToFileTime(&st, &ftLocal) ) + { + wxLogLastError(_T("SystemTimeToFileTime")); + } + + if ( !::LocalFileTimeToFileTime(&ftLocal, ft) ) + { + wxLogLastError(_T("LocalFileTimeToFileTime")); + } +} + +#endif // wxUSE_DATETIME && __WIN32__ + +// return a string with the volume par +static wxString wxGetVolumeString(const wxString& volume, wxPathFormat format) +{ + wxString path; + + if ( !volume.empty() ) + { + format = wxFileName::GetFormat(format); + + // Special Windows UNC paths hack, part 2: undo what we did in + // SplitPath() and make an UNC path if we have a drive which is not a + // single letter (hopefully the network shares can't be one letter only + // although I didn't find any authoritative docs on this) + if ( format == wxPATH_DOS && volume.length() > 1 ) + { + path << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_DOS << volume; + } + else if ( format == wxPATH_DOS || format == wxPATH_VMS ) + { + path << volume << wxFileName::GetVolumeSeparator(format); + } + // else ignore + } + + return path; +} + +// return true if the character is a DOS path separator i.e. either a slash or +// a backslash +inline bool IsDOSPathSep(wxChar ch) +{ + return ch == wxFILE_SEP_PATH_DOS || ch == wxFILE_SEP_PATH_UNIX; +} + +// return true if the format used is the DOS/Windows one and the string looks +// like a UNC path +static bool IsUNCPath(const wxString& path, wxPathFormat format) +{ + return format == wxPATH_DOS && + path.length() >= 4 && // "\\a" can't be a UNC path + IsDOSPathSep(path[0u]) && + IsDOSPathSep(path[1u]) && + !IsDOSPathSep(path[2u]); +} + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxFileName construction +// ---------------------------------------------------------------------------- + +void wxFileName::Assign( const wxFileName &filepath ) +{ + if ( &filepath == this ) + return; + + m_volume = filepath.GetVolume(); + m_dirs = filepath.GetDirs(); + m_name = filepath.GetName(); + m_ext = filepath.GetExt(); + m_relative = filepath.m_relative; + m_hasExt = filepath.m_hasExt; +} + +void wxFileName::Assign(const wxString& volume, + const wxString& path, + const wxString& name, + const wxString& ext, + bool hasExt, + wxPathFormat format) +{ + // we should ignore paths which look like UNC shares because we already + // have the volume here and the UNC notation (\\server\path) is only valid + // for paths which don't start with a volume, so prevent SetPath() from + // recognizing "\\foo\bar" in "c:\\foo\bar" as an UNC path + // + // note also that this is a rather ugly way to do what we want (passing + // some kind of flag telling to ignore UNC paths to SetPath() would be + // better) but this is the safest thing to do to avoid breaking backwards + // compatibility in 2.8 + if ( IsUNCPath(path, format) ) + { + // remove one of the 2 leading backslashes to ensure that it's not + // recognized as an UNC path by SetPath() + wxString pathNonUNC(path, 1, wxString::npos); + SetPath(pathNonUNC, format); + } + else // no UNC complications + { + SetPath(path, format); + } + + m_volume = volume; + m_ext = ext; + m_name = name; + + m_hasExt = hasExt; +} + +void wxFileName::SetPath( const wxString& pathOrig, wxPathFormat format ) +{ + m_dirs.Clear(); + + if ( pathOrig.empty() ) + { + // no path at all + m_relative = true; + + return; + } + + format = GetFormat( format ); + + // 0) deal with possible volume part first + wxString volume, + path; + SplitVolume(pathOrig, &volume, &path, format); + if ( !volume.empty() ) + { + m_relative = false; + + SetVolume(volume); + } + + // 1) Determine if the path is relative or absolute. + wxChar leadingChar = path[0u]; + + switch (format) + { + case wxPATH_MAC: + m_relative = leadingChar == wxT(':'); + + // We then remove a leading ":". The reason is in our + // storage form for relative paths: + // ":dir:file.txt" actually means "./dir/file.txt" in + // DOS notation and should get stored as + // (relative) (dir) (file.txt) + // "::dir:file.txt" actually means "../dir/file.txt" + // stored as (relative) (..) (dir) (file.txt) + // This is important only for the Mac as an empty dir + // actually means , whereas under DOS, double + // slashes can be ignored: "\\\\" is the same as "\\". + if (m_relative) + path.erase( 0, 1 ); + break; + + case wxPATH_VMS: + // TODO: what is the relative path format here? + m_relative = false; + break; + + default: + wxFAIL_MSG( _T("Unknown path format") ); + // !! Fall through !! + + case wxPATH_UNIX: + // the paths of the form "~" or "~username" are absolute + m_relative = leadingChar != wxT('/') && leadingChar != _T('~'); + break; + + case wxPATH_DOS: + m_relative = !IsPathSeparator(leadingChar, format); + break; + + } + + // 2) Break up the path into its members. If the original path + // was just "/" or "\\", m_dirs will be empty. We know from + // the m_relative field, if this means "nothing" or "root dir". + + wxStringTokenizer tn( path, GetPathSeparators(format) ); + + while ( tn.HasMoreTokens() ) + { + wxString token = tn.GetNextToken(); + + // Remove empty token under DOS and Unix, interpret them + // as .. under Mac. + if (token.empty()) + { + if (format == wxPATH_MAC) + m_dirs.Add( wxT("..") ); + // else ignore + } + else + { + m_dirs.Add( token ); + } + } +} + +void wxFileName::Assign(const wxString& fullpath, + wxPathFormat format) +{ + wxString volume, path, name, ext; + bool hasExt; + SplitPath(fullpath, &volume, &path, &name, &ext, &hasExt, format); + + Assign(volume, path, name, ext, hasExt, format); +} + +void wxFileName::Assign(const wxString& fullpathOrig, + const wxString& fullname, + wxPathFormat format) +{ + // always recognize fullpath as directory, even if it doesn't end with a + // slash + wxString fullpath = fullpathOrig; + if ( !fullpath.empty() && !wxEndsWithPathSeparator(fullpath) ) + { + fullpath += GetPathSeparator(format); + } + + wxString volume, path, name, ext; + bool hasExt; + + // do some consistency checks in debug mode: the name should be really just + // the filename and the path should be really just a path +#ifdef __WXDEBUG__ + wxString volDummy, pathDummy, nameDummy, extDummy; + + SplitPath(fullname, &volDummy, &pathDummy, &name, &ext, &hasExt, format); + + wxASSERT_MSG( volDummy.empty() && pathDummy.empty(), + _T("the file name shouldn't contain the path") ); + + SplitPath(fullpath, &volume, &path, &nameDummy, &extDummy, format); + + wxASSERT_MSG( nameDummy.empty() && extDummy.empty(), + _T("the path shouldn't contain file name nor extension") ); + +#else // !__WXDEBUG__ + SplitPath(fullname, NULL /* no volume */, NULL /* no path */, + &name, &ext, &hasExt, format); + SplitPath(fullpath, &volume, &path, NULL, NULL, format); +#endif // __WXDEBUG__/!__WXDEBUG__ + + Assign(volume, path, name, ext, hasExt, format); +} + +void wxFileName::Assign(const wxString& pathOrig, + const wxString& name, + const wxString& ext, + wxPathFormat format) +{ + wxString volume, + path; + SplitVolume(pathOrig, &volume, &path, format); + + Assign(volume, path, name, ext, format); +} + +void wxFileName::AssignDir(const wxString& dir, wxPathFormat format) +{ + Assign(dir, wxEmptyString, format); +} + +void wxFileName::Clear() +{ + m_dirs.Clear(); + + m_volume = + m_name = + m_ext = wxEmptyString; + + // we don't have any absolute path for now + m_relative = true; + + // nor any extension + m_hasExt = false; +} + +/* static */ +wxFileName wxFileName::FileName(const wxString& file, wxPathFormat format) +{ + return wxFileName(file, format); +} + +/* static */ +wxFileName wxFileName::DirName(const wxString& dir, wxPathFormat format) +{ + wxFileName fn; + fn.AssignDir(dir, format); + return fn; +} + +// ---------------------------------------------------------------------------- +// existence tests +// ---------------------------------------------------------------------------- + +bool wxFileName::FileExists() const +{ + return wxFileName::FileExists( GetFullPath() ); +} + +bool wxFileName::FileExists( const wxString &file ) +{ + return ::wxFileExists( file ); +} + +bool wxFileName::DirExists() const +{ + return wxFileName::DirExists( GetPath() ); +} + +bool wxFileName::DirExists( const wxString &dir ) +{ + return ::wxDirExists( dir ); +} + +// ---------------------------------------------------------------------------- +// CWD and HOME stuff +// ---------------------------------------------------------------------------- + +void wxFileName::AssignCwd(const wxString& volume) +{ + AssignDir(wxFileName::GetCwd(volume)); +} + +/* static */ +wxString wxFileName::GetCwd(const wxString& volume) +{ + // if we have the volume, we must get the current directory on this drive + // and to do this we have to chdir to this volume - at least under Windows, + // I don't know how to get the current drive on another volume elsewhere + // (TODO) + wxString cwdOld; + if ( !volume.empty() ) + { + cwdOld = wxGetCwd(); + SetCwd(volume + GetVolumeSeparator()); + } + + wxString cwd = ::wxGetCwd(); + + if ( !volume.empty() ) + { + SetCwd(cwdOld); + } + + return cwd; +} + +bool wxFileName::SetCwd() +{ + return wxFileName::SetCwd( GetPath() ); +} + +bool wxFileName::SetCwd( const wxString &cwd ) +{ + return ::wxSetWorkingDirectory( cwd ); +} + +void wxFileName::AssignHomeDir() +{ + AssignDir(wxFileName::GetHomeDir()); +} + +wxString wxFileName::GetHomeDir() +{ + return ::wxGetHomeDir(); +} + + +// ---------------------------------------------------------------------------- +// CreateTempFileName +// ---------------------------------------------------------------------------- + +#if wxUSE_FILE || wxUSE_FFILE + + +#if !defined wx_fdopen && defined HAVE_FDOPEN + #define wx_fdopen fdopen +#endif + +// NB: GetTempFileName() under Windows creates the file, so using +// O_EXCL there would fail +#ifdef __WINDOWS__ + #define wxOPEN_EXCL 0 +#else + #define wxOPEN_EXCL O_EXCL +#endif + + +#ifdef wxOpenOSFHandle +#define WX_HAVE_DELETE_ON_CLOSE +// On Windows create a file with the FILE_FLAGS_DELETE_ON_CLOSE flags. +// +static int wxOpenWithDeleteOnClose(const wxString& filename) +{ + DWORD access = GENERIC_READ | GENERIC_WRITE; + + DWORD disposition = OPEN_ALWAYS; + + DWORD attributes = FILE_ATTRIBUTE_TEMPORARY | + FILE_FLAG_DELETE_ON_CLOSE; + + HANDLE h = ::CreateFile(filename, access, 0, NULL, + disposition, attributes, NULL); + + return wxOpenOSFHandle(h, wxO_BINARY); +} +#endif // wxOpenOSFHandle + + +// Helper to open the file +// +static int wxTempOpen(const wxString& path, bool *deleteOnClose) +{ +#ifdef WX_HAVE_DELETE_ON_CLOSE + if (*deleteOnClose) + return wxOpenWithDeleteOnClose(path); +#endif + + *deleteOnClose = false; + + return wxOpen(path, wxO_BINARY | O_RDWR | O_CREAT | wxOPEN_EXCL, 0600); +} + + +#if wxUSE_FFILE +// Helper to open the file and attach it to the wxFFile +// +static bool wxTempOpen(wxFFile *file, const wxString& path, bool *deleteOnClose) +{ +#ifndef wx_fdopen + *deleteOnClose = false; + return file->Open(path, _T("w+b")); +#else // wx_fdopen + int fd = wxTempOpen(path, deleteOnClose); + if (fd == -1) + return false; + file->Attach(wx_fdopen(fd, "w+b")); + return file->IsOpened(); +#endif // wx_fdopen +} +#endif // wxUSE_FFILE + + +#if !wxUSE_FILE + #define WXFILEARGS(x, y) y +#elif !wxUSE_FFILE + #define WXFILEARGS(x, y) x +#else + #define WXFILEARGS(x, y) x, y +#endif + + +// Implementation of wxFileName::CreateTempFileName(). +// +static wxString wxCreateTempImpl( + const wxString& prefix, + WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp), + bool *deleteOnClose = NULL) +{ +#if wxUSE_FILE && wxUSE_FFILE + wxASSERT(fileTemp == NULL || ffileTemp == NULL); +#endif + wxString path, dir, name; + bool wantDeleteOnClose = false; + + if (deleteOnClose) + { + // set the result to false initially + wantDeleteOnClose = *deleteOnClose; + *deleteOnClose = false; + } + else + { + // easier if it alwasys points to something + deleteOnClose = &wantDeleteOnClose; + } + + // use the directory specified by the prefix + wxFileName::SplitPath(prefix, &dir, &name, NULL /* extension */); + + if (dir.empty()) + { + dir = wxFileName::GetTempDir(); + } + +#if defined(__WXWINCE__) + path = dir + wxT("\\") + name; + int i = 1; + while (wxFileName::FileExists(path)) + { + path = dir + wxT("\\") + name ; + path << i; + i ++; + } + +#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) + if ( !::GetTempFileName(dir, name, 0, wxStringBuffer(path, MAX_PATH + 1)) ) + { + wxLogLastError(_T("GetTempFileName")); + + path.clear(); + } + +#else // !Windows + path = dir; + + if ( !wxEndsWithPathSeparator(dir) && + (name.empty() || !wxIsPathSeparator(name[0u])) ) + { + path += wxFILE_SEP_PATH; + } + + path += name; + +#if defined(HAVE_MKSTEMP) + // scratch space for mkstemp() + path += _T("XXXXXX"); + + // we need to copy the path to the buffer in which mkstemp() can modify it + wxCharBuffer buf( wxConvFile.cWX2MB( path ) ); + + // cast is safe because the string length doesn't change + int fdTemp = mkstemp( (char*)(const char*) buf ); + if ( fdTemp == -1 ) + { + // this might be not necessary as mkstemp() on most systems should have + // already done it but it doesn't hurt neither... + path.clear(); + } + else // mkstemp() succeeded + { + path = wxConvFile.cMB2WX( (const char*) buf ); + + #if wxUSE_FILE + // avoid leaking the fd + if ( fileTemp ) + { + fileTemp->Attach(fdTemp); + } + else + #endif + + #if wxUSE_FFILE + if ( ffileTemp ) + { + #ifdef wx_fdopen + ffileTemp->Attach(wx_fdopen(fdTemp, "r+b")); + #else + ffileTemp->Open(path, _T("r+b")); + close(fdTemp); + #endif + } + else + #endif + + { + close(fdTemp); + } + } +#else // !HAVE_MKSTEMP + +#ifdef HAVE_MKTEMP + // same as above + path += _T("XXXXXX"); + + wxCharBuffer buf = wxConvFile.cWX2MB( path ); + if ( !mktemp( (char*)(const char*) buf ) ) + { + path.clear(); + } + else + { + path = wxConvFile.cMB2WX( (const char*) buf ); + } +#else // !HAVE_MKTEMP (includes __DOS__) + // generate the unique file name ourselves + #if !defined(__DOS__) && !defined(__PALMOS__) && (!defined(__MWERKS__) || defined(__DARWIN__) ) + path << (unsigned int)getpid(); + #endif + + wxString pathTry; + + static const size_t numTries = 1000; + for ( size_t n = 0; n < numTries; n++ ) + { + // 3 hex digits is enough for numTries == 1000 < 4096 + pathTry = path + wxString::Format(_T("%.03x"), (unsigned int) n); + if ( !wxFileName::FileExists(pathTry) ) + { + break; + } + + pathTry.clear(); + } + + path = pathTry; +#endif // HAVE_MKTEMP/!HAVE_MKTEMP + +#endif // HAVE_MKSTEMP/!HAVE_MKSTEMP + +#endif // Windows/!Windows + + if ( path.empty() ) + { + wxLogSysError(_("Failed to create a temporary file name")); + } + else + { + bool ok = true; + + // open the file - of course, there is a race condition here, this is + // why we always prefer using mkstemp()... + #if wxUSE_FILE + if ( fileTemp && !fileTemp->IsOpened() ) + { + *deleteOnClose = wantDeleteOnClose; + int fd = wxTempOpen(path, deleteOnClose); + if (fd != -1) + fileTemp->Attach(fd); + else + ok = false; + } + #endif + + #if wxUSE_FFILE + if ( ffileTemp && !ffileTemp->IsOpened() ) + { + *deleteOnClose = wantDeleteOnClose; + ok = wxTempOpen(ffileTemp, path, deleteOnClose); + } + #endif + + if ( !ok ) + { + // FIXME: If !ok here should we loop and try again with another + // file name? That is the standard recourse if open(O_EXCL) + // fails, though of course it should be protected against + // possible infinite looping too. + + wxLogError(_("Failed to open temporary file.")); + + path.clear(); + } + } + + return path; +} + + +static bool wxCreateTempImpl( + const wxString& prefix, + WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp), + wxString *name) +{ + bool deleteOnClose = true; + + *name = wxCreateTempImpl(prefix, + WXFILEARGS(fileTemp, ffileTemp), + &deleteOnClose); + + bool ok = !name->empty(); + + if (deleteOnClose) + name->clear(); +#ifdef __UNIX__ + else if (ok && wxRemoveFile(*name)) + name->clear(); +#endif + + return ok; +} + + +static void wxAssignTempImpl( + wxFileName *fn, + const wxString& prefix, + WXFILEARGS(wxFile *fileTemp, wxFFile *ffileTemp)) +{ + wxString tempname; + tempname = wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, ffileTemp)); + + if ( tempname.empty() ) + { + // error, failed to get temp file name + fn->Clear(); + } + else // ok + { + fn->Assign(tempname); + } +} + + +void wxFileName::AssignTempFileName(const wxString& prefix) +{ + wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, NULL)); +} + +/* static */ +wxString wxFileName::CreateTempFileName(const wxString& prefix) +{ + return wxCreateTempImpl(prefix, WXFILEARGS(NULL, NULL)); +} + +#endif // wxUSE_FILE || wxUSE_FFILE + + +#if wxUSE_FILE + +wxString wxCreateTempFileName(const wxString& prefix, + wxFile *fileTemp, + bool *deleteOnClose) +{ + return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), deleteOnClose); +} + +bool wxCreateTempFile(const wxString& prefix, + wxFile *fileTemp, + wxString *name) +{ + return wxCreateTempImpl(prefix, WXFILEARGS(fileTemp, NULL), name); +} + +void wxFileName::AssignTempFileName(const wxString& prefix, wxFile *fileTemp) +{ + wxAssignTempImpl(this, prefix, WXFILEARGS(fileTemp, NULL)); +} + +/* static */ +wxString +wxFileName::CreateTempFileName(const wxString& prefix, wxFile *fileTemp) +{ + return wxCreateTempFileName(prefix, fileTemp); +} + +#endif // wxUSE_FILE + + +#if wxUSE_FFILE + +wxString wxCreateTempFileName(const wxString& prefix, + wxFFile *fileTemp, + bool *deleteOnClose) +{ + return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), deleteOnClose); +} + +bool wxCreateTempFile(const wxString& prefix, + wxFFile *fileTemp, + wxString *name) +{ + return wxCreateTempImpl(prefix, WXFILEARGS(NULL, fileTemp), name); + +} + +void wxFileName::AssignTempFileName(const wxString& prefix, wxFFile *fileTemp) +{ + wxAssignTempImpl(this, prefix, WXFILEARGS(NULL, fileTemp)); +} + +/* static */ +wxString +wxFileName::CreateTempFileName(const wxString& prefix, wxFFile *fileTemp) +{ + return wxCreateTempFileName(prefix, fileTemp); +} + +#endif // wxUSE_FFILE + + +// ---------------------------------------------------------------------------- +// directory operations +// ---------------------------------------------------------------------------- + +wxString wxFileName::GetTempDir() +{ + wxString dir; + dir = wxGetenv(_T("TMPDIR")); + if (dir.empty()) + { + dir = wxGetenv(_T("TMP")); + if (dir.empty()) + { + dir = wxGetenv(_T("TEMP")); + } + } + +#if defined(__WXWINCE__) + if (dir.empty()) + { + // FIXME. Create \temp dir? + if (DirExists(wxT("\\temp"))) + dir = wxT("\\temp"); + } +#elif defined(__WINDOWS__) && !defined(__WXMICROWIN__) + + if ( dir.empty() ) + { + if ( !::GetTempPath(MAX_PATH, wxStringBuffer(dir, MAX_PATH + 1)) ) + { + wxLogLastError(_T("GetTempPath")); + } + + if ( dir.empty() ) + { + // GetTempFileName() fails if we pass it an empty string + dir = _T('.'); + } + } +#else // !Windows + + if ( dir.empty() ) + { + // default +#if defined(__DOS__) || defined(__OS2__) + dir = _T("."); +#elif defined(__WXMAC__) + dir = wxMacFindFolder(short(kOnSystemDisk), kTemporaryFolderType, kCreateFolder); +#else + dir = _T("/tmp"); +#endif + } +#endif + + return dir; +} + +bool wxFileName::Mkdir( int perm, int flags ) +{ + return wxFileName::Mkdir(GetPath(), perm, flags); +} + +bool wxFileName::Mkdir( const wxString& dir, int perm, int flags ) +{ + if ( flags & wxPATH_MKDIR_FULL ) + { + // split the path in components + wxFileName filename; + filename.AssignDir(dir); + + wxString currPath; + if ( filename.HasVolume()) + { + currPath << wxGetVolumeString(filename.GetVolume(), wxPATH_NATIVE); + } + + wxArrayString dirs = filename.GetDirs(); + size_t count = dirs.GetCount(); + for ( size_t i = 0; i < count; i++ ) + { + if ( i > 0 || +#if defined(__WXMAC__) && !defined(__DARWIN__) + // relative pathnames are exactely the other way round under mac... + !filename.IsAbsolute() +#else + filename.IsAbsolute() +#endif + ) + currPath += wxFILE_SEP_PATH; + currPath += dirs[i]; + + if (!DirExists(currPath)) + { + if (!wxMkdir(currPath, perm)) + { + // no need to try creating further directories + return false; + } + } + } + + return true; + + } + + return ::wxMkdir( dir, perm ); +} + +bool wxFileName::Rmdir() +{ + return wxFileName::Rmdir( GetPath() ); +} + +bool wxFileName::Rmdir( const wxString &dir ) +{ + return ::wxRmdir( dir ); +} + +// ---------------------------------------------------------------------------- +// path normalization +// ---------------------------------------------------------------------------- + +bool wxFileName::Normalize(int flags, + const wxString& cwd, + wxPathFormat format) +{ + // deal with env vars renaming first as this may seriously change the path + if ( flags & wxPATH_NORM_ENV_VARS ) + { + wxString pathOrig = GetFullPath(format); + wxString path = wxExpandEnvVars(pathOrig); + if ( path != pathOrig ) + { + Assign(path); + } + } + + + // the existing path components + wxArrayString dirs = GetDirs(); + + // the path to prepend in front to make the path absolute + wxFileName curDir; + + format = GetFormat(format); + + // set up the directory to use for making the path absolute later + if ( (flags & wxPATH_NORM_ABSOLUTE) && !IsAbsolute(format) ) + { + if ( cwd.empty() ) + { + curDir.AssignCwd(GetVolume()); + } + else // cwd provided + { + curDir.AssignDir(cwd); + } + } + + // handle ~ stuff under Unix only + if ( (format == wxPATH_UNIX) && (flags & wxPATH_NORM_TILDE) ) + { + if ( !dirs.IsEmpty() ) + { + wxString dir = dirs[0u]; + if ( !dir.empty() && dir[0u] == _T('~') ) + { + // to make the path absolute use the home directory + curDir.AssignDir(wxGetUserHome(dir.c_str() + 1)); + + // if we are expanding the tilde, then this path + // *should* be already relative (since we checked for + // the tilde only in the first char of the first dir); + // if m_relative==false, it's because it was initialized + // from a string which started with /~; in that case + // we reach this point but then need m_relative=true + // for relative->absolute expansion later + m_relative = true; + + dirs.RemoveAt(0u); + } + } + } + + // transform relative path into abs one + if ( curDir.IsOk() ) + { + // this path may be relative because it doesn't have the volume name + // and still have m_relative=true; in this case we shouldn't modify + // our directory components but just set the current volume + if ( !HasVolume() && curDir.HasVolume() ) + { + SetVolume(curDir.GetVolume()); + + if ( !m_relative ) + { + // yes, it was the case - we don't need curDir then + curDir.Clear(); + } + } + + // finally, prepend curDir to the dirs array + wxArrayString dirsNew = curDir.GetDirs(); + WX_PREPEND_ARRAY(dirs, dirsNew); + + // if we used e.g. tilde expansion previously and wxGetUserHome didn't + // return for some reason an absolute path, then curDir maybe not be absolute! + if ( curDir.IsAbsolute(format) ) + { + // we have prepended an absolute path and thus we are now an absolute + // file name too + m_relative = false; + } + // else if (flags & wxPATH_NORM_ABSOLUTE): + // should we warn the user that we didn't manage to make the path absolute? + } + + // now deal with ".", ".." and the rest + m_dirs.Empty(); + size_t count = dirs.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + wxString dir = dirs[n]; + + if ( flags & wxPATH_NORM_DOTS ) + { + if ( dir == wxT(".") ) + { + // just ignore + continue; + } + + if ( dir == wxT("..") ) + { + if ( m_dirs.IsEmpty() ) + { + wxLogError(_("The path '%s' contains too many \"..\"!"), + GetFullPath().c_str()); + return false; + } + + m_dirs.RemoveAt(m_dirs.GetCount() - 1); + continue; + } + } + + m_dirs.Add(dir); + } + +#if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE + if ( (flags & wxPATH_NORM_SHORTCUT) ) + { + wxString filename; + if (GetShortcutTarget(GetFullPath(format), filename)) + { + m_relative = false; + Assign(filename); + } + } +#endif + +#if defined(__WIN32__) + if ( (flags & wxPATH_NORM_LONG) && (format == wxPATH_DOS) ) + { + Assign(GetLongPath()); + } +#endif // Win32 + + // Change case (this should be kept at the end of the function, to ensure + // that the path doesn't change any more after we normalize its case) + if ( (flags & wxPATH_NORM_CASE) && !IsCaseSensitive(format) ) + { + m_volume.MakeLower(); + m_name.MakeLower(); + m_ext.MakeLower(); + + // directory entries must be made lower case as well + count = m_dirs.GetCount(); + for ( size_t i = 0; i < count; i++ ) + { + m_dirs[i].MakeLower(); + } + } + + return true; +} + +// ---------------------------------------------------------------------------- +// get the shortcut target +// ---------------------------------------------------------------------------- + +// WinCE (3) doesn't have CLSID_ShellLink, IID_IShellLink definitions. +// The .lnk file is a plain text file so it should be easy to +// make it work. Hint from Google Groups: +// "If you open up a lnk file, you'll see a +// number, followed by a pound sign (#), followed by more text. The +// number is the number of characters that follows the pound sign. The +// characters after the pound sign are the command line (which _can_ +// include arguments) to be executed. Any path (e.g. \windows\program +// files\myapp.exe) that includes spaces needs to be enclosed in +// quotation marks." + +#if defined(__WIN32__) && !defined(__WXWINCE__) && wxUSE_OLE +// The following lines are necessary under WinCE +// #include "wx/msw/private.h" +// #include +#include +#if defined(__WXWINCE__) +#include +#endif + +bool wxFileName::GetShortcutTarget(const wxString& shortcutPath, + wxString& targetFilename, + wxString* arguments) +{ + wxString path, file, ext; + wxSplitPath(shortcutPath, & path, & file, & ext); + + HRESULT hres; + IShellLink* psl; + bool success = false; + + // Assume it's not a shortcut if it doesn't end with lnk + if (ext.CmpNoCase(wxT("lnk"))!=0) + return false; + + // create a ShellLink object + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, + IID_IShellLink, (LPVOID*) &psl); + + if (SUCCEEDED(hres)) + { + IPersistFile* ppf; + hres = psl->QueryInterface( IID_IPersistFile, (LPVOID *) &ppf); + if (SUCCEEDED(hres)) + { + WCHAR wsz[MAX_PATH]; + + MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, shortcutPath.mb_str(), -1, wsz, + MAX_PATH); + + hres = ppf->Load(wsz, 0); + ppf->Release(); + + if (SUCCEEDED(hres)) + { + wxChar buf[2048]; + // Wrong prototype in early versions +#if defined(__MINGW32__) && !wxCHECK_W32API_VERSION(2, 2) + psl->GetPath((CHAR*) buf, 2048, NULL, SLGP_UNCPRIORITY); +#else + psl->GetPath(buf, 2048, NULL, SLGP_UNCPRIORITY); +#endif + targetFilename = wxString(buf); + success = (shortcutPath != targetFilename); + + psl->GetArguments(buf, 2048); + wxString args(buf); + if (!args.empty() && arguments) + { + *arguments = args; + } + } + } + + psl->Release(); + } + return success; +} + +#endif // __WIN32__ && !__WXWINCE__ + + +// ---------------------------------------------------------------------------- +// absolute/relative paths +// ---------------------------------------------------------------------------- + +bool wxFileName::IsAbsolute(wxPathFormat format) const +{ + // if our path doesn't start with a path separator, it's not an absolute + // path + if ( m_relative ) + return false; + + if ( !GetVolumeSeparator(format).empty() ) + { + // this format has volumes and an absolute path must have one, it's not + // enough to have the full path to bean absolute file under Windows + if ( GetVolume().empty() ) + return false; + } + + return true; +} + +bool wxFileName::MakeRelativeTo(const wxString& pathBase, wxPathFormat format) +{ + wxFileName fnBase = wxFileName::DirName(pathBase, format); + + // get cwd only once - small time saving + wxString cwd = wxGetCwd(); + Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format); + fnBase.Normalize(wxPATH_NORM_ALL & ~wxPATH_NORM_CASE, cwd, format); + + bool withCase = IsCaseSensitive(format); + + // we can't do anything if the files live on different volumes + if ( !GetVolume().IsSameAs(fnBase.GetVolume(), withCase) ) + { + // nothing done + return false; + } + + // same drive, so we don't need our volume + m_volume.clear(); + + // remove common directories starting at the top + while ( !m_dirs.IsEmpty() && !fnBase.m_dirs.IsEmpty() && + m_dirs[0u].IsSameAs(fnBase.m_dirs[0u], withCase) ) + { + m_dirs.RemoveAt(0); + fnBase.m_dirs.RemoveAt(0); + } + + // add as many ".." as needed + size_t count = fnBase.m_dirs.GetCount(); + for ( size_t i = 0; i < count; i++ ) + { + m_dirs.Insert(wxT(".."), 0u); + } + + if ( format == wxPATH_UNIX || format == wxPATH_DOS ) + { + // a directory made relative with respect to itself is '.' under Unix + // and DOS, by definition (but we don't have to insert "./" for the + // files) + if ( m_dirs.IsEmpty() && IsDir() ) + { + m_dirs.Add(_T('.')); + } + } + + m_relative = true; + + // we were modified + return true; +} + +// ---------------------------------------------------------------------------- +// filename kind tests +// ---------------------------------------------------------------------------- + +bool wxFileName::SameAs(const wxFileName& filepath, wxPathFormat format) const +{ + wxFileName fn1 = *this, + fn2 = filepath; + + // get cwd only once - small time saving + wxString cwd = wxGetCwd(); + fn1.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format); + fn2.Normalize(wxPATH_NORM_ALL | wxPATH_NORM_CASE, cwd, format); + + if ( fn1.GetFullPath() == fn2.GetFullPath() ) + return true; + + // TODO: compare inodes for Unix, this works even when filenames are + // different but files are the same (symlinks) (VZ) + + return false; +} + +/* static */ +bool wxFileName::IsCaseSensitive( wxPathFormat format ) +{ + // only Unix filenames are truely case-sensitive + return GetFormat(format) == wxPATH_UNIX; +} + +/* static */ +wxString wxFileName::GetForbiddenChars(wxPathFormat format) +{ + // Inits to forbidden characters that are common to (almost) all platforms. + wxString strForbiddenChars = wxT("*?"); + + // If asserts, wxPathFormat has been changed. In case of a new path format + // addition, the following code might have to be updated. + wxCOMPILE_TIME_ASSERT(wxPATH_MAX == 5, wxPathFormatChanged); + switch ( GetFormat(format) ) + { + default : + wxFAIL_MSG( wxT("Unknown path format") ); + // !! Fall through !! + + case wxPATH_UNIX: + break; + + case wxPATH_MAC: + // On a Mac even names with * and ? are allowed (Tested with OS + // 9.2.1 and OS X 10.2.5) + strForbiddenChars = wxEmptyString; + break; + + case wxPATH_DOS: + strForbiddenChars += wxT("\\/:\"<>|"); + break; + + case wxPATH_VMS: + break; + } + + return strForbiddenChars; +} + +/* static */ +wxString wxFileName::GetVolumeSeparator(wxPathFormat WXUNUSED_IN_WINCE(format)) +{ +#ifdef __WXWINCE__ + return wxEmptyString; +#else + wxString sepVol; + + if ( (GetFormat(format) == wxPATH_DOS) || + (GetFormat(format) == wxPATH_VMS) ) + { + sepVol = wxFILE_SEP_DSK; + } + //else: leave empty + + return sepVol; +#endif +} + +/* static */ +wxString wxFileName::GetPathSeparators(wxPathFormat format) +{ + wxString seps; + switch ( GetFormat(format) ) + { + case wxPATH_DOS: + // accept both as native APIs do but put the native one first as + // this is the one we use in GetFullPath() + seps << wxFILE_SEP_PATH_DOS << wxFILE_SEP_PATH_UNIX; + break; + + default: + wxFAIL_MSG( _T("Unknown wxPATH_XXX style") ); + // fall through + + case wxPATH_UNIX: + seps = wxFILE_SEP_PATH_UNIX; + break; + + case wxPATH_MAC: + seps = wxFILE_SEP_PATH_MAC; + break; + + case wxPATH_VMS: + seps = wxFILE_SEP_PATH_VMS; + break; + } + + return seps; +} + +/* static */ +wxString wxFileName::GetPathTerminators(wxPathFormat format) +{ + format = GetFormat(format); + + // under VMS the end of the path is ']', not the path separator used to + // separate the components + return format == wxPATH_VMS ? wxString(_T(']')) : GetPathSeparators(format); +} + +/* static */ +bool wxFileName::IsPathSeparator(wxChar ch, wxPathFormat format) +{ + // wxString::Find() doesn't work as expected with NUL - it will always find + // it, so test for it separately + return ch != _T('\0') && GetPathSeparators(format).Find(ch) != wxNOT_FOUND; +} + +// ---------------------------------------------------------------------------- +// path components manipulation +// ---------------------------------------------------------------------------- + +/* static */ bool wxFileName::IsValidDirComponent(const wxString& dir) +{ + if ( dir.empty() ) + { + wxFAIL_MSG( _T("empty directory passed to wxFileName::InsertDir()") ); + + return false; + } + + const size_t len = dir.length(); + for ( size_t n = 0; n < len; n++ ) + { + if ( dir[n] == GetVolumeSeparator() || IsPathSeparator(dir[n]) ) + { + wxFAIL_MSG( _T("invalid directory component in wxFileName") ); + + return false; + } + } + + return true; +} + +void wxFileName::AppendDir( const wxString& dir ) +{ + if ( IsValidDirComponent(dir) ) + m_dirs.Add( dir ); +} + +void wxFileName::PrependDir( const wxString& dir ) +{ + InsertDir(0, dir); +} + +void wxFileName::InsertDir(size_t before, const wxString& dir) +{ + if ( IsValidDirComponent(dir) ) + m_dirs.Insert(dir, before); +} + +void wxFileName::RemoveDir(size_t pos) +{ + m_dirs.RemoveAt(pos); +} + +// ---------------------------------------------------------------------------- +// accessors +// ---------------------------------------------------------------------------- + +void wxFileName::SetFullName(const wxString& fullname) +{ + SplitPath(fullname, NULL /* no volume */, NULL /* no path */, + &m_name, &m_ext, &m_hasExt); +} + +wxString wxFileName::GetFullName() const +{ + wxString fullname = m_name; + if ( m_hasExt ) + { + fullname << wxFILE_SEP_EXT << m_ext; + } + + return fullname; +} + +wxString wxFileName::GetPath( int flags, wxPathFormat format ) const +{ + format = GetFormat( format ); + + wxString fullpath; + + // return the volume with the path as well if requested + if ( flags & wxPATH_GET_VOLUME ) + { + fullpath += wxGetVolumeString(GetVolume(), format); + } + + // the leading character + switch ( format ) + { + case wxPATH_MAC: + if ( m_relative ) + fullpath += wxFILE_SEP_PATH_MAC; + break; + + case wxPATH_DOS: + if ( !m_relative ) + fullpath += wxFILE_SEP_PATH_DOS; + break; + + default: + wxFAIL_MSG( wxT("Unknown path format") ); + // fall through + + case wxPATH_UNIX: + if ( !m_relative ) + { + // normally the absolute file names start with a slash + // with one exception: the ones like "~/foo.bar" don't + // have it + if ( m_dirs.IsEmpty() || m_dirs[0u] != _T('~') ) + { + fullpath += wxFILE_SEP_PATH_UNIX; + } + } + break; + + case wxPATH_VMS: + // no leading character here but use this place to unset + // wxPATH_GET_SEPARATOR flag: under VMS it doesn't make sense + // as, if I understand correctly, there should never be a dot + // before the closing bracket + flags &= ~wxPATH_GET_SEPARATOR; + } + + if ( m_dirs.empty() ) + { + // there is nothing more + return fullpath; + } + + // then concatenate all the path components using the path separator + if ( format == wxPATH_VMS ) + { + fullpath += wxT('['); + } + + const size_t dirCount = m_dirs.GetCount(); + for ( size_t i = 0; i < dirCount; i++ ) + { + switch (format) + { + case wxPATH_MAC: + if ( m_dirs[i] == wxT(".") ) + { + // skip appending ':', this shouldn't be done in this + // case as "::" is interpreted as ".." under Unix + continue; + } + + // convert back from ".." to nothing + if ( !m_dirs[i].IsSameAs(wxT("..")) ) + fullpath += m_dirs[i]; + break; + + default: + wxFAIL_MSG( wxT("Unexpected path format") ); + // still fall through + + case wxPATH_DOS: + case wxPATH_UNIX: + fullpath += m_dirs[i]; + break; + + case wxPATH_VMS: + // TODO: What to do with ".." under VMS + + // convert back from ".." to nothing + if ( !m_dirs[i].IsSameAs(wxT("..")) ) + fullpath += m_dirs[i]; + break; + } + + if ( (flags & wxPATH_GET_SEPARATOR) || (i != dirCount - 1) ) + fullpath += GetPathSeparator(format); + } + + if ( format == wxPATH_VMS ) + { + fullpath += wxT(']'); + } + + return fullpath; +} + +wxString wxFileName::GetFullPath( wxPathFormat format ) const +{ + // we already have a function to get the path + wxString fullpath = GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR, + format); + + // now just add the file name and extension to it + fullpath += GetFullName(); + + return fullpath; +} + +// Return the short form of the path (returns identity on non-Windows platforms) +wxString wxFileName::GetShortPath() const +{ + wxString path(GetFullPath()); + +#if defined(__WXMSW__) && defined(__WIN32__) && !defined(__WXMICROWIN__) && !defined(__WXWINCE__) + DWORD sz = ::GetShortPathName(path, NULL, 0); + if ( sz != 0 ) + { + wxString pathOut; + if ( ::GetShortPathName + ( + path, + wxStringBuffer(pathOut, sz), + sz + ) != 0 ) + { + return pathOut; + } + } +#endif // Windows + + return path; +} + +// Return the long form of the path (returns identity on non-Windows platforms) +wxString wxFileName::GetLongPath() const +{ + wxString pathOut, + path = GetFullPath(); + +#if defined(__WIN32__) && !defined(__WXWINCE__) && !defined(__WXMICROWIN__) + +#if wxUSE_DYNLIB_CLASS + typedef DWORD (WINAPI *GET_LONG_PATH_NAME)(const wxChar *, wxChar *, DWORD); + + // this is MT-safe as in the worst case we're going to resolve the function + // twice -- but as the result is the same in both threads, it's ok + static GET_LONG_PATH_NAME s_pfnGetLongPathName = NULL; + if ( !s_pfnGetLongPathName ) + { + static bool s_triedToLoad = false; + + if ( !s_triedToLoad ) + { + s_triedToLoad = true; + + wxDynamicLibrary dllKernel(_T("kernel32")); + + const wxChar* GetLongPathName = _T("GetLongPathName") +#if wxUSE_UNICODE + _T("W"); +#else // ANSI + _T("A"); +#endif // Unicode/ANSI + + if ( dllKernel.HasSymbol(GetLongPathName) ) + { + s_pfnGetLongPathName = (GET_LONG_PATH_NAME) + dllKernel.GetSymbol(GetLongPathName); + } + + // note that kernel32.dll can be unloaded, it stays in memory + // anyhow as all Win32 programs link to it and so it's safe to call + // GetLongPathName() even after unloading it + } + } + + if ( s_pfnGetLongPathName ) + { + DWORD dwSize = (*s_pfnGetLongPathName)(path, NULL, 0); + if ( dwSize > 0 ) + { + if ( (*s_pfnGetLongPathName) + ( + path, + wxStringBuffer(pathOut, dwSize), + dwSize + ) != 0 ) + { + return pathOut; + } + } + } +#endif // wxUSE_DYNLIB_CLASS + + // The OS didn't support GetLongPathName, or some other error. + // We need to call FindFirstFile on each component in turn. + + WIN32_FIND_DATA findFileData; + HANDLE hFind; + + if ( HasVolume() ) + pathOut = GetVolume() + + GetVolumeSeparator(wxPATH_DOS) + + GetPathSeparator(wxPATH_DOS); + else + pathOut = wxEmptyString; + + wxArrayString dirs = GetDirs(); + dirs.Add(GetFullName()); + + wxString tmpPath; + + size_t count = dirs.GetCount(); + for ( size_t i = 0; i < count; i++ ) + { + // We're using pathOut to collect the long-name path, but using a + // temporary for appending the last path component which may be + // short-name + tmpPath = pathOut + dirs[i]; + + if ( tmpPath.empty() ) + continue; + + // can't see this being necessary? MF + if ( tmpPath.Last() == GetVolumeSeparator(wxPATH_DOS) ) + { + // Can't pass a drive and root dir to FindFirstFile, + // so continue to next dir + tmpPath += wxFILE_SEP_PATH; + pathOut = tmpPath; + continue; + } + + hFind = ::FindFirstFile(tmpPath, &findFileData); + if (hFind == INVALID_HANDLE_VALUE) + { + // Error: most likely reason is that path doesn't exist, so + // append any unprocessed parts and return + for ( i += 1; i < count; i++ ) + tmpPath += wxFILE_SEP_PATH + dirs[i]; + + return tmpPath; + } + + pathOut += findFileData.cFileName; + if ( (i < (count-1)) ) + pathOut += wxFILE_SEP_PATH; + + ::FindClose(hFind); + } +#else // !Win32 + pathOut = path; +#endif // Win32/!Win32 + + return pathOut; +} + +wxPathFormat wxFileName::GetFormat( wxPathFormat format ) +{ + if (format == wxPATH_NATIVE) + { +#if defined(__WXMSW__) || defined(__OS2__) || defined(__DOS__) + format = wxPATH_DOS; +#elif defined(__WXMAC__) && !defined(__DARWIN__) + format = wxPATH_MAC; +#elif defined(__VMS) + format = wxPATH_VMS; +#else + format = wxPATH_UNIX; +#endif + } + return format; +} + +// ---------------------------------------------------------------------------- +// path splitting function +// ---------------------------------------------------------------------------- + +/* static */ +void +wxFileName::SplitVolume(const wxString& fullpathWithVolume, + wxString *pstrVolume, + wxString *pstrPath, + wxPathFormat format) +{ + format = GetFormat(format); + + wxString fullpath = fullpathWithVolume; + + // special Windows UNC paths hack: transform \\share\path into share:path + if ( IsUNCPath(fullpath, format) ) + { + fullpath.erase(0, 2); + + size_t posFirstSlash = + fullpath.find_first_of(GetPathTerminators(format)); + if ( posFirstSlash != wxString::npos ) + { + fullpath[posFirstSlash] = wxFILE_SEP_DSK; + + // UNC paths are always absolute, right? (FIXME) + fullpath.insert(posFirstSlash + 1, 1, wxFILE_SEP_PATH_DOS); + } + } + + // We separate the volume here + if ( format == wxPATH_DOS || format == wxPATH_VMS ) + { + wxString sepVol = GetVolumeSeparator(format); + + size_t posFirstColon = fullpath.find_first_of(sepVol); + if ( posFirstColon != wxString::npos ) + { + if ( pstrVolume ) + { + *pstrVolume = fullpath.Left(posFirstColon); + } + + // remove the volume name and the separator from the full path + fullpath.erase(0, posFirstColon + sepVol.length()); + } + } + + if ( pstrPath ) + *pstrPath = fullpath; +} + +/* static */ +void wxFileName::SplitPath(const wxString& fullpathWithVolume, + wxString *pstrVolume, + wxString *pstrPath, + wxString *pstrName, + wxString *pstrExt, + bool *hasExt, + wxPathFormat format) +{ + format = GetFormat(format); + + wxString fullpath; + SplitVolume(fullpathWithVolume, pstrVolume, &fullpath, format); + + // find the positions of the last dot and last path separator in the path + size_t posLastDot = fullpath.find_last_of(wxFILE_SEP_EXT); + size_t posLastSlash = fullpath.find_last_of(GetPathTerminators(format)); + + // check whether this dot occurs at the very beginning of a path component + if ( (posLastDot != wxString::npos) && + (posLastDot == 0 || + IsPathSeparator(fullpath[posLastDot - 1]) || + (format == wxPATH_VMS && fullpath[posLastDot - 1] == _T(']'))) ) + { + // dot may be (and commonly -- at least under Unix -- is) the first + // character of the filename, don't treat the entire filename as + // extension in this case + posLastDot = wxString::npos; + } + + // if we do have a dot and a slash, check that the dot is in the name part + if ( (posLastDot != wxString::npos) && + (posLastSlash != wxString::npos) && + (posLastDot < posLastSlash) ) + { + // the dot is part of the path, not the start of the extension + posLastDot = wxString::npos; + } + + // now fill in the variables provided by user + if ( pstrPath ) + { + if ( posLastSlash == wxString::npos ) + { + // no path at all + pstrPath->Empty(); + } + else + { + // take everything up to the path separator but take care to make + // the path equal to something like '/', not empty, for the files + // immediately under root directory + size_t len = posLastSlash; + + // this rule does not apply to mac since we do not start with colons (sep) + // except for relative paths + if ( !len && format != wxPATH_MAC) + len++; + + *pstrPath = fullpath.Left(len); + + // special VMS hack: remove the initial bracket + if ( format == wxPATH_VMS ) + { + if ( (*pstrPath)[0u] == _T('[') ) + pstrPath->erase(0, 1); + } + } + } + + if ( pstrName ) + { + // take all characters starting from the one after the last slash and + // up to, but excluding, the last dot + size_t nStart = posLastSlash == wxString::npos ? 0 : posLastSlash + 1; + size_t count; + if ( posLastDot == wxString::npos ) + { + // take all until the end + count = wxString::npos; + } + else if ( posLastSlash == wxString::npos ) + { + count = posLastDot; + } + else // have both dot and slash + { + count = posLastDot - posLastSlash - 1; + } + + *pstrName = fullpath.Mid(nStart, count); + } + + // finally deal with the extension here: we have an added complication that + // extension may be empty (but present) as in "foo." where trailing dot + // indicates the empty extension at the end -- and hence we must remember + // that we have it independently of pstrExt + if ( posLastDot == wxString::npos ) + { + // no extension + if ( pstrExt ) + pstrExt->clear(); + if ( hasExt ) + *hasExt = false; + } + else + { + // take everything after the dot + if ( pstrExt ) + *pstrExt = fullpath.Mid(posLastDot + 1); + if ( hasExt ) + *hasExt = true; + } +} + +/* static */ +void wxFileName::SplitPath(const wxString& fullpath, + wxString *path, + wxString *name, + wxString *ext, + wxPathFormat format) +{ + wxString volume; + SplitPath(fullpath, &volume, path, name, ext, format); + + if ( path ) + { + path->Prepend(wxGetVolumeString(volume, format)); + } +} + +/* static */ +wxString wxFileName::StripExtension(const wxString& fullpath) +{ + wxFileName fn(fullpath); + fn.SetExt(_T("")); + return fn.GetFullPath(); +} + +// ---------------------------------------------------------------------------- +// time functions +// ---------------------------------------------------------------------------- + +#if wxUSE_DATETIME + +bool wxFileName::SetTimes(const wxDateTime *dtAccess, + const wxDateTime *dtMod, + const wxDateTime *dtCreate) +{ +#if defined(__WIN32__) + FILETIME ftAccess, ftCreate, ftWrite; + + if ( dtCreate ) + ConvertWxToFileTime(&ftCreate, *dtCreate); + if ( dtAccess ) + ConvertWxToFileTime(&ftAccess, *dtAccess); + if ( dtMod ) + ConvertWxToFileTime(&ftWrite, *dtMod); + + wxString path; + int flags; + if ( IsDir() ) + { + if ( wxGetOsVersion() == wxOS_WINDOWS_9X ) + { + wxLogError(_("Setting directory access times is not supported under this OS version")); + return false; + } + + path = GetPath(); + flags = FILE_FLAG_BACKUP_SEMANTICS; + } + else // file + { + path = GetFullPath(); + flags = 0; + } + + wxFileHandle fh(path, wxFileHandle::Write, flags); + if ( fh.IsOk() ) + { + if ( ::SetFileTime(fh, + dtCreate ? &ftCreate : NULL, + dtAccess ? &ftAccess : NULL, + dtMod ? &ftWrite : NULL) ) + { + return true; + } + } +#elif defined(__UNIX_LIKE__) || (defined(__DOS__) && defined(__WATCOMC__)) + wxUnusedVar(dtCreate); + + if ( !dtAccess && !dtMod ) + { + // can't modify the creation time anyhow, don't try + return true; + } + + // if dtAccess or dtMod is not specified, use the other one (which must be + // non NULL because of the test above) for both times + utimbuf utm; + utm.actime = dtAccess ? dtAccess->GetTicks() : dtMod->GetTicks(); + utm.modtime = dtMod ? dtMod->GetTicks() : dtAccess->GetTicks(); + if ( utime(GetFullPath().fn_str(), &utm) == 0 ) + { + return true; + } +#else // other platform + wxUnusedVar(dtAccess); + wxUnusedVar(dtMod); + wxUnusedVar(dtCreate); +#endif // platforms + + wxLogSysError(_("Failed to modify file times for '%s'"), + GetFullPath().c_str()); + + return false; +} + +bool wxFileName::Touch() +{ +#if defined(__UNIX_LIKE__) + // under Unix touching file is simple: just pass NULL to utime() + if ( utime(GetFullPath().fn_str(), NULL) == 0 ) + { + return true; + } + + wxLogSysError(_("Failed to touch the file '%s'"), GetFullPath().c_str()); + + return false; +#else // other platform + wxDateTime dtNow = wxDateTime::Now(); + + return SetTimes(&dtNow, &dtNow, NULL /* don't change create time */); +#endif // platforms +} + +#ifdef wxNEED_WX_UNISTD_H + +static int wxStat( const char *file_name, wxStructStat *buf ) +{ + return stat( file_name , buf ); +} + +#endif + +bool wxFileName::GetTimes(wxDateTime *dtAccess, + wxDateTime *dtMod, + wxDateTime *dtCreate) const +{ +#if defined(__WIN32__) + // we must use different methods for the files and directories under + // Windows as CreateFile(GENERIC_READ) doesn't work for the directories and + // CreateFile(FILE_FLAG_BACKUP_SEMANTICS) works -- but only under NT and + // not 9x + bool ok; + FILETIME ftAccess, ftCreate, ftWrite; + if ( IsDir() ) + { + // implemented in msw/dir.cpp + extern bool wxGetDirectoryTimes(const wxString& dirname, + FILETIME *, FILETIME *, FILETIME *); + + // we should pass the path without the trailing separator to + // wxGetDirectoryTimes() + ok = wxGetDirectoryTimes(GetPath(wxPATH_GET_VOLUME), + &ftAccess, &ftCreate, &ftWrite); + } + else // file + { + wxFileHandle fh(GetFullPath(), wxFileHandle::Read); + if ( fh.IsOk() ) + { + ok = ::GetFileTime(fh, + dtCreate ? &ftCreate : NULL, + dtAccess ? &ftAccess : NULL, + dtMod ? &ftWrite : NULL) != 0; + } + else + { + ok = false; + } + } + + if ( ok ) + { + if ( dtCreate ) + ConvertFileTimeToWx(dtCreate, ftCreate); + if ( dtAccess ) + ConvertFileTimeToWx(dtAccess, ftAccess); + if ( dtMod ) + ConvertFileTimeToWx(dtMod, ftWrite); + + return true; + } +#elif defined(__UNIX_LIKE__) || defined(__WXMAC__) || defined(__OS2__) || (defined(__DOS__) && defined(__WATCOMC__)) + // no need to test for IsDir() here + wxStructStat stBuf; + if ( wxStat( GetFullPath().fn_str(), &stBuf) == 0 ) + { + if ( dtAccess ) + dtAccess->Set(stBuf.st_atime); + if ( dtMod ) + dtMod->Set(stBuf.st_mtime); + if ( dtCreate ) + dtCreate->Set(stBuf.st_ctime); + + return true; + } +#else // other platform + wxUnusedVar(dtAccess); + wxUnusedVar(dtMod); + wxUnusedVar(dtCreate); +#endif // platforms + + wxLogSysError(_("Failed to retrieve file times for '%s'"), + GetFullPath().c_str()); + + return false; +} + +#endif // wxUSE_DATETIME + + +// ---------------------------------------------------------------------------- +// file size functions +// ---------------------------------------------------------------------------- + +/* static */ +wxULongLong wxFileName::GetSize(const wxString &filename) +{ + if (!wxFileExists(filename)) + return wxInvalidSize; + +#if defined(__WXPALMOS__) + // TODO + return wxInvalidSize; +#elif defined(__WIN32__) + wxFileHandle f(filename, wxFileHandle::Read); + if (!f.IsOk()) + return wxInvalidSize; + + DWORD lpFileSizeHigh; + DWORD ret = GetFileSize(f, &lpFileSizeHigh); + if ( ret == INVALID_FILE_SIZE && ::GetLastError() != NO_ERROR ) + return wxInvalidSize; + + return wxULongLong(lpFileSizeHigh, ret); +#else // ! __WIN32__ + wxStructStat st; +#ifndef wxNEED_WX_UNISTD_H + if (wxStat( filename.fn_str() , &st) != 0) +#else + if (wxStat( filename, &st) != 0) +#endif + return wxInvalidSize; + return wxULongLong(st.st_size); +#endif +} + +/* static */ +wxString wxFileName::GetHumanReadableSize(const wxULongLong &bs, + const wxString &nullsize, + int precision) +{ + static const double KILOBYTESIZE = 1024.0; + static const double MEGABYTESIZE = 1024.0*KILOBYTESIZE; + static const double GIGABYTESIZE = 1024.0*MEGABYTESIZE; + static const double TERABYTESIZE = 1024.0*GIGABYTESIZE; + + if (bs == 0 || bs == wxInvalidSize) + return nullsize; + + double bytesize = bs.ToDouble(); + if (bytesize < KILOBYTESIZE) + return wxString::Format(_("%s B"), bs.ToString().c_str()); + if (bytesize < MEGABYTESIZE) + return wxString::Format(_("%.*f kB"), precision, bytesize/KILOBYTESIZE); + if (bytesize < GIGABYTESIZE) + return wxString::Format(_("%.*f MB"), precision, bytesize/MEGABYTESIZE); + if (bytesize < TERABYTESIZE) + return wxString::Format(_("%.*f GB"), precision, bytesize/GIGABYTESIZE); + + return wxString::Format(_("%.*f TB"), precision, bytesize/TERABYTESIZE); +} + +wxULongLong wxFileName::GetSize() const +{ + return GetSize(GetFullPath()); +} + +wxString wxFileName::GetHumanReadableSize(const wxString &failmsg, int precision) const +{ + return GetHumanReadableSize(GetSize(), failmsg, precision); +} + + +// ---------------------------------------------------------------------------- +// Mac-specific functions +// ---------------------------------------------------------------------------- + +#ifdef __WXMAC__ + +const short kMacExtensionMaxLength = 16 ; +class MacDefaultExtensionRecord +{ +public : + MacDefaultExtensionRecord() + { + m_ext[0] = 0 ; + m_type = m_creator = 0 ; + } + MacDefaultExtensionRecord( const MacDefaultExtensionRecord& from ) + { + wxStrcpy( m_ext , from.m_ext ) ; + m_type = from.m_type ; + m_creator = from.m_creator ; + } + MacDefaultExtensionRecord( const wxChar * extension , OSType type , OSType creator ) + { + wxStrncpy( m_ext , extension , kMacExtensionMaxLength ) ; + m_ext[kMacExtensionMaxLength] = 0 ; + m_type = type ; + m_creator = creator ; + } + wxChar m_ext[kMacExtensionMaxLength] ; + OSType m_type ; + OSType m_creator ; +} ; + +WX_DECLARE_OBJARRAY(MacDefaultExtensionRecord, MacDefaultExtensionArray) ; + +bool gMacDefaultExtensionsInited = false ; + +#include "wx/arrimpl.cpp" + +WX_DEFINE_EXPORTED_OBJARRAY(MacDefaultExtensionArray) ; + +MacDefaultExtensionArray gMacDefaultExtensions ; + +// load the default extensions +MacDefaultExtensionRecord gDefaults[] = +{ + MacDefaultExtensionRecord( wxT("txt") , 'TEXT' , 'ttxt' ) , + MacDefaultExtensionRecord( wxT("tif") , 'TIFF' , '****' ) , + MacDefaultExtensionRecord( wxT("jpg") , 'JPEG' , '****' ) , +} ; + +static void MacEnsureDefaultExtensionsLoaded() +{ + if ( !gMacDefaultExtensionsInited ) + { + // we could load the pc exchange prefs here too + for ( size_t i = 0 ; i < WXSIZEOF( gDefaults ) ; ++i ) + { + gMacDefaultExtensions.Add( gDefaults[i] ) ; + } + gMacDefaultExtensionsInited = true ; + } +} + +bool wxFileName::MacSetTypeAndCreator( wxUint32 type , wxUint32 creator ) +{ + FSRef fsRef ; + FSCatalogInfo catInfo; + FileInfo *finfo ; + + if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr ) + { + if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr ) + { + finfo = (FileInfo*)&catInfo.finderInfo; + finfo->fileType = type ; + finfo->fileCreator = creator ; + FSSetCatalogInfo( &fsRef, kFSCatInfoFinderInfo, &catInfo ) ; + return true ; + } + } + return false ; +} + +bool wxFileName::MacGetTypeAndCreator( wxUint32 *type , wxUint32 *creator ) +{ + FSRef fsRef ; + FSCatalogInfo catInfo; + FileInfo *finfo ; + + if ( wxMacPathToFSRef( GetFullPath() , &fsRef ) == noErr ) + { + if ( FSGetCatalogInfo (&fsRef, kFSCatInfoFinderInfo, &catInfo, NULL, NULL, NULL) == noErr ) + { + finfo = (FileInfo*)&catInfo.finderInfo; + *type = finfo->fileType ; + *creator = finfo->fileCreator ; + return true ; + } + } + return false ; +} + +bool wxFileName::MacSetDefaultTypeAndCreator() +{ + wxUint32 type , creator ; + if ( wxFileName::MacFindDefaultTypeAndCreator(GetExt() , &type , + &creator ) ) + { + return MacSetTypeAndCreator( type , creator ) ; + } + return false; +} + +bool wxFileName::MacFindDefaultTypeAndCreator( const wxString& ext , wxUint32 *type , wxUint32 *creator ) +{ + MacEnsureDefaultExtensionsLoaded() ; + wxString extl = ext.Lower() ; + for( int i = gMacDefaultExtensions.Count() - 1 ; i >= 0 ; --i ) + { + if ( gMacDefaultExtensions.Item(i).m_ext == extl ) + { + *type = gMacDefaultExtensions.Item(i).m_type ; + *creator = gMacDefaultExtensions.Item(i).m_creator ; + return true ; + } + } + return false ; +} + +void wxFileName::MacRegisterDefaultTypeAndCreator( const wxString& ext , wxUint32 type , wxUint32 creator ) +{ + MacEnsureDefaultExtensionsLoaded() ; + MacDefaultExtensionRecord rec ; + rec.m_type = type ; + rec.m_creator = creator ; + wxStrncpy( rec.m_ext , ext.Lower().c_str() , kMacExtensionMaxLength ) ; + gMacDefaultExtensions.Add( rec ) ; +} +#endif diff --git a/Source/3rd Party/wx/src/common/filepickercmn.cpp b/Source/3rd Party/wx/src/common/filepickercmn.cpp index 87def3dfc..7b805dc8f 100644 --- a/Source/3rd Party/wx/src/common/filepickercmn.cpp +++ b/Source/3rd Party/wx/src/common/filepickercmn.cpp @@ -1,224 +1,224 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/filepickercmn.cpp -// Purpose: wxFilePickerCtrl class implementation -// Author: Francesco Montorsi (readapted code written by Vadim Zeitlin) -// Modified by: -// Created: 15/04/2006 -// RCS-ID: $Id: filepickercmn.cpp 42219 2006-10-21 19:53:05Z PC $ -// Copyright: (c) Vadim Zeitlin, Francesco Montorsi -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FILEPICKERCTRL || wxUSE_DIRPICKERCTRL - -#include "wx/filepicker.h" -#include "wx/filename.h" - -#ifndef WX_PRECOMP - #include "wx/textctrl.h" -#endif - -// ============================================================================ -// implementation -// ============================================================================ - -const wxChar wxFilePickerCtrlNameStr[] = wxT("filepicker"); -const wxChar wxFilePickerWidgetNameStr[] = wxT("filepickerwidget"); -const wxChar wxDirPickerCtrlNameStr[] = wxT("dirpicker"); -const wxChar wxDirPickerWidgetNameStr[] = wxT("dirpickerwidget"); -const wxChar wxFilePickerWidgetLabel[] = wxT("Browse"); -const wxChar wxDirPickerWidgetLabel[] = wxT("Browse"); - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_FILEPICKER_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_DIRPICKER_CHANGED) -IMPLEMENT_DYNAMIC_CLASS(wxFileDirPickerEvent, wxCommandEvent) - -// ---------------------------------------------------------------------------- -// wxFileDirPickerCtrlBase -// ---------------------------------------------------------------------------- - -bool wxFileDirPickerCtrlBase::CreateBase(wxWindow *parent, - wxWindowID id, - const wxString &path, - const wxString &message, - const wxString &wildcard, - const wxPoint &pos, - const wxSize &size, - long style, - const wxValidator& validator, - const wxString &name ) -{ - wxASSERT_MSG(path.empty() || CheckPath(path), wxT("Invalid initial path!")); - - if (!wxPickerBase::CreateBase(parent, id, path, pos, size, - style, validator, name)) - return false; - - if (!HasFlag(wxFLP_OPEN) && !HasFlag(wxFLP_SAVE)) - m_windowStyle |= wxFLP_OPEN; // wxFD_OPEN is the default - - // check that the styles are not contradictory - wxASSERT_MSG( !(HasFlag(wxFLP_SAVE) && HasFlag(wxFLP_OPEN)), - _T("can't specify both wxFLP_SAVE and wxFLP_OPEN at once") ); - - wxASSERT_MSG( !HasFlag(wxFLP_SAVE) || !HasFlag(wxFLP_FILE_MUST_EXIST), - _T("wxFLP_FILE_MUST_EXIST can't be used with wxFLP_SAVE" ) ); - - wxASSERT_MSG( !HasFlag(wxFLP_OPEN) || !HasFlag(wxFLP_OVERWRITE_PROMPT), - _T("wxFLP_OVERWRITE_PROMPT can't be used with wxFLP_OPEN") ); - - // create a wxFilePickerWidget or a wxDirPickerWidget... - m_pickerIface = CreatePicker(this, path, message, wildcard); - if ( !m_pickerIface ) - return false; - m_picker = m_pickerIface->AsControl(); - - // complete sizer creation - wxPickerBase::PostCreation(); - - m_picker->Connect(GetEventType(), - wxFileDirPickerEventHandler(wxFileDirPickerCtrlBase::OnFileDirChange), - NULL, this); - - // default's wxPickerBase textctrl limit is too small for this control: - // make it bigger - if (m_text) m_text->SetMaxLength(512); - - return true; -} - -wxString wxFileDirPickerCtrlBase::GetPath() const -{ - return m_pickerIface->GetPath(); -} - -void wxFileDirPickerCtrlBase::SetPath(const wxString &path) -{ - m_pickerIface->SetPath(path); - UpdateTextCtrlFromPicker(); -} - -void wxFileDirPickerCtrlBase::UpdatePickerFromTextCtrl() -{ - wxASSERT(m_text); - - if (m_bIgnoreNextTextCtrlUpdate) - { - // ignore this update - m_bIgnoreNextTextCtrlUpdate = false; - return; - } - - // remove the eventually present path-separator from the end of the textctrl - // string otherwise we would generate a wxFileDirPickerEvent when changing - // from e.g. /home/user to /home/user/ and we want to avoid it ! - wxString newpath(GetTextCtrlValue()); - if (!CheckPath(newpath)) - return; // invalid user input - - if (m_pickerIface->GetPath() != newpath) - { - m_pickerIface->SetPath(newpath); - - // update current working directory, if necessary - // NOTE: the path separator is required because if newpath is "C:" - // then no change would happen - if (IsCwdToUpdate()) - wxSetWorkingDirectory(newpath); - - // fire an event - wxFileDirPickerEvent event(GetEventType(), this, GetId(), newpath); - GetEventHandler()->ProcessEvent(event); - } -} - -void wxFileDirPickerCtrlBase::UpdateTextCtrlFromPicker() -{ - if (!m_text) - return; // no textctrl to update - - // NOTE: this SetValue() will generate an unwanted wxEVT_COMMAND_TEXT_UPDATED - // which will trigger a unneeded UpdateFromTextCtrl(); thus before using - // SetValue() we set the m_bIgnoreNextTextCtrlUpdate flag... - m_bIgnoreNextTextCtrlUpdate = true; - m_text->SetValue(m_pickerIface->GetPath()); -} - - - -// ---------------------------------------------------------------------------- -// wxFileDirPickerCtrlBase - event handlers -// ---------------------------------------------------------------------------- - -void wxFileDirPickerCtrlBase::OnFileDirChange(wxFileDirPickerEvent &ev) -{ - UpdateTextCtrlFromPicker(); - - // the wxFilePickerWidget sent us a colour-change notification. - // forward this event to our parent - wxFileDirPickerEvent event(GetEventType(), this, GetId(), ev.GetPath()); - GetEventHandler()->ProcessEvent(event); -} - -#endif // wxUSE_FILEPICKERCTRL || wxUSE_DIRPICKERCTRL - -// ---------------------------------------------------------------------------- -// wxFileDirPickerCtrl -// ---------------------------------------------------------------------------- - -#if wxUSE_FILEPICKERCTRL - -IMPLEMENT_DYNAMIC_CLASS(wxFilePickerCtrl, wxPickerBase) - -bool wxFilePickerCtrl::CheckPath(const wxString& path) const -{ - // if wxFLP_SAVE was given or wxFLP_FILE_MUST_EXIST has NOT been given we - // must accept any path - return HasFlag(wxFLP_SAVE) || - !HasFlag(wxFLP_FILE_MUST_EXIST) || - wxFileName::FileExists(path); -} - -wxString wxFilePickerCtrl::GetTextCtrlValue() const -{ - // filter it through wxFileName to remove any spurious path separator - return wxFileName(m_text->GetValue()).GetFullPath(); -} - -#endif // wxUSE_FILEPICKERCTRL - -// ---------------------------------------------------------------------------- -// wxDirPickerCtrl -// ---------------------------------------------------------------------------- - -#if wxUSE_DIRPICKERCTRL -IMPLEMENT_DYNAMIC_CLASS(wxDirPickerCtrl, wxPickerBase) - -bool wxDirPickerCtrl::CheckPath(const wxString& path) const -{ - // if wxDIRP_DIR_MUST_EXIST has NOT been given we must accept any path - return !HasFlag(wxDIRP_DIR_MUST_EXIST) || wxFileName::DirExists(path); -} - -wxString wxDirPickerCtrl::GetTextCtrlValue() const -{ - // filter it through wxFileName to remove any spurious path separator - return wxFileName::DirName(m_text->GetValue()).GetPath(); -} - -#endif // wxUSE_DIRPICKERCTRL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/filepickercmn.cpp +// Purpose: wxFilePickerCtrl class implementation +// Author: Francesco Montorsi (readapted code written by Vadim Zeitlin) +// Modified by: +// Created: 15/04/2006 +// RCS-ID: $Id: filepickercmn.cpp 42219 2006-10-21 19:53:05Z PC $ +// Copyright: (c) Vadim Zeitlin, Francesco Montorsi +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FILEPICKERCTRL || wxUSE_DIRPICKERCTRL + +#include "wx/filepicker.h" +#include "wx/filename.h" + +#ifndef WX_PRECOMP + #include "wx/textctrl.h" +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +const wxChar wxFilePickerCtrlNameStr[] = wxT("filepicker"); +const wxChar wxFilePickerWidgetNameStr[] = wxT("filepickerwidget"); +const wxChar wxDirPickerCtrlNameStr[] = wxT("dirpicker"); +const wxChar wxDirPickerWidgetNameStr[] = wxT("dirpickerwidget"); +const wxChar wxFilePickerWidgetLabel[] = wxT("Browse"); +const wxChar wxDirPickerWidgetLabel[] = wxT("Browse"); + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_FILEPICKER_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_DIRPICKER_CHANGED) +IMPLEMENT_DYNAMIC_CLASS(wxFileDirPickerEvent, wxCommandEvent) + +// ---------------------------------------------------------------------------- +// wxFileDirPickerCtrlBase +// ---------------------------------------------------------------------------- + +bool wxFileDirPickerCtrlBase::CreateBase(wxWindow *parent, + wxWindowID id, + const wxString &path, + const wxString &message, + const wxString &wildcard, + const wxPoint &pos, + const wxSize &size, + long style, + const wxValidator& validator, + const wxString &name ) +{ + wxASSERT_MSG(path.empty() || CheckPath(path), wxT("Invalid initial path!")); + + if (!wxPickerBase::CreateBase(parent, id, path, pos, size, + style, validator, name)) + return false; + + if (!HasFlag(wxFLP_OPEN) && !HasFlag(wxFLP_SAVE)) + m_windowStyle |= wxFLP_OPEN; // wxFD_OPEN is the default + + // check that the styles are not contradictory + wxASSERT_MSG( !(HasFlag(wxFLP_SAVE) && HasFlag(wxFLP_OPEN)), + _T("can't specify both wxFLP_SAVE and wxFLP_OPEN at once") ); + + wxASSERT_MSG( !HasFlag(wxFLP_SAVE) || !HasFlag(wxFLP_FILE_MUST_EXIST), + _T("wxFLP_FILE_MUST_EXIST can't be used with wxFLP_SAVE" ) ); + + wxASSERT_MSG( !HasFlag(wxFLP_OPEN) || !HasFlag(wxFLP_OVERWRITE_PROMPT), + _T("wxFLP_OVERWRITE_PROMPT can't be used with wxFLP_OPEN") ); + + // create a wxFilePickerWidget or a wxDirPickerWidget... + m_pickerIface = CreatePicker(this, path, message, wildcard); + if ( !m_pickerIface ) + return false; + m_picker = m_pickerIface->AsControl(); + + // complete sizer creation + wxPickerBase::PostCreation(); + + m_picker->Connect(GetEventType(), + wxFileDirPickerEventHandler(wxFileDirPickerCtrlBase::OnFileDirChange), + NULL, this); + + // default's wxPickerBase textctrl limit is too small for this control: + // make it bigger + if (m_text) m_text->SetMaxLength(512); + + return true; +} + +wxString wxFileDirPickerCtrlBase::GetPath() const +{ + return m_pickerIface->GetPath(); +} + +void wxFileDirPickerCtrlBase::SetPath(const wxString &path) +{ + m_pickerIface->SetPath(path); + UpdateTextCtrlFromPicker(); +} + +void wxFileDirPickerCtrlBase::UpdatePickerFromTextCtrl() +{ + wxASSERT(m_text); + + if (m_bIgnoreNextTextCtrlUpdate) + { + // ignore this update + m_bIgnoreNextTextCtrlUpdate = false; + return; + } + + // remove the eventually present path-separator from the end of the textctrl + // string otherwise we would generate a wxFileDirPickerEvent when changing + // from e.g. /home/user to /home/user/ and we want to avoid it ! + wxString newpath(GetTextCtrlValue()); + if (!CheckPath(newpath)) + return; // invalid user input + + if (m_pickerIface->GetPath() != newpath) + { + m_pickerIface->SetPath(newpath); + + // update current working directory, if necessary + // NOTE: the path separator is required because if newpath is "C:" + // then no change would happen + if (IsCwdToUpdate()) + wxSetWorkingDirectory(newpath); + + // fire an event + wxFileDirPickerEvent event(GetEventType(), this, GetId(), newpath); + GetEventHandler()->ProcessEvent(event); + } +} + +void wxFileDirPickerCtrlBase::UpdateTextCtrlFromPicker() +{ + if (!m_text) + return; // no textctrl to update + + // NOTE: this SetValue() will generate an unwanted wxEVT_COMMAND_TEXT_UPDATED + // which will trigger a unneeded UpdateFromTextCtrl(); thus before using + // SetValue() we set the m_bIgnoreNextTextCtrlUpdate flag... + m_bIgnoreNextTextCtrlUpdate = true; + m_text->SetValue(m_pickerIface->GetPath()); +} + + + +// ---------------------------------------------------------------------------- +// wxFileDirPickerCtrlBase - event handlers +// ---------------------------------------------------------------------------- + +void wxFileDirPickerCtrlBase::OnFileDirChange(wxFileDirPickerEvent &ev) +{ + UpdateTextCtrlFromPicker(); + + // the wxFilePickerWidget sent us a colour-change notification. + // forward this event to our parent + wxFileDirPickerEvent event(GetEventType(), this, GetId(), ev.GetPath()); + GetEventHandler()->ProcessEvent(event); +} + +#endif // wxUSE_FILEPICKERCTRL || wxUSE_DIRPICKERCTRL + +// ---------------------------------------------------------------------------- +// wxFileDirPickerCtrl +// ---------------------------------------------------------------------------- + +#if wxUSE_FILEPICKERCTRL + +IMPLEMENT_DYNAMIC_CLASS(wxFilePickerCtrl, wxPickerBase) + +bool wxFilePickerCtrl::CheckPath(const wxString& path) const +{ + // if wxFLP_SAVE was given or wxFLP_FILE_MUST_EXIST has NOT been given we + // must accept any path + return HasFlag(wxFLP_SAVE) || + !HasFlag(wxFLP_FILE_MUST_EXIST) || + wxFileName::FileExists(path); +} + +wxString wxFilePickerCtrl::GetTextCtrlValue() const +{ + // filter it through wxFileName to remove any spurious path separator + return wxFileName(m_text->GetValue()).GetFullPath(); +} + +#endif // wxUSE_FILEPICKERCTRL + +// ---------------------------------------------------------------------------- +// wxDirPickerCtrl +// ---------------------------------------------------------------------------- + +#if wxUSE_DIRPICKERCTRL +IMPLEMENT_DYNAMIC_CLASS(wxDirPickerCtrl, wxPickerBase) + +bool wxDirPickerCtrl::CheckPath(const wxString& path) const +{ + // if wxDIRP_DIR_MUST_EXIST has NOT been given we must accept any path + return !HasFlag(wxDIRP_DIR_MUST_EXIST) || wxFileName::DirExists(path); +} + +wxString wxDirPickerCtrl::GetTextCtrlValue() const +{ + // filter it through wxFileName to remove any spurious path separator + return wxFileName::DirName(m_text->GetValue()).GetPath(); +} + +#endif // wxUSE_DIRPICKERCTRL diff --git a/Source/3rd Party/wx/src/common/filesys.cpp b/Source/3rd Party/wx/src/common/filesys.cpp index 65ea14117..0f850bcf6 100644 --- a/Source/3rd Party/wx/src/common/filesys.cpp +++ b/Source/3rd Party/wx/src/common/filesys.cpp @@ -1,700 +1,700 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/filesys.cpp -// Purpose: wxFileSystem class - interface for opening files -// Author: Vaclav Slavik -// Copyright: (c) 1999 Vaclav Slavik -// CVS-ID: $Id: filesys.cpp 55271 2008-08-26 00:03:04Z VZ $ -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - - -#if wxUSE_FILESYSTEM - -#include "wx/filesys.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/module.h" -#endif - -#include "wx/sysopt.h" -#include "wx/wfstream.h" -#include "wx/mimetype.h" -#include "wx/filename.h" -#include "wx/tokenzr.h" -#include "wx/uri.h" -#include "wx/private/fileback.h" - - -//-------------------------------------------------------------------------------- -// wxFileSystemHandler -//-------------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxFileSystemHandler, wxObject) - - -wxString wxFileSystemHandler::GetMimeTypeFromExt(const wxString& location) -{ - wxString ext, mime; - wxString loc = GetRightLocation(location); - wxChar c; - int l = loc.length(), l2; - - l2 = l; - for (int i = l-1; i >= 0; i--) - { - c = loc[(unsigned int) i]; - if ( c == wxT('#') ) - l2 = i + 1; - if ( c == wxT('.') ) - { - ext = loc.Right(l2-i-1); - break; - } - if ( (c == wxT('/')) || (c == wxT('\\')) || (c == wxT(':')) ) - return wxEmptyString; - } - -#if wxUSE_MIMETYPE - static bool s_MinimalMimeEnsured = false; - - // Don't use mime types manager if the application doesn't need it and it would be - // cause an unacceptable delay, especially on startup. - bool useMimeTypesManager = true; -#if wxUSE_SYSTEM_OPTIONS - useMimeTypesManager = (wxSystemOptions::GetOptionInt(wxT("filesys.no-mimetypesmanager")) == 0); -#endif - - if (useMimeTypesManager) - { - if (!s_MinimalMimeEnsured) - { - static const wxFileTypeInfo fallbacks[] = - { - wxFileTypeInfo(_T("image/jpeg"), - wxEmptyString, - wxEmptyString, - _T("JPEG image (from fallback)"), - _T("jpg"), _T("jpeg"), _T("JPG"), _T("JPEG"), NULL), - wxFileTypeInfo(_T("image/gif"), - wxEmptyString, - wxEmptyString, - _T("GIF image (from fallback)"), - _T("gif"), _T("GIF"), NULL), - wxFileTypeInfo(_T("image/png"), - wxEmptyString, - wxEmptyString, - _T("PNG image (from fallback)"), - _T("png"), _T("PNG"), NULL), - wxFileTypeInfo(_T("image/bmp"), - wxEmptyString, - wxEmptyString, - _T("windows bitmap image (from fallback)"), - _T("bmp"), _T("BMP"), NULL), - wxFileTypeInfo(_T("text/html"), - wxEmptyString, - wxEmptyString, - _T("HTML document (from fallback)"), - _T("htm"), _T("html"), _T("HTM"), _T("HTML"), NULL), - // must terminate the table with this! - wxFileTypeInfo() - }; - wxTheMimeTypesManager->AddFallbacks(fallbacks); - s_MinimalMimeEnsured = true; - } - - wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext); - if ( !ft || !ft -> GetMimeType(&mime) ) - { - mime = wxEmptyString; - } - - delete ft; - - return mime; - } - else -#endif - { - if ( ext.IsSameAs(wxT("htm"), false) || ext.IsSameAs(_T("html"), false) ) - return wxT("text/html"); - if ( ext.IsSameAs(wxT("jpg"), false) || ext.IsSameAs(_T("jpeg"), false) ) - return wxT("image/jpeg"); - if ( ext.IsSameAs(wxT("gif"), false) ) - return wxT("image/gif"); - if ( ext.IsSameAs(wxT("png"), false) ) - return wxT("image/png"); - if ( ext.IsSameAs(wxT("bmp"), false) ) - return wxT("image/bmp"); - return wxEmptyString; - } -} - - - -wxString wxFileSystemHandler::GetProtocol(const wxString& location) const -{ - wxString s = wxEmptyString; - int i, l = location.length(); - bool fnd = false; - - for (i = l-1; (i >= 0) && ((location[i] != wxT('#')) || (!fnd)); i--) { - if ((location[i] == wxT(':')) && (i != 1 /*win: C:\path*/)) fnd = true; - } - if (!fnd) return wxT("file"); - for (++i; (i < l) && (location[i] != wxT(':')); i++) s << location[i]; - return s; -} - - -wxString wxFileSystemHandler::GetLeftLocation(const wxString& location) const -{ - int i; - bool fnd = false; - - for (i = location.length()-1; i >= 0; i--) { - if ((location[i] == wxT(':')) && (i != 1 /*win: C:\path*/)) fnd = true; - else if (fnd && (location[i] == wxT('#'))) return location.Left(i); - } - return wxEmptyString; -} - -wxString wxFileSystemHandler::GetRightLocation(const wxString& location) const -{ - int i, l = location.length(); - int l2 = l + 1; - - for (i = l-1; - (i >= 0) && - ((location[i] != wxT(':')) || (i == 1) || (location[i-2] == wxT(':'))); - i--) - { - if (location[i] == wxT('#')) l2 = i + 1; - } - if (i == 0) return wxEmptyString; - else return location.Mid(i + 1, l2 - i - 2); -} - -wxString wxFileSystemHandler::GetAnchor(const wxString& location) const -{ - wxChar c; - int l = location.length(); - - for (int i = l-1; i >= 0; i--) { - c = location[i]; - if (c == wxT('#')) - return location.Right(l-i-1); - else if ((c == wxT('/')) || (c == wxT('\\')) || (c == wxT(':'))) - return wxEmptyString; - } - return wxEmptyString; -} - - -wxString wxFileSystemHandler::FindFirst(const wxString& WXUNUSED(spec), - int WXUNUSED(flags)) -{ - return wxEmptyString; -} - -wxString wxFileSystemHandler::FindNext() -{ - return wxEmptyString; -} - -//-------------------------------------------------------------------------------- -// wxLocalFSHandler -//-------------------------------------------------------------------------------- - - -wxString wxLocalFSHandler::ms_root; - -bool wxLocalFSHandler::CanOpen(const wxString& location) -{ - return GetProtocol(location) == wxT("file"); -} - -wxFSFile* wxLocalFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location) -{ - // location has Unix path separators - wxString right = GetRightLocation(location); - wxFileName fn = wxFileSystem::URLToFileName(right); - wxString fullpath = ms_root + fn.GetFullPath(); - - if (!wxFileExists(fullpath)) - return (wxFSFile*) NULL; - - // we need to check whether we can really read from this file, otherwise - // wxFSFile is not going to work -#if wxUSE_FFILE - wxFFileInputStream *is = new wxFFileInputStream(fullpath); -#elif wxUSE_FILE - wxFileInputStream *is = new wxFileInputStream(fullpath); -#else -#error One of wxUSE_FILE or wxUSE_FFILE must be set to 1 for wxFSHandler to work -#endif - if ( !is->Ok() ) - { - delete is; - return (wxFSFile*) NULL; - } - - return new wxFSFile(is, - right, - GetMimeTypeFromExt(location), - GetAnchor(location) -#if wxUSE_DATETIME - ,wxDateTime(wxFileModificationTime(fullpath)) -#endif // wxUSE_DATETIME - ); -} - -wxString wxLocalFSHandler::FindFirst(const wxString& spec, int flags) -{ - wxFileName fn = wxFileSystem::URLToFileName(GetRightLocation(spec)); - return wxFindFirstFile(ms_root + fn.GetFullPath(), flags); -} - -wxString wxLocalFSHandler::FindNext() -{ - return wxFindNextFile(); -} - - - -//----------------------------------------------------------------------------- -// wxFileSystem -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxFileSystem, wxObject) -IMPLEMENT_ABSTRACT_CLASS(wxFSFile, wxObject) - - -wxList wxFileSystem::m_Handlers; - - -wxFileSystem::~wxFileSystem() -{ - WX_CLEAR_HASH_MAP(wxFSHandlerHash, m_LocalHandlers) -} - - -static wxString MakeCorrectPath(const wxString& path) -{ - wxString p(path); - wxString r; - int i, j, cnt; - - cnt = p.length(); - for (i = 0; i < cnt; i++) - if (p.GetChar(i) == wxT('\\')) p.GetWritableChar(i) = wxT('/'); // Want to be windows-safe - - if (p.Left(2) == wxT("./")) { p = p.Mid(2); cnt -= 2; } - - if (cnt < 3) return p; - - r << p.GetChar(0) << p.GetChar(1); - - // skip trailing ../.., if any - for (i = 2; i < cnt && (p.GetChar(i) == wxT('/') || p.GetChar(i) == wxT('.')); i++) r << p.GetChar(i); - - // remove back references: translate dir1/../dir2 to dir2 - for (; i < cnt; i++) - { - r << p.GetChar(i); - if (p.GetChar(i) == wxT('/') && p.GetChar(i-1) == wxT('.') && p.GetChar(i-2) == wxT('.')) - { - for (j = r.length() - 2; j >= 0 && r.GetChar(j) != wxT('/') && r.GetChar(j) != wxT(':'); j--) {} - if (j >= 0 && r.GetChar(j) != wxT(':')) - { - for (j = j - 1; j >= 0 && r.GetChar(j) != wxT('/') && r.GetChar(j) != wxT(':'); j--) {} - r.Remove(j + 1); - } - } - } - - for (; i < cnt; i++) r << p.GetChar(i); - - return r; -} - - -void wxFileSystem::ChangePathTo(const wxString& location, bool is_dir) -{ - int i, pathpos = -1; - - m_Path = MakeCorrectPath(location); - - if (is_dir) - { - if (m_Path.length() > 0 && m_Path.Last() != wxT('/') && m_Path.Last() != wxT(':')) - m_Path << wxT('/'); - } - - else - { - for (i = m_Path.length()-1; i >= 0; i--) - { - if (m_Path[(unsigned int) i] == wxT('/')) - { - if ((i > 1) && (m_Path[(unsigned int) (i-1)] == wxT('/')) && (m_Path[(unsigned int) (i-2)] == wxT(':'))) - { - i -= 2; - continue; - } - else - { - pathpos = i; - break; - } - } - else if (m_Path[(unsigned int) i] == wxT(':')) { - pathpos = i; - break; - } - } - if (pathpos == -1) - { - for (i = 0; i < (int) m_Path.length(); i++) - { - if (m_Path[(unsigned int) i] == wxT(':')) - { - m_Path.Remove(i+1); - break; - } - } - if (i == (int) m_Path.length()) - m_Path = wxEmptyString; - } - else - { - m_Path.Remove(pathpos+1); - } - } -} - - - -wxFileSystemHandler *wxFileSystem::MakeLocal(wxFileSystemHandler *h) -{ - wxClassInfo *classinfo = h->GetClassInfo(); - - if (classinfo->IsDynamic()) - { - wxFileSystemHandler*& local = m_LocalHandlers[classinfo]; - if (!local) - local = (wxFileSystemHandler*)classinfo->CreateObject(); - return local; - } - else - { - return h; - } -} - - - -wxFSFile* wxFileSystem::OpenFile(const wxString& location, int flags) -{ - if ((flags & wxFS_READ) == 0) - return NULL; - - wxString loc = MakeCorrectPath(location); - unsigned i, ln; - wxChar meta; - wxFSFile *s = NULL; - wxList::compatibility_iterator node; - - ln = loc.length(); - meta = 0; - for (i = 0; i < ln; i++) - { - switch (loc[i]) - { - case wxT('/') : case wxT(':') : case wxT('#') : - meta = loc[i]; - break; - } - if (meta != 0) break; - } - m_LastName = wxEmptyString; - - // try relative paths first : - if (meta != wxT(':')) - { - node = m_Handlers.GetFirst(); - while (node) - { - wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); - if (h->CanOpen(m_Path + loc)) - { - s = MakeLocal(h)->OpenFile(*this, m_Path + loc); - if (s) { m_LastName = m_Path + loc; break; } - } - node = node->GetNext(); - } - } - - // if failed, try absolute paths : - if (s == NULL) - { - node = m_Handlers.GetFirst(); - while (node) - { - wxFileSystemHandler *h = (wxFileSystemHandler*) node->GetData(); - if (h->CanOpen(loc)) - { - s = MakeLocal(h)->OpenFile(*this, loc); - if (s) { m_LastName = loc; break; } - } - node = node->GetNext(); - } - } - - if (s && (flags & wxFS_SEEKABLE) != 0 && !s->GetStream()->IsSeekable()) - { - wxBackedInputStream *stream; - stream = new wxBackedInputStream(s->DetachStream()); - stream->FindLength(); - s->SetStream(stream); - } - - return (s); -} - - - -wxString wxFileSystem::FindFirst(const wxString& spec, int flags) -{ - wxList::compatibility_iterator node; - wxString spec2(spec); - - m_FindFileHandler = NULL; - - for (int i = spec2.length()-1; i >= 0; i--) - if (spec2[(unsigned int) i] == wxT('\\')) spec2.GetWritableChar(i) = wxT('/'); // Want to be windows-safe - - node = m_Handlers.GetFirst(); - while (node) - { - wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); - if (h -> CanOpen(m_Path + spec2)) - { - m_FindFileHandler = MakeLocal(h); - return m_FindFileHandler -> FindFirst(m_Path + spec2, flags); - } - node = node->GetNext(); - } - - node = m_Handlers.GetFirst(); - while (node) - { - wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); - if (h -> CanOpen(spec2)) - { - m_FindFileHandler = MakeLocal(h); - return m_FindFileHandler -> FindFirst(spec2, flags); - } - node = node->GetNext(); - } - - return wxEmptyString; -} - - - -wxString wxFileSystem::FindNext() -{ - if (m_FindFileHandler == NULL) return wxEmptyString; - else return m_FindFileHandler -> FindNext(); -} - -bool wxFileSystem::FindFileInPath(wxString *pStr, - const wxChar *path, - const wxChar *basename) -{ - // we assume that it's not empty - wxCHECK_MSG( !wxIsEmpty(basename), false, - _T("empty file name in wxFileSystem::FindFileInPath")); - - // skip path separator in the beginning of the file name if present - if ( wxIsPathSeparator(*basename) ) - basename++; - - wxStringTokenizer tokenizer(path, wxPATH_SEP); - while ( tokenizer.HasMoreTokens() ) - { - wxString strFile = tokenizer.GetNextToken(); - if ( !wxEndsWithPathSeparator(strFile) ) - strFile += wxFILE_SEP_PATH; - strFile += basename; - - wxFSFile *file = OpenFile(strFile); - if ( file ) - { - delete file; - *pStr = strFile; - return true; - } - } - - return false; -} - -void wxFileSystem::AddHandler(wxFileSystemHandler *handler) -{ - // prepend the handler to the beginning of the list because handlers added - // last should have the highest priority to allow overriding them - m_Handlers.Insert((size_t)0, handler); -} - -wxFileSystemHandler* wxFileSystem::RemoveHandler(wxFileSystemHandler *handler) -{ - // if handler has already been removed (or deleted) - // we return NULL. This is by design in case - // CleanUpHandlers() is called before RemoveHandler - // is called, as we cannot control the order - // which modules are unloaded - if (!m_Handlers.DeleteObject(handler)) - return NULL; - - return handler; -} - - -bool wxFileSystem::HasHandlerForPath(const wxString &location) -{ - for ( wxList::compatibility_iterator node = m_Handlers.GetFirst(); - node; node = node->GetNext() ) - { - wxFileSystemHandler *h = (wxFileSystemHandler*) node->GetData(); - if (h->CanOpen(location)) - return true; - } - - return false; -} - -void wxFileSystem::CleanUpHandlers() -{ - WX_CLEAR_LIST(wxList, m_Handlers); -} - -static const wxString g_unixPathString(wxT("/")); -static const wxString g_nativePathString(wxFILE_SEP_PATH); - -// Returns the native path for a file URL -wxFileName wxFileSystem::URLToFileName(const wxString& url) -{ - wxString path = url; - - if ( path.Find(wxT("file://")) == 0 ) - { - path = path.Mid(7); - } - else if ( path.Find(wxT("file:")) == 0 ) - { - path = path.Mid(5); - } - // Remove preceding double slash on Mac Classic -#if defined(__WXMAC__) && !defined(__UNIX__) - else if ( path.Find(wxT("//")) == 0 ) - path = path.Mid(2); -#endif - - path = wxURI::Unescape(path); - -#ifdef __WXMSW__ - // file urls either start with a forward slash (local harddisk), - // otherwise they have a servername/sharename notation, - // which only exists on msw and corresponds to a unc - if ( path[0u] == wxT('/') && path [1u] != wxT('/')) - { - path = path.Mid(1); - } - else if ( (url.Find(wxT("file://")) == 0) && - (path.Find(wxT('/')) != wxNOT_FOUND) && - (path.length() > 1) && (path[1u] != wxT(':')) ) - { - path = wxT("//") + path; - } -#endif - - path.Replace(g_unixPathString, g_nativePathString); - - return wxFileName(path, wxPATH_NATIVE); -} - -// Returns the file URL for a native path -wxString wxFileSystem::FileNameToURL(const wxFileName& filename) -{ - wxFileName fn = filename; - fn.Normalize(wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | wxPATH_NORM_ABSOLUTE); - wxString url = fn.GetFullPath(wxPATH_NATIVE); - -#ifndef __UNIX__ - // unc notation, wxMSW - if ( url.Find(wxT("\\\\")) == 0 ) - { - url = wxT("//") + url.Mid(2); - } - else - { - url = wxT("/") + url; -#ifdef __WXMAC__ - url = wxT("/") + url; -#endif - - } -#endif - - url.Replace(g_nativePathString, g_unixPathString); - url.Replace(wxT("%"), wxT("%25")); // '%'s must be replaced first! - url.Replace(wxT("#"), wxT("%23")); - url.Replace(wxT(":"), wxT("%3A")); - url = wxT("file:") + url; - return url; -} - - -///// Module: - -class wxFileSystemModule : public wxModule -{ - DECLARE_DYNAMIC_CLASS(wxFileSystemModule) - - public: - wxFileSystemModule() : - wxModule(), - m_handler(NULL) - { - } - - virtual bool OnInit() - { - m_handler = new wxLocalFSHandler; - wxFileSystem::AddHandler(m_handler); - return true; - } - virtual void OnExit() - { - delete wxFileSystem::RemoveHandler(m_handler); - - wxFileSystem::CleanUpHandlers(); - } - - private: - wxFileSystemHandler* m_handler; - -}; - -IMPLEMENT_DYNAMIC_CLASS(wxFileSystemModule, wxModule) - -#endif - // wxUSE_FILESYSTEM +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/filesys.cpp +// Purpose: wxFileSystem class - interface for opening files +// Author: Vaclav Slavik +// Copyright: (c) 1999 Vaclav Slavik +// CVS-ID: $Id: filesys.cpp 55271 2008-08-26 00:03:04Z VZ $ +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + + +#if wxUSE_FILESYSTEM + +#include "wx/filesys.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/module.h" +#endif + +#include "wx/sysopt.h" +#include "wx/wfstream.h" +#include "wx/mimetype.h" +#include "wx/filename.h" +#include "wx/tokenzr.h" +#include "wx/uri.h" +#include "wx/private/fileback.h" + + +//-------------------------------------------------------------------------------- +// wxFileSystemHandler +//-------------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxFileSystemHandler, wxObject) + + +wxString wxFileSystemHandler::GetMimeTypeFromExt(const wxString& location) +{ + wxString ext, mime; + wxString loc = GetRightLocation(location); + wxChar c; + int l = loc.length(), l2; + + l2 = l; + for (int i = l-1; i >= 0; i--) + { + c = loc[(unsigned int) i]; + if ( c == wxT('#') ) + l2 = i + 1; + if ( c == wxT('.') ) + { + ext = loc.Right(l2-i-1); + break; + } + if ( (c == wxT('/')) || (c == wxT('\\')) || (c == wxT(':')) ) + return wxEmptyString; + } + +#if wxUSE_MIMETYPE + static bool s_MinimalMimeEnsured = false; + + // Don't use mime types manager if the application doesn't need it and it would be + // cause an unacceptable delay, especially on startup. + bool useMimeTypesManager = true; +#if wxUSE_SYSTEM_OPTIONS + useMimeTypesManager = (wxSystemOptions::GetOptionInt(wxT("filesys.no-mimetypesmanager")) == 0); +#endif + + if (useMimeTypesManager) + { + if (!s_MinimalMimeEnsured) + { + static const wxFileTypeInfo fallbacks[] = + { + wxFileTypeInfo(_T("image/jpeg"), + wxEmptyString, + wxEmptyString, + _T("JPEG image (from fallback)"), + _T("jpg"), _T("jpeg"), _T("JPG"), _T("JPEG"), NULL), + wxFileTypeInfo(_T("image/gif"), + wxEmptyString, + wxEmptyString, + _T("GIF image (from fallback)"), + _T("gif"), _T("GIF"), NULL), + wxFileTypeInfo(_T("image/png"), + wxEmptyString, + wxEmptyString, + _T("PNG image (from fallback)"), + _T("png"), _T("PNG"), NULL), + wxFileTypeInfo(_T("image/bmp"), + wxEmptyString, + wxEmptyString, + _T("windows bitmap image (from fallback)"), + _T("bmp"), _T("BMP"), NULL), + wxFileTypeInfo(_T("text/html"), + wxEmptyString, + wxEmptyString, + _T("HTML document (from fallback)"), + _T("htm"), _T("html"), _T("HTM"), _T("HTML"), NULL), + // must terminate the table with this! + wxFileTypeInfo() + }; + wxTheMimeTypesManager->AddFallbacks(fallbacks); + s_MinimalMimeEnsured = true; + } + + wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(ext); + if ( !ft || !ft -> GetMimeType(&mime) ) + { + mime = wxEmptyString; + } + + delete ft; + + return mime; + } + else +#endif + { + if ( ext.IsSameAs(wxT("htm"), false) || ext.IsSameAs(_T("html"), false) ) + return wxT("text/html"); + if ( ext.IsSameAs(wxT("jpg"), false) || ext.IsSameAs(_T("jpeg"), false) ) + return wxT("image/jpeg"); + if ( ext.IsSameAs(wxT("gif"), false) ) + return wxT("image/gif"); + if ( ext.IsSameAs(wxT("png"), false) ) + return wxT("image/png"); + if ( ext.IsSameAs(wxT("bmp"), false) ) + return wxT("image/bmp"); + return wxEmptyString; + } +} + + + +wxString wxFileSystemHandler::GetProtocol(const wxString& location) const +{ + wxString s = wxEmptyString; + int i, l = location.length(); + bool fnd = false; + + for (i = l-1; (i >= 0) && ((location[i] != wxT('#')) || (!fnd)); i--) { + if ((location[i] == wxT(':')) && (i != 1 /*win: C:\path*/)) fnd = true; + } + if (!fnd) return wxT("file"); + for (++i; (i < l) && (location[i] != wxT(':')); i++) s << location[i]; + return s; +} + + +wxString wxFileSystemHandler::GetLeftLocation(const wxString& location) const +{ + int i; + bool fnd = false; + + for (i = location.length()-1; i >= 0; i--) { + if ((location[i] == wxT(':')) && (i != 1 /*win: C:\path*/)) fnd = true; + else if (fnd && (location[i] == wxT('#'))) return location.Left(i); + } + return wxEmptyString; +} + +wxString wxFileSystemHandler::GetRightLocation(const wxString& location) const +{ + int i, l = location.length(); + int l2 = l + 1; + + for (i = l-1; + (i >= 0) && + ((location[i] != wxT(':')) || (i == 1) || (location[i-2] == wxT(':'))); + i--) + { + if (location[i] == wxT('#')) l2 = i + 1; + } + if (i == 0) return wxEmptyString; + else return location.Mid(i + 1, l2 - i - 2); +} + +wxString wxFileSystemHandler::GetAnchor(const wxString& location) const +{ + wxChar c; + int l = location.length(); + + for (int i = l-1; i >= 0; i--) { + c = location[i]; + if (c == wxT('#')) + return location.Right(l-i-1); + else if ((c == wxT('/')) || (c == wxT('\\')) || (c == wxT(':'))) + return wxEmptyString; + } + return wxEmptyString; +} + + +wxString wxFileSystemHandler::FindFirst(const wxString& WXUNUSED(spec), + int WXUNUSED(flags)) +{ + return wxEmptyString; +} + +wxString wxFileSystemHandler::FindNext() +{ + return wxEmptyString; +} + +//-------------------------------------------------------------------------------- +// wxLocalFSHandler +//-------------------------------------------------------------------------------- + + +wxString wxLocalFSHandler::ms_root; + +bool wxLocalFSHandler::CanOpen(const wxString& location) +{ + return GetProtocol(location) == wxT("file"); +} + +wxFSFile* wxLocalFSHandler::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location) +{ + // location has Unix path separators + wxString right = GetRightLocation(location); + wxFileName fn = wxFileSystem::URLToFileName(right); + wxString fullpath = ms_root + fn.GetFullPath(); + + if (!wxFileExists(fullpath)) + return (wxFSFile*) NULL; + + // we need to check whether we can really read from this file, otherwise + // wxFSFile is not going to work +#if wxUSE_FFILE + wxFFileInputStream *is = new wxFFileInputStream(fullpath); +#elif wxUSE_FILE + wxFileInputStream *is = new wxFileInputStream(fullpath); +#else +#error One of wxUSE_FILE or wxUSE_FFILE must be set to 1 for wxFSHandler to work +#endif + if ( !is->Ok() ) + { + delete is; + return (wxFSFile*) NULL; + } + + return new wxFSFile(is, + right, + GetMimeTypeFromExt(location), + GetAnchor(location) +#if wxUSE_DATETIME + ,wxDateTime(wxFileModificationTime(fullpath)) +#endif // wxUSE_DATETIME + ); +} + +wxString wxLocalFSHandler::FindFirst(const wxString& spec, int flags) +{ + wxFileName fn = wxFileSystem::URLToFileName(GetRightLocation(spec)); + return wxFindFirstFile(ms_root + fn.GetFullPath(), flags); +} + +wxString wxLocalFSHandler::FindNext() +{ + return wxFindNextFile(); +} + + + +//----------------------------------------------------------------------------- +// wxFileSystem +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxFileSystem, wxObject) +IMPLEMENT_ABSTRACT_CLASS(wxFSFile, wxObject) + + +wxList wxFileSystem::m_Handlers; + + +wxFileSystem::~wxFileSystem() +{ + WX_CLEAR_HASH_MAP(wxFSHandlerHash, m_LocalHandlers) +} + + +static wxString MakeCorrectPath(const wxString& path) +{ + wxString p(path); + wxString r; + int i, j, cnt; + + cnt = p.length(); + for (i = 0; i < cnt; i++) + if (p.GetChar(i) == wxT('\\')) p.GetWritableChar(i) = wxT('/'); // Want to be windows-safe + + if (p.Left(2) == wxT("./")) { p = p.Mid(2); cnt -= 2; } + + if (cnt < 3) return p; + + r << p.GetChar(0) << p.GetChar(1); + + // skip trailing ../.., if any + for (i = 2; i < cnt && (p.GetChar(i) == wxT('/') || p.GetChar(i) == wxT('.')); i++) r << p.GetChar(i); + + // remove back references: translate dir1/../dir2 to dir2 + for (; i < cnt; i++) + { + r << p.GetChar(i); + if (p.GetChar(i) == wxT('/') && p.GetChar(i-1) == wxT('.') && p.GetChar(i-2) == wxT('.')) + { + for (j = r.length() - 2; j >= 0 && r.GetChar(j) != wxT('/') && r.GetChar(j) != wxT(':'); j--) {} + if (j >= 0 && r.GetChar(j) != wxT(':')) + { + for (j = j - 1; j >= 0 && r.GetChar(j) != wxT('/') && r.GetChar(j) != wxT(':'); j--) {} + r.Remove(j + 1); + } + } + } + + for (; i < cnt; i++) r << p.GetChar(i); + + return r; +} + + +void wxFileSystem::ChangePathTo(const wxString& location, bool is_dir) +{ + int i, pathpos = -1; + + m_Path = MakeCorrectPath(location); + + if (is_dir) + { + if (m_Path.length() > 0 && m_Path.Last() != wxT('/') && m_Path.Last() != wxT(':')) + m_Path << wxT('/'); + } + + else + { + for (i = m_Path.length()-1; i >= 0; i--) + { + if (m_Path[(unsigned int) i] == wxT('/')) + { + if ((i > 1) && (m_Path[(unsigned int) (i-1)] == wxT('/')) && (m_Path[(unsigned int) (i-2)] == wxT(':'))) + { + i -= 2; + continue; + } + else + { + pathpos = i; + break; + } + } + else if (m_Path[(unsigned int) i] == wxT(':')) { + pathpos = i; + break; + } + } + if (pathpos == -1) + { + for (i = 0; i < (int) m_Path.length(); i++) + { + if (m_Path[(unsigned int) i] == wxT(':')) + { + m_Path.Remove(i+1); + break; + } + } + if (i == (int) m_Path.length()) + m_Path = wxEmptyString; + } + else + { + m_Path.Remove(pathpos+1); + } + } +} + + + +wxFileSystemHandler *wxFileSystem::MakeLocal(wxFileSystemHandler *h) +{ + wxClassInfo *classinfo = h->GetClassInfo(); + + if (classinfo->IsDynamic()) + { + wxFileSystemHandler*& local = m_LocalHandlers[classinfo]; + if (!local) + local = (wxFileSystemHandler*)classinfo->CreateObject(); + return local; + } + else + { + return h; + } +} + + + +wxFSFile* wxFileSystem::OpenFile(const wxString& location, int flags) +{ + if ((flags & wxFS_READ) == 0) + return NULL; + + wxString loc = MakeCorrectPath(location); + unsigned i, ln; + wxChar meta; + wxFSFile *s = NULL; + wxList::compatibility_iterator node; + + ln = loc.length(); + meta = 0; + for (i = 0; i < ln; i++) + { + switch (loc[i]) + { + case wxT('/') : case wxT(':') : case wxT('#') : + meta = loc[i]; + break; + } + if (meta != 0) break; + } + m_LastName = wxEmptyString; + + // try relative paths first : + if (meta != wxT(':')) + { + node = m_Handlers.GetFirst(); + while (node) + { + wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); + if (h->CanOpen(m_Path + loc)) + { + s = MakeLocal(h)->OpenFile(*this, m_Path + loc); + if (s) { m_LastName = m_Path + loc; break; } + } + node = node->GetNext(); + } + } + + // if failed, try absolute paths : + if (s == NULL) + { + node = m_Handlers.GetFirst(); + while (node) + { + wxFileSystemHandler *h = (wxFileSystemHandler*) node->GetData(); + if (h->CanOpen(loc)) + { + s = MakeLocal(h)->OpenFile(*this, loc); + if (s) { m_LastName = loc; break; } + } + node = node->GetNext(); + } + } + + if (s && (flags & wxFS_SEEKABLE) != 0 && !s->GetStream()->IsSeekable()) + { + wxBackedInputStream *stream; + stream = new wxBackedInputStream(s->DetachStream()); + stream->FindLength(); + s->SetStream(stream); + } + + return (s); +} + + + +wxString wxFileSystem::FindFirst(const wxString& spec, int flags) +{ + wxList::compatibility_iterator node; + wxString spec2(spec); + + m_FindFileHandler = NULL; + + for (int i = spec2.length()-1; i >= 0; i--) + if (spec2[(unsigned int) i] == wxT('\\')) spec2.GetWritableChar(i) = wxT('/'); // Want to be windows-safe + + node = m_Handlers.GetFirst(); + while (node) + { + wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); + if (h -> CanOpen(m_Path + spec2)) + { + m_FindFileHandler = MakeLocal(h); + return m_FindFileHandler -> FindFirst(m_Path + spec2, flags); + } + node = node->GetNext(); + } + + node = m_Handlers.GetFirst(); + while (node) + { + wxFileSystemHandler *h = (wxFileSystemHandler*) node -> GetData(); + if (h -> CanOpen(spec2)) + { + m_FindFileHandler = MakeLocal(h); + return m_FindFileHandler -> FindFirst(spec2, flags); + } + node = node->GetNext(); + } + + return wxEmptyString; +} + + + +wxString wxFileSystem::FindNext() +{ + if (m_FindFileHandler == NULL) return wxEmptyString; + else return m_FindFileHandler -> FindNext(); +} + +bool wxFileSystem::FindFileInPath(wxString *pStr, + const wxChar *path, + const wxChar *basename) +{ + // we assume that it's not empty + wxCHECK_MSG( !wxIsEmpty(basename), false, + _T("empty file name in wxFileSystem::FindFileInPath")); + + // skip path separator in the beginning of the file name if present + if ( wxIsPathSeparator(*basename) ) + basename++; + + wxStringTokenizer tokenizer(path, wxPATH_SEP); + while ( tokenizer.HasMoreTokens() ) + { + wxString strFile = tokenizer.GetNextToken(); + if ( !wxEndsWithPathSeparator(strFile) ) + strFile += wxFILE_SEP_PATH; + strFile += basename; + + wxFSFile *file = OpenFile(strFile); + if ( file ) + { + delete file; + *pStr = strFile; + return true; + } + } + + return false; +} + +void wxFileSystem::AddHandler(wxFileSystemHandler *handler) +{ + // prepend the handler to the beginning of the list because handlers added + // last should have the highest priority to allow overriding them + m_Handlers.Insert((size_t)0, handler); +} + +wxFileSystemHandler* wxFileSystem::RemoveHandler(wxFileSystemHandler *handler) +{ + // if handler has already been removed (or deleted) + // we return NULL. This is by design in case + // CleanUpHandlers() is called before RemoveHandler + // is called, as we cannot control the order + // which modules are unloaded + if (!m_Handlers.DeleteObject(handler)) + return NULL; + + return handler; +} + + +bool wxFileSystem::HasHandlerForPath(const wxString &location) +{ + for ( wxList::compatibility_iterator node = m_Handlers.GetFirst(); + node; node = node->GetNext() ) + { + wxFileSystemHandler *h = (wxFileSystemHandler*) node->GetData(); + if (h->CanOpen(location)) + return true; + } + + return false; +} + +void wxFileSystem::CleanUpHandlers() +{ + WX_CLEAR_LIST(wxList, m_Handlers); +} + +static const wxString g_unixPathString(wxT("/")); +static const wxString g_nativePathString(wxFILE_SEP_PATH); + +// Returns the native path for a file URL +wxFileName wxFileSystem::URLToFileName(const wxString& url) +{ + wxString path = url; + + if ( path.Find(wxT("file://")) == 0 ) + { + path = path.Mid(7); + } + else if ( path.Find(wxT("file:")) == 0 ) + { + path = path.Mid(5); + } + // Remove preceding double slash on Mac Classic +#if defined(__WXMAC__) && !defined(__UNIX__) + else if ( path.Find(wxT("//")) == 0 ) + path = path.Mid(2); +#endif + + path = wxURI::Unescape(path); + +#ifdef __WXMSW__ + // file urls either start with a forward slash (local harddisk), + // otherwise they have a servername/sharename notation, + // which only exists on msw and corresponds to a unc + if ( path[0u] == wxT('/') && path [1u] != wxT('/')) + { + path = path.Mid(1); + } + else if ( (url.Find(wxT("file://")) == 0) && + (path.Find(wxT('/')) != wxNOT_FOUND) && + (path.length() > 1) && (path[1u] != wxT(':')) ) + { + path = wxT("//") + path; + } +#endif + + path.Replace(g_unixPathString, g_nativePathString); + + return wxFileName(path, wxPATH_NATIVE); +} + +// Returns the file URL for a native path +wxString wxFileSystem::FileNameToURL(const wxFileName& filename) +{ + wxFileName fn = filename; + fn.Normalize(wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | wxPATH_NORM_ABSOLUTE); + wxString url = fn.GetFullPath(wxPATH_NATIVE); + +#ifndef __UNIX__ + // unc notation, wxMSW + if ( url.Find(wxT("\\\\")) == 0 ) + { + url = wxT("//") + url.Mid(2); + } + else + { + url = wxT("/") + url; +#ifdef __WXMAC__ + url = wxT("/") + url; +#endif + + } +#endif + + url.Replace(g_nativePathString, g_unixPathString); + url.Replace(wxT("%"), wxT("%25")); // '%'s must be replaced first! + url.Replace(wxT("#"), wxT("%23")); + url.Replace(wxT(":"), wxT("%3A")); + url = wxT("file:") + url; + return url; +} + + +///// Module: + +class wxFileSystemModule : public wxModule +{ + DECLARE_DYNAMIC_CLASS(wxFileSystemModule) + + public: + wxFileSystemModule() : + wxModule(), + m_handler(NULL) + { + } + + virtual bool OnInit() + { + m_handler = new wxLocalFSHandler; + wxFileSystem::AddHandler(m_handler); + return true; + } + virtual void OnExit() + { + delete wxFileSystem::RemoveHandler(m_handler); + + wxFileSystem::CleanUpHandlers(); + } + + private: + wxFileSystemHandler* m_handler; + +}; + +IMPLEMENT_DYNAMIC_CLASS(wxFileSystemModule, wxModule) + +#endif + // wxUSE_FILESYSTEM diff --git a/Source/3rd Party/wx/src/common/filtall.cpp b/Source/3rd Party/wx/src/common/filtall.cpp index 69f595e45..952730f82 100644 --- a/Source/3rd Party/wx/src/common/filtall.cpp +++ b/Source/3rd Party/wx/src/common/filtall.cpp @@ -1,36 +1,36 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/filtall.cpp -// Purpose: Link all filter streams -// Author: Mike Wetherell -// RCS-ID: $Id: filtall.cpp 42412 2006-10-25 20:41:12Z MW $ -// Copyright: (c) 2006 Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#if wxUSE_ZLIB -#include "wx/zstream.h" -#endif - -// Reference filter classes to ensure they are linked into a statically -// linked program that uses Find or GetFirst to look for an filter handler. -// It is in its own file so that the user can override this behaviour by -// providing their own implementation. - -void wxUseFilterClasses() -{ -#if wxUSE_ZLIB - wxZlibClassFactory(); - wxGzipClassFactory(); -#endif -} - -#endif // wxUSE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/filtall.cpp +// Purpose: Link all filter streams +// Author: Mike Wetherell +// RCS-ID: $Id: filtall.cpp 42412 2006-10-25 20:41:12Z MW $ +// Copyright: (c) 2006 Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#if wxUSE_ZLIB +#include "wx/zstream.h" +#endif + +// Reference filter classes to ensure they are linked into a statically +// linked program that uses Find or GetFirst to look for an filter handler. +// It is in its own file so that the user can override this behaviour by +// providing their own implementation. + +void wxUseFilterClasses() +{ +#if wxUSE_ZLIB + wxZlibClassFactory(); + wxGzipClassFactory(); +#endif +} + +#endif // wxUSE_STREAMS diff --git a/Source/3rd Party/wx/src/common/filtfind.cpp b/Source/3rd Party/wx/src/common/filtfind.cpp index 7da889a76..16cb227f3 100644 --- a/Source/3rd Party/wx/src/common/filtfind.cpp +++ b/Source/3rd Party/wx/src/common/filtfind.cpp @@ -1,43 +1,43 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/filtfind.cpp -// Purpose: Streams for filter formats -// Author: Mike Wetherell -// RCS-ID: $Id: filtfind.cpp 42412 2006-10-25 20:41:12Z MW $ -// Copyright: (c) Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#include "wx/stream.h" - -// These functions are in a separate file so that statically linked apps -// that do not call them to search for filter handlers will only link in -// the filter classes they use. - -const wxFilterClassFactory * -wxFilterClassFactory::Find(const wxChar *protocol, wxStreamProtocolType type) -{ - for (const wxFilterClassFactory *f = GetFirst(); f; f = f->GetNext()) - if (f->CanHandle(protocol, type)) - return f; - - return NULL; -} - -// static -const wxFilterClassFactory *wxFilterClassFactory::GetFirst() -{ - if (!sm_first) - wxUseFilterClasses(); - return sm_first; -} - -#endif // wxUSE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/filtfind.cpp +// Purpose: Streams for filter formats +// Author: Mike Wetherell +// RCS-ID: $Id: filtfind.cpp 42412 2006-10-25 20:41:12Z MW $ +// Copyright: (c) Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#include "wx/stream.h" + +// These functions are in a separate file so that statically linked apps +// that do not call them to search for filter handlers will only link in +// the filter classes they use. + +const wxFilterClassFactory * +wxFilterClassFactory::Find(const wxChar *protocol, wxStreamProtocolType type) +{ + for (const wxFilterClassFactory *f = GetFirst(); f; f = f->GetNext()) + if (f->CanHandle(protocol, type)) + return f; + + return NULL; +} + +// static +const wxFilterClassFactory *wxFilterClassFactory::GetFirst() +{ + if (!sm_first) + wxUseFilterClasses(); + return sm_first; +} + +#endif // wxUSE_STREAMS diff --git a/Source/3rd Party/wx/src/common/fldlgcmn.cpp b/Source/3rd Party/wx/src/common/fldlgcmn.cpp index 9aef8a173..6f59d40eb 100644 --- a/Source/3rd Party/wx/src/common/fldlgcmn.cpp +++ b/Source/3rd Party/wx/src/common/fldlgcmn.cpp @@ -1,348 +1,348 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fldlgcmn.cpp -// Purpose: wxFileDialog common functions -// Author: John Labenski -// Modified by: -// Created: 14.06.03 (extracted from src/*/filedlg.cpp) -// RCS-ID: $Id: fldlgcmn.cpp 66916 2011-02-16 21:48:55Z JS $ -// Copyright: (c) Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if wxUSE_FILEDLG - -#include "wx/filedlg.h" -#include "wx/dirdlg.h" - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/window.h" -#endif // WX_PRECOMP - -//---------------------------------------------------------------------------- -// wxFileDialogBase -//---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxFileDialogBase, wxDialog) - -void wxFileDialogBase::Init() -{ - m_filterIndex = - m_windowStyle = 0; -} - -bool wxFileDialogBase::Create(wxWindow *parent, - const wxString& message, - const wxString& defaultDir, - const wxString& defaultFile, - const wxString& wildCard, - long style, - const wxPoint& WXUNUSED(pos), - const wxSize& WXUNUSED(sz), - const wxString& WXUNUSED(name)) -{ - m_message = message; - m_dir = defaultDir; - m_fileName = defaultFile; - m_wildCard = wildCard; - - m_parent = parent; - m_windowStyle = style; - m_filterIndex = 0; - - if (!HasFdFlag(wxFD_OPEN) && !HasFdFlag(wxFD_SAVE)) - m_windowStyle |= wxFD_OPEN; // wxFD_OPEN is the default - - // check that the styles are not contradictory - wxASSERT_MSG( !(HasFdFlag(wxFD_SAVE) && HasFdFlag(wxFD_OPEN)), - _T("can't specify both wxFD_SAVE and wxFD_OPEN at once") ); - - wxASSERT_MSG( !HasFdFlag(wxFD_SAVE) || - (!HasFdFlag(wxFD_MULTIPLE) && !HasFdFlag(wxFD_FILE_MUST_EXIST)), - _T("wxFD_MULTIPLE or wxFD_FILE_MUST_EXIST can't be used with wxFD_SAVE" ) ); - - wxASSERT_MSG( !HasFdFlag(wxFD_OPEN) || !HasFdFlag(wxFD_OVERWRITE_PROMPT), - _T("wxFD_OVERWRITE_PROMPT can't be used with wxFD_OPEN") ); - - if ( wildCard.empty() || wildCard == wxFileSelectorDefaultWildcardStr ) - { - m_wildCard = wxString::Format(_("All files (%s)|%s"), - wxFileSelectorDefaultWildcardStr, - wxFileSelectorDefaultWildcardStr); - } - else // have wild card - { - // convert m_wildCard from "*.bar" to "bar files (*.bar)|*.bar" - if ( m_wildCard.Find(wxT('|')) == wxNOT_FOUND ) - { - wxString::size_type nDot = m_wildCard.find(_T("*.")); - if ( nDot != wxString::npos ) - nDot++; - else - nDot = 0; - - m_wildCard = wxString::Format - ( - _("%s files (%s)|%s"), - wildCard.c_str() + nDot, - wildCard.c_str(), - wildCard.c_str() - ); - } - } - - return true; -} - -#if WXWIN_COMPATIBILITY_2_4 -// Parses the filterStr, returning the number of filters. -// Returns 0 if none or if there's a problem. -// filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpg" -int wxFileDialogBase::ParseWildcard(const wxString& filterStr, - wxArrayString& descriptions, - wxArrayString& filters) -{ - return ::wxParseCommonDialogsFilter(filterStr, descriptions, filters); -} -#endif // WXWIN_COMPATIBILITY_2_4 - -#if WXWIN_COMPATIBILITY_2_6 -long wxFileDialogBase::GetStyle() const -{ - return GetWindowStyle(); -} - -void wxFileDialogBase::SetStyle(long style) -{ - SetWindowStyle(style); -} -#endif // WXWIN_COMPATIBILITY_2_6 - - -wxString wxFileDialogBase::AppendExtension(const wxString &filePath, - const wxString &extensionList) -{ - // strip off path, to avoid problems with "path.bar/foo" - wxString fileName = filePath.AfterLast(wxFILE_SEP_PATH); - - // if fileName is of form "foo.bar" it's ok, return it - int idx_dot = fileName.Find(wxT('.'), true); - if ((idx_dot != wxNOT_FOUND) && (idx_dot < (int)fileName.length() - 1)) - return filePath; - - // get the first extension from extensionList, or all of it - wxString ext = extensionList.BeforeFirst(wxT(';')); - - // if ext == "foo" or "foo." there's no extension - int idx_ext_dot = ext.Find(wxT('.'), true); - if ((idx_ext_dot == wxNOT_FOUND) || (idx_ext_dot == (int)ext.length() - 1)) - return filePath; - else - ext = ext.AfterLast(wxT('.')); - - // if ext == "*" or "bar*" or "b?r" or " " then its not valid - if ((ext.Find(wxT('*')) != wxNOT_FOUND) || - (ext.Find(wxT('?')) != wxNOT_FOUND) || - (ext.Strip(wxString::both).empty())) - return filePath; - - // if fileName doesn't have a '.' then add one - if (filePath.Last() != wxT('.')) - ext = wxT(".") + ext; - - return filePath + ext; -} - -//---------------------------------------------------------------------------- -// wxFileDialog convenience functions -//---------------------------------------------------------------------------- - -wxString wxFileSelector(const wxChar *title, - const wxChar *defaultDir, - const wxChar *defaultFileName, - const wxChar *defaultExtension, - const wxChar *filter, - int flags, - wxWindow *parent, - int x, int y) -{ - // The defaultExtension, if non-NULL, is - // appended to the filename if the user fails to type an extension. The new - // implementation (taken from wxFileSelectorEx) appends the extension - // automatically, by looking at the filter specification. In fact this - // should be better than the native Microsoft implementation because - // Windows only allows *one* default extension, whereas here we do the - // right thing depending on the filter the user has chosen. - - // If there's a default extension specified but no filter, we create a - // suitable filter. - - wxString filter2; - if ( !wxIsEmpty(defaultExtension) && wxIsEmpty(filter) ) - filter2 = wxString(wxT("*.")) + defaultExtension; - else if ( !wxIsEmpty(filter) ) - filter2 = filter; - - wxString defaultDirString; - if (!wxIsEmpty(defaultDir)) - defaultDirString = defaultDir; - - wxString defaultFilenameString; - if (!wxIsEmpty(defaultFileName)) - defaultFilenameString = defaultFileName; - - wxFileDialog fileDialog(parent, title, defaultDirString, - defaultFilenameString, filter2, - flags, wxPoint(x, y)); - - // if filter is of form "All files (*)|*|..." set correct filter index - if((wxStrlen(defaultExtension) != 0) && (filter2.Find(wxT('|')) != wxNOT_FOUND)) - { - int filterIndex = 0; - - wxArrayString descriptions, filters; - // don't care about errors, handled already by wxFileDialog - (void)wxParseCommonDialogsFilter(filter2, descriptions, filters); - for (size_t n=0; n 0) - fileDialog.SetFilterIndex(filterIndex); - } - - wxString filename; - if ( fileDialog.ShowModal() == wxID_OK ) - { - filename = fileDialog.GetPath(); - } - - return filename; -} - -//---------------------------------------------------------------------------- -// wxFileSelectorEx -//---------------------------------------------------------------------------- - -wxString wxFileSelectorEx(const wxChar *title, - const wxChar *defaultDir, - const wxChar *defaultFileName, - int* defaultFilterIndex, - const wxChar *filter, - int flags, - wxWindow* parent, - int x, - int y) - -{ - wxFileDialog fileDialog(parent, - !wxIsEmpty(title) ? title : wxEmptyString, - !wxIsEmpty(defaultDir) ? defaultDir : wxEmptyString, - !wxIsEmpty(defaultFileName) ? defaultFileName : wxEmptyString, - !wxIsEmpty(filter) ? filter : wxEmptyString, - flags, wxPoint(x, y)); - - wxString filename; - if ( fileDialog.ShowModal() == wxID_OK ) - { - if ( defaultFilterIndex ) - *defaultFilterIndex = fileDialog.GetFilterIndex(); - - filename = fileDialog.GetPath(); - } - - return filename; -} - -//---------------------------------------------------------------------------- -// wxDefaultFileSelector - Generic load/save dialog (for internal use only) -//---------------------------------------------------------------------------- - -static wxString wxDefaultFileSelector(bool load, - const wxChar *what, - const wxChar *extension, - const wxChar *default_name, - wxWindow *parent) -{ - wxString prompt; - wxString str; - if (load) - str = _("Load %s file"); - else - str = _("Save %s file"); - prompt.Printf(str, what); - - wxString wild; - const wxChar *ext = extension; - if ( !wxIsEmpty(ext) ) - { - if ( *ext == wxT('.') ) - ext++; - - wild.Printf(wxT("*.%s"), ext); - } - else // no extension specified - { - wild = wxFileSelectorDefaultWildcardStr; - } - - return wxFileSelector(prompt, NULL, default_name, ext, wild, - load ? (wxFD_OPEN | wxFD_FILE_MUST_EXIST) : wxFD_SAVE, parent); -} - -//---------------------------------------------------------------------------- -// wxLoadFileSelector -//---------------------------------------------------------------------------- - -WXDLLEXPORT wxString wxLoadFileSelector(const wxChar *what, - const wxChar *extension, - const wxChar *default_name, - wxWindow *parent) -{ - return wxDefaultFileSelector(true, what, extension, default_name, parent); -} - -//---------------------------------------------------------------------------- -// wxSaveFileSelector -//---------------------------------------------------------------------------- - -WXDLLEXPORT wxString wxSaveFileSelector(const wxChar *what, - const wxChar *extension, - const wxChar *default_name, - wxWindow *parent) -{ - return wxDefaultFileSelector(false, what, extension, default_name, parent); -} - - -//---------------------------------------------------------------------------- -// wxDirDialogBase -//---------------------------------------------------------------------------- - -#if WXWIN_COMPATIBILITY_2_6 -long wxDirDialogBase::GetStyle() const -{ - return GetWindowStyle(); -} - -void wxDirDialogBase::SetStyle(long style) -{ - SetWindowStyle(style); -} -#endif // WXWIN_COMPATIBILITY_2_6 - - -#endif // wxUSE_FILEDLG +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fldlgcmn.cpp +// Purpose: wxFileDialog common functions +// Author: John Labenski +// Modified by: +// Created: 14.06.03 (extracted from src/*/filedlg.cpp) +// RCS-ID: $Id: fldlgcmn.cpp 66916 2011-02-16 21:48:55Z JS $ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if wxUSE_FILEDLG + +#include "wx/filedlg.h" +#include "wx/dirdlg.h" + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/window.h" +#endif // WX_PRECOMP + +//---------------------------------------------------------------------------- +// wxFileDialogBase +//---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxFileDialogBase, wxDialog) + +void wxFileDialogBase::Init() +{ + m_filterIndex = + m_windowStyle = 0; +} + +bool wxFileDialogBase::Create(wxWindow *parent, + const wxString& message, + const wxString& defaultDir, + const wxString& defaultFile, + const wxString& wildCard, + long style, + const wxPoint& WXUNUSED(pos), + const wxSize& WXUNUSED(sz), + const wxString& WXUNUSED(name)) +{ + m_message = message; + m_dir = defaultDir; + m_fileName = defaultFile; + m_wildCard = wildCard; + + m_parent = parent; + m_windowStyle = style; + m_filterIndex = 0; + + if (!HasFdFlag(wxFD_OPEN) && !HasFdFlag(wxFD_SAVE)) + m_windowStyle |= wxFD_OPEN; // wxFD_OPEN is the default + + // check that the styles are not contradictory + wxASSERT_MSG( !(HasFdFlag(wxFD_SAVE) && HasFdFlag(wxFD_OPEN)), + _T("can't specify both wxFD_SAVE and wxFD_OPEN at once") ); + + wxASSERT_MSG( !HasFdFlag(wxFD_SAVE) || + (!HasFdFlag(wxFD_MULTIPLE) && !HasFdFlag(wxFD_FILE_MUST_EXIST)), + _T("wxFD_MULTIPLE or wxFD_FILE_MUST_EXIST can't be used with wxFD_SAVE" ) ); + + wxASSERT_MSG( !HasFdFlag(wxFD_OPEN) || !HasFdFlag(wxFD_OVERWRITE_PROMPT), + _T("wxFD_OVERWRITE_PROMPT can't be used with wxFD_OPEN") ); + + if ( wildCard.empty() || wildCard == wxFileSelectorDefaultWildcardStr ) + { + m_wildCard = wxString::Format(_("All files (%s)|%s"), + wxFileSelectorDefaultWildcardStr, + wxFileSelectorDefaultWildcardStr); + } + else // have wild card + { + // convert m_wildCard from "*.bar" to "bar files (*.bar)|*.bar" + if ( m_wildCard.Find(wxT('|')) == wxNOT_FOUND ) + { + wxString::size_type nDot = m_wildCard.find(_T("*.")); + if ( nDot != wxString::npos ) + nDot++; + else + nDot = 0; + + m_wildCard = wxString::Format + ( + _("%s files (%s)|%s"), + wildCard.c_str() + nDot, + wildCard.c_str(), + wildCard.c_str() + ); + } + } + + return true; +} + +#if WXWIN_COMPATIBILITY_2_4 +// Parses the filterStr, returning the number of filters. +// Returns 0 if none or if there's a problem. +// filterStr is in the form: "All files (*.*)|*.*|JPEG Files (*.jpeg)|*.jpg" +int wxFileDialogBase::ParseWildcard(const wxString& filterStr, + wxArrayString& descriptions, + wxArrayString& filters) +{ + return ::wxParseCommonDialogsFilter(filterStr, descriptions, filters); +} +#endif // WXWIN_COMPATIBILITY_2_4 + +#if WXWIN_COMPATIBILITY_2_6 +long wxFileDialogBase::GetStyle() const +{ + return GetWindowStyle(); +} + +void wxFileDialogBase::SetStyle(long style) +{ + SetWindowStyle(style); +} +#endif // WXWIN_COMPATIBILITY_2_6 + + +wxString wxFileDialogBase::AppendExtension(const wxString &filePath, + const wxString &extensionList) +{ + // strip off path, to avoid problems with "path.bar/foo" + wxString fileName = filePath.AfterLast(wxFILE_SEP_PATH); + + // if fileName is of form "foo.bar" it's ok, return it + int idx_dot = fileName.Find(wxT('.'), true); + if ((idx_dot != wxNOT_FOUND) && (idx_dot < (int)fileName.length() - 1)) + return filePath; + + // get the first extension from extensionList, or all of it + wxString ext = extensionList.BeforeFirst(wxT(';')); + + // if ext == "foo" or "foo." there's no extension + int idx_ext_dot = ext.Find(wxT('.'), true); + if ((idx_ext_dot == wxNOT_FOUND) || (idx_ext_dot == (int)ext.length() - 1)) + return filePath; + else + ext = ext.AfterLast(wxT('.')); + + // if ext == "*" or "bar*" or "b?r" or " " then its not valid + if ((ext.Find(wxT('*')) != wxNOT_FOUND) || + (ext.Find(wxT('?')) != wxNOT_FOUND) || + (ext.Strip(wxString::both).empty())) + return filePath; + + // if fileName doesn't have a '.' then add one + if (filePath.Last() != wxT('.')) + ext = wxT(".") + ext; + + return filePath + ext; +} + +//---------------------------------------------------------------------------- +// wxFileDialog convenience functions +//---------------------------------------------------------------------------- + +wxString wxFileSelector(const wxChar *title, + const wxChar *defaultDir, + const wxChar *defaultFileName, + const wxChar *defaultExtension, + const wxChar *filter, + int flags, + wxWindow *parent, + int x, int y) +{ + // The defaultExtension, if non-NULL, is + // appended to the filename if the user fails to type an extension. The new + // implementation (taken from wxFileSelectorEx) appends the extension + // automatically, by looking at the filter specification. In fact this + // should be better than the native Microsoft implementation because + // Windows only allows *one* default extension, whereas here we do the + // right thing depending on the filter the user has chosen. + + // If there's a default extension specified but no filter, we create a + // suitable filter. + + wxString filter2; + if ( !wxIsEmpty(defaultExtension) && wxIsEmpty(filter) ) + filter2 = wxString(wxT("*.")) + defaultExtension; + else if ( !wxIsEmpty(filter) ) + filter2 = filter; + + wxString defaultDirString; + if (!wxIsEmpty(defaultDir)) + defaultDirString = defaultDir; + + wxString defaultFilenameString; + if (!wxIsEmpty(defaultFileName)) + defaultFilenameString = defaultFileName; + + wxFileDialog fileDialog(parent, title, defaultDirString, + defaultFilenameString, filter2, + flags, wxPoint(x, y)); + + // if filter is of form "All files (*)|*|..." set correct filter index + if((wxStrlen(defaultExtension) != 0) && (filter2.Find(wxT('|')) != wxNOT_FOUND)) + { + int filterIndex = 0; + + wxArrayString descriptions, filters; + // don't care about errors, handled already by wxFileDialog + (void)wxParseCommonDialogsFilter(filter2, descriptions, filters); + for (size_t n=0; n 0) + fileDialog.SetFilterIndex(filterIndex); + } + + wxString filename; + if ( fileDialog.ShowModal() == wxID_OK ) + { + filename = fileDialog.GetPath(); + } + + return filename; +} + +//---------------------------------------------------------------------------- +// wxFileSelectorEx +//---------------------------------------------------------------------------- + +wxString wxFileSelectorEx(const wxChar *title, + const wxChar *defaultDir, + const wxChar *defaultFileName, + int* defaultFilterIndex, + const wxChar *filter, + int flags, + wxWindow* parent, + int x, + int y) + +{ + wxFileDialog fileDialog(parent, + !wxIsEmpty(title) ? title : wxEmptyString, + !wxIsEmpty(defaultDir) ? defaultDir : wxEmptyString, + !wxIsEmpty(defaultFileName) ? defaultFileName : wxEmptyString, + !wxIsEmpty(filter) ? filter : wxEmptyString, + flags, wxPoint(x, y)); + + wxString filename; + if ( fileDialog.ShowModal() == wxID_OK ) + { + if ( defaultFilterIndex ) + *defaultFilterIndex = fileDialog.GetFilterIndex(); + + filename = fileDialog.GetPath(); + } + + return filename; +} + +//---------------------------------------------------------------------------- +// wxDefaultFileSelector - Generic load/save dialog (for internal use only) +//---------------------------------------------------------------------------- + +static wxString wxDefaultFileSelector(bool load, + const wxChar *what, + const wxChar *extension, + const wxChar *default_name, + wxWindow *parent) +{ + wxString prompt; + wxString str; + if (load) + str = _("Load %s file"); + else + str = _("Save %s file"); + prompt.Printf(str, what); + + wxString wild; + const wxChar *ext = extension; + if ( !wxIsEmpty(ext) ) + { + if ( *ext == wxT('.') ) + ext++; + + wild.Printf(wxT("*.%s"), ext); + } + else // no extension specified + { + wild = wxFileSelectorDefaultWildcardStr; + } + + return wxFileSelector(prompt, NULL, default_name, ext, wild, + load ? (wxFD_OPEN | wxFD_FILE_MUST_EXIST) : wxFD_SAVE, parent); +} + +//---------------------------------------------------------------------------- +// wxLoadFileSelector +//---------------------------------------------------------------------------- + +WXDLLEXPORT wxString wxLoadFileSelector(const wxChar *what, + const wxChar *extension, + const wxChar *default_name, + wxWindow *parent) +{ + return wxDefaultFileSelector(true, what, extension, default_name, parent); +} + +//---------------------------------------------------------------------------- +// wxSaveFileSelector +//---------------------------------------------------------------------------- + +WXDLLEXPORT wxString wxSaveFileSelector(const wxChar *what, + const wxChar *extension, + const wxChar *default_name, + wxWindow *parent) +{ + return wxDefaultFileSelector(false, what, extension, default_name, parent); +} + + +//---------------------------------------------------------------------------- +// wxDirDialogBase +//---------------------------------------------------------------------------- + +#if WXWIN_COMPATIBILITY_2_6 +long wxDirDialogBase::GetStyle() const +{ + return GetWindowStyle(); +} + +void wxDirDialogBase::SetStyle(long style) +{ + SetWindowStyle(style); +} +#endif // WXWIN_COMPATIBILITY_2_6 + + +#endif // wxUSE_FILEDLG diff --git a/Source/3rd Party/wx/src/common/fmapbase.cpp b/Source/3rd Party/wx/src/common/fmapbase.cpp index 165013278..d273922c1 100644 --- a/Source/3rd Party/wx/src/common/fmapbase.cpp +++ b/Source/3rd Party/wx/src/common/fmapbase.cpp @@ -1,737 +1,737 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/fmapbase.cpp -// Purpose: wxFontMapperBase class implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 21.06.2003 (extracted from common/fontmap.cpp) -// RCS-ID: $Id: fmapbase.cpp 43063 2006-11-04 20:48:04Z VZ $ -// Copyright: (c) 1999-2003 Vadim Zeitlin -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FONTMAP - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/module.h" -#endif //WX_PRECOMP - -#if defined(__WXMSW__) - #include "wx/msw/private.h" // includes windows.h for LOGFONT - #include "wx/msw/winundef.h" -#endif - -#include "wx/fontmap.h" -#include "wx/fmappriv.h" - -#include "wx/apptrait.h" - -// wxMemoryConfig uses wxFileConfig -#if wxUSE_CONFIG && wxUSE_FILECONFIG - #include "wx/config.h" - #include "wx/memconf.h" -#endif - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// encodings supported by GetEncodingDescription -static wxFontEncoding gs_encodings[] = -{ - wxFONTENCODING_ISO8859_1, - wxFONTENCODING_ISO8859_2, - wxFONTENCODING_ISO8859_3, - wxFONTENCODING_ISO8859_4, - wxFONTENCODING_ISO8859_5, - wxFONTENCODING_ISO8859_6, - wxFONTENCODING_ISO8859_7, - wxFONTENCODING_ISO8859_8, - wxFONTENCODING_ISO8859_9, - wxFONTENCODING_ISO8859_10, - wxFONTENCODING_ISO8859_11, - wxFONTENCODING_ISO8859_12, - wxFONTENCODING_ISO8859_13, - wxFONTENCODING_ISO8859_14, - wxFONTENCODING_ISO8859_15, - wxFONTENCODING_KOI8, - wxFONTENCODING_KOI8_U, - wxFONTENCODING_CP874, - wxFONTENCODING_CP932, - wxFONTENCODING_CP936, - wxFONTENCODING_CP949, - wxFONTENCODING_CP950, - wxFONTENCODING_CP1250, - wxFONTENCODING_CP1251, - wxFONTENCODING_CP1252, - wxFONTENCODING_CP1253, - wxFONTENCODING_CP1254, - wxFONTENCODING_CP1255, - wxFONTENCODING_CP1256, - wxFONTENCODING_CP1257, - wxFONTENCODING_CP437, - wxFONTENCODING_UTF7, - wxFONTENCODING_UTF8, - wxFONTENCODING_UTF16BE, - wxFONTENCODING_UTF16LE, - wxFONTENCODING_UTF32BE, - wxFONTENCODING_UTF32LE, - wxFONTENCODING_EUC_JP, - wxFONTENCODING_DEFAULT, - wxFONTENCODING_BIG5, - wxFONTENCODING_SHIFT_JIS, - wxFONTENCODING_GB2312, -}; - -// the descriptions for them -static const wxChar* gs_encodingDescs[] = -{ - wxTRANSLATE( "Western European (ISO-8859-1)" ), - wxTRANSLATE( "Central European (ISO-8859-2)" ), - wxTRANSLATE( "Esperanto (ISO-8859-3)" ), - wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ), - wxTRANSLATE( "Cyrillic (ISO-8859-5)" ), - wxTRANSLATE( "Arabic (ISO-8859-6)" ), - wxTRANSLATE( "Greek (ISO-8859-7)" ), - wxTRANSLATE( "Hebrew (ISO-8859-8)" ), - wxTRANSLATE( "Turkish (ISO-8859-9)" ), - wxTRANSLATE( "Nordic (ISO-8859-10)" ), - wxTRANSLATE( "Thai (ISO-8859-11)" ), - wxTRANSLATE( "Indian (ISO-8859-12)" ), - wxTRANSLATE( "Baltic (ISO-8859-13)" ), - wxTRANSLATE( "Celtic (ISO-8859-14)" ), - wxTRANSLATE( "Western European with Euro (ISO-8859-15)" ), - wxTRANSLATE( "KOI8-R" ), - wxTRANSLATE( "KOI8-U" ), - wxTRANSLATE( "Windows Thai (CP 874)" ), - wxTRANSLATE( "Windows Japanese (CP 932)" ), - wxTRANSLATE( "Windows Chinese Simplified (CP 936)" ), - wxTRANSLATE( "Windows Korean (CP 949)" ), - wxTRANSLATE( "Windows Chinese Traditional (CP 950)" ), - wxTRANSLATE( "Windows Central European (CP 1250)" ), - wxTRANSLATE( "Windows Cyrillic (CP 1251)" ), - wxTRANSLATE( "Windows Western European (CP 1252)" ), - wxTRANSLATE( "Windows Greek (CP 1253)" ), - wxTRANSLATE( "Windows Turkish (CP 1254)" ), - wxTRANSLATE( "Windows Hebrew (CP 1255)" ), - wxTRANSLATE( "Windows Arabic (CP 1256)" ), - wxTRANSLATE( "Windows Baltic (CP 1257)" ), - wxTRANSLATE( "Windows/DOS OEM (CP 437)" ), - wxTRANSLATE( "Unicode 7 bit (UTF-7)" ), - wxTRANSLATE( "Unicode 8 bit (UTF-8)" ), -#ifdef WORDS_BIGENDIAN - wxTRANSLATE( "Unicode 16 bit (UTF-16)" ), - wxTRANSLATE( "Unicode 16 bit Little Endian (UTF-16LE)" ), - wxTRANSLATE( "Unicode 32 bit (UTF-32)" ), - wxTRANSLATE( "Unicode 32 bit Little Endian (UTF-32LE)" ), -#else // WORDS_BIGENDIAN - wxTRANSLATE( "Unicode 16 bit Big Endian (UTF-16BE)" ), - wxTRANSLATE( "Unicode 16 bit (UTF-16)" ), - wxTRANSLATE( "Unicode 32 bit Big Endian (UTF-32BE)" ), - wxTRANSLATE( "Unicode 32 bit (UTF-32)" ), -#endif // WORDS_BIGENDIAN - wxTRANSLATE( "Extended Unix Codepage for Japanese (EUC-JP)" ), - wxTRANSLATE( "US-ASCII" ), - wxTRANSLATE( "BIG5" ), - wxTRANSLATE( "SHIFT-JIS" ), - wxTRANSLATE( "GB-2312" ), -}; - -// and the internal names (these are not translated on purpose!) -static const wxChar* gs_encodingNames[WXSIZEOF(gs_encodingDescs)][9] = -{ - // names from the columns correspond to these OS: - // Linux Solaris and IRIX HP-UX AIX - { _T("ISO-8859-1"), _T("ISO8859-1"), _T("iso88591"), _T("8859-1"), wxT("iso_8859_1"), NULL }, - { _T("ISO-8859-2"), _T("ISO8859-2"), _T("iso88592"), _T("8859-2"), NULL }, - { _T("ISO-8859-3"), _T("ISO8859-3"), _T("iso88593"), _T("8859-3"), NULL }, - { _T("ISO-8859-4"), _T("ISO8859-4"), _T("iso88594"), _T("8859-4"), NULL }, - { _T("ISO-8859-5"), _T("ISO8859-5"), _T("iso88595"), _T("8859-5"), NULL }, - { _T("ISO-8859-6"), _T("ISO8859-6"), _T("iso88596"), _T("8859-6"), NULL }, - { _T("ISO-8859-7"), _T("ISO8859-7"), _T("iso88597"), _T("8859-7"), NULL }, - { _T("ISO-8859-8"), _T("ISO8859-8"), _T("iso88598"), _T("8859-8"), NULL }, - { _T("ISO-8859-9"), _T("ISO8859-9"), _T("iso88599"), _T("8859-9"), NULL }, - { _T("ISO-8859-10"), _T("ISO8859-10"), _T("iso885910"), _T("8859-10"), NULL }, - { _T("ISO-8859-11"), _T("ISO8859-11"), _T("iso885911"), _T("8859-11"), NULL }, - { _T("ISO-8859-12"), _T("ISO8859-12"), _T("iso885912"), _T("8859-12"), NULL }, - { _T("ISO-8859-13"), _T("ISO8859-13"), _T("iso885913"), _T("8859-13"), NULL }, - { _T("ISO-8859-14"), _T("ISO8859-14"), _T("iso885914"), _T("8859-14"), NULL }, - { _T("ISO-8859-15"), _T("ISO8859-15"), _T("iso885915"), _T("8859-15"), NULL }, - - // although koi8-ru is not strictly speaking the same as koi8-r, - // they are similar enough to make mapping it to koi8 better than - // not recognizing it at all - { wxT( "KOI8-R" ), wxT( "KOI8-RU" ), NULL }, - { wxT( "KOI8-U" ), NULL }, - - { wxT( "WINDOWS-874" ), wxT( "CP-874" ), NULL }, - { wxT( "WINDOWS-932" ), wxT( "CP-932" ), NULL }, - { wxT( "WINDOWS-936" ), wxT( "CP-936" ), NULL }, - { wxT( "WINDOWS-949" ), wxT( "CP-949" ), wxT( "EUC-KR" ), wxT( "eucKR" ), wxT( "euc_kr" ), NULL }, - { wxT( "WINDOWS-950" ), wxT( "CP-950" ), NULL }, - { wxT( "WINDOWS-1250" ),wxT( "CP-1250" ), NULL }, - { wxT( "WINDOWS-1251" ),wxT( "CP-1251" ), NULL }, - { wxT( "WINDOWS-1252" ),wxT( "CP-1252" ), wxT("IBM-1252"), NULL }, - { wxT( "WINDOWS-1253" ),wxT( "CP-1253" ), NULL }, - { wxT( "WINDOWS-1254" ),wxT( "CP-1254" ), NULL }, - { wxT( "WINDOWS-1255" ),wxT( "CP-1255" ), NULL }, - { wxT( "WINDOWS-1256" ),wxT( "CP-1256" ), NULL }, - { wxT( "WINDOWS-1257" ),wxT( "CP-1257" ), NULL }, - { wxT( "WINDOWS-437" ), wxT( "CP-437" ), NULL }, - - { wxT( "UTF-7" ), wxT("utf7"), NULL }, - { wxT( "UTF-8" ), wxT("utf8"), NULL }, -#ifdef WORDS_BIGENDIAN - { wxT( "UTF-16BE" ), wxT("UCS-2BE"), wxT( "UTF-16" ), wxT("UCS-2"), wxT("UCS2"), NULL }, - { wxT( "UTF-16LE" ), wxT("UCS-2LE"), NULL }, - { wxT( "UTF-32BE" ), wxT( "UCS-4BE" ), wxT( "UTF-32" ), wxT( "UCS-4" ), wxT("UCS4"), NULL }, - { wxT( "UTF-32LE" ), wxT( "UCS-4LE" ), NULL }, -#else // WORDS_BIGENDIAN - { wxT( "UTF-16BE" ), wxT("UCS-2BE"), NULL }, - { wxT( "UTF-16LE" ), wxT("UCS-2LE"), wxT( "UTF-16" ), wxT("UCS-2"), wxT("UCS2"), NULL }, - { wxT( "UTF-32BE" ), wxT( "UCS-4BE" ), NULL }, - { wxT( "UTF-32LE" ), wxT( "UCS-4LE" ), wxT( "UTF-32" ), wxT( "UCS-4" ), wxT("UCS4"), NULL }, -#endif // WORDS_BIGENDIAN - - { wxT( "EUC-JP" ), wxT( "eucJP" ), wxT( "euc_jp" ), wxT( "IBM-eucJP" ), NULL }, - - // 646 is for Solaris, roman8 -- for HP-UX - { wxT( "US-ASCII" ), wxT( "ASCII" ), wxT("C"), wxT("POSIX"), wxT("ANSI_X3.4-1968"), - wxT("646"), wxT("roman8"), wxT( "" ), NULL }, - - { wxT( "BIG5" ), wxT("big5"), NULL }, - { wxT( "SJIS" ), wxT( "SHIFT-JIS" ), wxT( "SHIFT_JIS" ), NULL }, - { wxT( "GB2312" ), NULL }, -}; - -wxCOMPILE_TIME_ASSERT( WXSIZEOF(gs_encodingDescs) == WXSIZEOF(gs_encodings), EncodingsArraysNotInSync ); -wxCOMPILE_TIME_ASSERT( WXSIZEOF(gs_encodingNames) == WXSIZEOF(gs_encodings), EncodingsArraysNotInSync ); - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -// clean up the font mapper object -class wxFontMapperModule : public wxModule -{ -public: - wxFontMapperModule() : wxModule() { } - - virtual bool OnInit() - { - // a dummy wxFontMapperBase object could have been created during the - // program startup before wxApp was created, we have to delete it to - // allow creating the real font mapper next time it is needed now that - // we can create it (when the modules are initialized, wxApp object - // already exists) - wxFontMapperBase *fm = wxFontMapperBase::Get(); - if ( fm && fm->IsDummy() ) - wxFontMapperBase::Reset(); - - return true; - } - - virtual void OnExit() - { - wxFontMapperBase::Reset(); - } - - DECLARE_DYNAMIC_CLASS(wxFontMapperModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxFontMapperModule, wxModule) - - -// ============================================================================ -// wxFontMapperBase implementation -// ============================================================================ - -wxFontMapper *wxFontMapperBase::sm_instance = NULL; - -// ---------------------------------------------------------------------------- -// ctor and dtor -// ---------------------------------------------------------------------------- - -wxFontMapperBase::wxFontMapperBase() -{ -#if wxUSE_CONFIG && wxUSE_FILECONFIG - m_configDummy = NULL; -#endif // wxUSE_CONFIG -} - -wxFontMapperBase::~wxFontMapperBase() -{ -#if wxUSE_CONFIG && wxUSE_FILECONFIG - if ( m_configDummy ) - delete m_configDummy; -#endif // wxUSE_CONFIG -} - -/* static */ -wxFontMapperBase *wxFontMapperBase::Get() -{ - if ( !sm_instance ) - { - wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; - if ( traits ) - { - sm_instance = traits->CreateFontMapper(); - - wxASSERT_MSG( sm_instance, - _T("wxAppTraits::CreateFontMapper() failed") ); - } - - if ( !sm_instance ) - { - // last resort: we must create something because the existing code - // relies on always having a valid font mapper object - sm_instance = (wxFontMapper *)new wxFontMapperBase; - } - } - - return (wxFontMapperBase*)sm_instance; -} - -/* static */ -wxFontMapper *wxFontMapperBase::Set(wxFontMapper *mapper) -{ - wxFontMapper *old = sm_instance; - sm_instance = mapper; - return old; -} - -/* static */ -void wxFontMapperBase::Reset() -{ - if ( sm_instance ) - { - // we need a cast as wxFontMapper is not fully declared here and so the - // compiler can't know that it derives from wxFontMapperBase (but - // run-time behaviour will be correct because the dtor is virtual) - delete (wxFontMapperBase *)sm_instance; - sm_instance = NULL; - } -} - -#if wxUSE_CONFIG && wxUSE_FILECONFIG - -// ---------------------------------------------------------------------------- -// config usage customisation -// ---------------------------------------------------------------------------- - -/* static */ -const wxChar *wxFontMapperBase::GetDefaultConfigPath() -{ - return FONTMAPPER_ROOT_PATH; -} - -void wxFontMapperBase::SetConfigPath(const wxString& prefix) -{ - wxCHECK_RET( !prefix.empty() && prefix[0] == wxCONFIG_PATH_SEPARATOR, - wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") ); - - m_configRootPath = prefix; -} - -// ---------------------------------------------------------------------------- -// get config object and path for it -// ---------------------------------------------------------------------------- - -wxConfigBase *wxFontMapperBase::GetConfig() -{ - wxConfigBase *config = wxConfig::Get(false); - - // If there is no global configuration, use an internal memory configuration - if ( !config ) - { - if ( !m_configDummy ) - m_configDummy = new wxMemoryConfig; - config = m_configDummy; - - // FIXME: ideally, we should add keys from dummy config to a real one later, - // but it is a low-priority task because typical wxWin application - // either doesn't use wxConfig at all or creates wxConfig object in - // wxApp::OnInit(), before any real interaction with the user takes - // place... - } - - return config; -} - -const wxString& wxFontMapperBase::GetConfigPath() -{ - if ( !m_configRootPath ) - { - // use the default - m_configRootPath = GetDefaultConfigPath(); - } - - return m_configRootPath; -} - -// ---------------------------------------------------------------------------- -// config helpers -// ---------------------------------------------------------------------------- - -bool wxFontMapperBase::ChangePath(const wxString& pathNew, wxString *pathOld) -{ - wxConfigBase *config = GetConfig(); - if ( !config ) - return false; - - *pathOld = config->GetPath(); - - wxString path = GetConfigPath(); - if ( path.empty() || path.Last() != wxCONFIG_PATH_SEPARATOR ) - { - path += wxCONFIG_PATH_SEPARATOR; - } - - wxASSERT_MSG( !pathNew || (pathNew[0] != wxCONFIG_PATH_SEPARATOR), - wxT("should be a relative path") ); - - path += pathNew; - - config->SetPath(path); - - return true; -} - -void wxFontMapperBase::RestorePath(const wxString& pathOld) -{ - GetConfig()->SetPath(pathOld); -} - -#endif - -// ---------------------------------------------------------------------------- -// charset/encoding correspondence -// ---------------------------------------------------------------------------- - -wxFontEncoding -wxFontMapperBase::CharsetToEncoding(const wxString& charset, - bool WXUNUSED(interactive)) -{ - int enc = NonInteractiveCharsetToEncoding(charset); - if ( enc == wxFONTENCODING_UNKNOWN ) - { - // we should return wxFONTENCODING_SYSTEM from here for unknown - // encodings - enc = wxFONTENCODING_SYSTEM; - } - - return (wxFontEncoding)enc; -} - -int -wxFontMapperBase::NonInteractiveCharsetToEncoding(const wxString& charset) -{ - wxFontEncoding encoding = wxFONTENCODING_SYSTEM; - - // we're going to modify it, make a copy - wxString cs = charset; - -#if wxUSE_CONFIG && wxUSE_FILECONFIG - // first try the user-defined settings - wxFontMapperPathChanger path(this, FONTMAPPER_CHARSET_PATH); - if ( path.IsOk() ) - { - wxConfigBase *config = GetConfig(); - - // do we have an encoding for this charset? - long value = config->Read(charset, -1l); - if ( value != -1 ) - { - if ( value == wxFONTENCODING_UNKNOWN ) - { - // don't try to find it, in particular don't ask the user - return value; - } - - if ( value >= 0 && value <= wxFONTENCODING_MAX ) - { - encoding = (wxFontEncoding)value; - } - else - { - wxLogDebug(wxT("corrupted config data: invalid encoding %ld for charset '%s' ignored"), - value, charset.c_str()); - } - } - - if ( encoding == wxFONTENCODING_SYSTEM ) - { - // may be we have an alias? - config->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH); - - wxString alias = config->Read(charset); - if ( !alias.empty() ) - { - // yes, we do - use it instead - cs = alias; - } - } - } -#endif // wxUSE_CONFIG - - // if didn't find it there, try to recognize it ourselves - if ( encoding == wxFONTENCODING_SYSTEM ) - { - // trim any spaces - cs.Trim(true); - cs.Trim(false); - - // discard the optional quotes - if ( !cs.empty() ) - { - if ( cs[0u] == _T('"') && cs.Last() == _T('"') ) - { - cs = wxString(cs.c_str(), cs.length() - 1); - } - } - - for ( size_t i = 0; i < WXSIZEOF(gs_encodingNames); ++i ) - { - for ( const wxChar** encName = gs_encodingNames[i]; *encName; ++encName ) - { - if ( cs.CmpNoCase(*encName) == 0 ) - return gs_encodings[i]; - } - } - - cs.MakeUpper(); - - if ( cs.Left(3) == wxT("ISO") ) - { - // the dash is optional (or, to be exact, it is not, but - // several brokenmails "forget" it) - const wxChar *p = cs.c_str() + 3; - if ( *p == wxT('-') ) - p++; - - // printf( "iso %s\n", (const char*) cs.ToAscii() ); - - unsigned int value; - if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 ) - { - // printf( "value %d\n", (int)value ); - - // make it 0 based and check that it is strictly positive in - // the process (no such thing as iso8859-0 encoding) - if ( (value-- > 0) && - (value < wxFONTENCODING_ISO8859_MAX - - wxFONTENCODING_ISO8859_1) ) - { - // it's a valid ISO8859 encoding - value += wxFONTENCODING_ISO8859_1; - encoding = (wxFontEncoding)value; - } - } - } - else if ( cs.Left(4) == wxT("8859") ) - { - const wxChar *p = cs.c_str(); - - unsigned int value; - if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 ) - { - // printf( "value %d\n", (int)value ); - - // make it 0 based and check that it is strictly positive in - // the process (no such thing as iso8859-0 encoding) - if ( (value-- > 0) && - (value < wxFONTENCODING_ISO8859_MAX - - wxFONTENCODING_ISO8859_1) ) - { - // it's a valid ISO8859 encoding - value += wxFONTENCODING_ISO8859_1; - encoding = (wxFontEncoding)value; - } - } - } - else // check for Windows charsets - { - size_t len; - if ( cs.Left(7) == wxT("WINDOWS") ) - { - len = 7; - } - else if ( cs.Left(2) == wxT("CP") ) - { - len = 2; - } - else // not a Windows encoding - { - len = 0; - } - - if ( len ) - { - const wxChar *p = cs.c_str() + len; - if ( *p == wxT('-') ) - p++; - - unsigned int value; - if ( wxSscanf(p, wxT("%u"), &value) == 1 ) - { - if ( value >= 1250 ) - { - value -= 1250; - if ( value < wxFONTENCODING_CP12_MAX - - wxFONTENCODING_CP1250 ) - { - // a valid Windows code page - value += wxFONTENCODING_CP1250; - encoding = (wxFontEncoding)value; - } - } - - switch ( value ) - { - case 866: - encoding = wxFONTENCODING_CP866; - break; - - case 874: - encoding = wxFONTENCODING_CP874; - break; - - case 932: - encoding = wxFONTENCODING_CP932; - break; - - case 936: - encoding = wxFONTENCODING_CP936; - break; - - case 949: - encoding = wxFONTENCODING_CP949; - break; - - case 950: - encoding = wxFONTENCODING_CP950; - break; - } - } - } - } - //else: unknown - } - - return encoding; -} - -/* static */ -size_t wxFontMapperBase::GetSupportedEncodingsCount() -{ - return WXSIZEOF(gs_encodings); -} - -/* static */ -wxFontEncoding wxFontMapperBase::GetEncoding(size_t n) -{ - wxCHECK_MSG( n < WXSIZEOF(gs_encodings), wxFONTENCODING_SYSTEM, - _T("wxFontMapper::GetEncoding(): invalid index") ); - - return gs_encodings[n]; -} - -/* static */ -wxString wxFontMapperBase::GetEncodingDescription(wxFontEncoding encoding) -{ - if ( encoding == wxFONTENCODING_DEFAULT ) - { - return _("Default encoding"); - } - - const size_t count = WXSIZEOF(gs_encodingDescs); - - for ( size_t i = 0; i < count; i++ ) - { - if ( gs_encodings[i] == encoding ) - { - return wxGetTranslation(gs_encodingDescs[i]); - } - } - - wxString str; - str.Printf(_("Unknown encoding (%d)"), encoding); - - return str; -} - -/* static */ -wxString wxFontMapperBase::GetEncodingName(wxFontEncoding encoding) -{ - if ( encoding == wxFONTENCODING_DEFAULT ) - { - return _("default"); - } - - const size_t count = WXSIZEOF(gs_encodingNames); - - for ( size_t i = 0; i < count; i++ ) - { - if ( gs_encodings[i] == encoding ) - { - return gs_encodingNames[i][0]; - } - } - - wxString str; - str.Printf(_("unknown-%d"), encoding); - - return str; -} - -/* static */ -const wxChar** wxFontMapperBase::GetAllEncodingNames(wxFontEncoding encoding) -{ - static const wxChar* dummy[] = { NULL }; - - for ( size_t i = 0; i < WXSIZEOF(gs_encodingNames); i++ ) - { - if ( gs_encodings[i] == encoding ) - { - return gs_encodingNames[i]; - } - } - - return dummy; -} - -/* static */ -wxFontEncoding wxFontMapperBase::GetEncodingFromName(const wxString& name) -{ - const size_t count = WXSIZEOF(gs_encodingNames); - - for ( size_t i = 0; i < count; i++ ) - { - for ( const wxChar** encName = gs_encodingNames[i]; *encName; ++encName ) - { - if ( name.CmpNoCase(*encName) == 0 ) - return gs_encodings[i]; - } - } - - return wxFONTENCODING_MAX; -} - -#endif // wxUSE_FONTMAP +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/fmapbase.cpp +// Purpose: wxFontMapperBase class implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 21.06.2003 (extracted from common/fontmap.cpp) +// RCS-ID: $Id: fmapbase.cpp 43063 2006-11-04 20:48:04Z VZ $ +// Copyright: (c) 1999-2003 Vadim Zeitlin +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FONTMAP + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/module.h" +#endif //WX_PRECOMP + +#if defined(__WXMSW__) + #include "wx/msw/private.h" // includes windows.h for LOGFONT + #include "wx/msw/winundef.h" +#endif + +#include "wx/fontmap.h" +#include "wx/fmappriv.h" + +#include "wx/apptrait.h" + +// wxMemoryConfig uses wxFileConfig +#if wxUSE_CONFIG && wxUSE_FILECONFIG + #include "wx/config.h" + #include "wx/memconf.h" +#endif + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// encodings supported by GetEncodingDescription +static wxFontEncoding gs_encodings[] = +{ + wxFONTENCODING_ISO8859_1, + wxFONTENCODING_ISO8859_2, + wxFONTENCODING_ISO8859_3, + wxFONTENCODING_ISO8859_4, + wxFONTENCODING_ISO8859_5, + wxFONTENCODING_ISO8859_6, + wxFONTENCODING_ISO8859_7, + wxFONTENCODING_ISO8859_8, + wxFONTENCODING_ISO8859_9, + wxFONTENCODING_ISO8859_10, + wxFONTENCODING_ISO8859_11, + wxFONTENCODING_ISO8859_12, + wxFONTENCODING_ISO8859_13, + wxFONTENCODING_ISO8859_14, + wxFONTENCODING_ISO8859_15, + wxFONTENCODING_KOI8, + wxFONTENCODING_KOI8_U, + wxFONTENCODING_CP874, + wxFONTENCODING_CP932, + wxFONTENCODING_CP936, + wxFONTENCODING_CP949, + wxFONTENCODING_CP950, + wxFONTENCODING_CP1250, + wxFONTENCODING_CP1251, + wxFONTENCODING_CP1252, + wxFONTENCODING_CP1253, + wxFONTENCODING_CP1254, + wxFONTENCODING_CP1255, + wxFONTENCODING_CP1256, + wxFONTENCODING_CP1257, + wxFONTENCODING_CP437, + wxFONTENCODING_UTF7, + wxFONTENCODING_UTF8, + wxFONTENCODING_UTF16BE, + wxFONTENCODING_UTF16LE, + wxFONTENCODING_UTF32BE, + wxFONTENCODING_UTF32LE, + wxFONTENCODING_EUC_JP, + wxFONTENCODING_DEFAULT, + wxFONTENCODING_BIG5, + wxFONTENCODING_SHIFT_JIS, + wxFONTENCODING_GB2312, +}; + +// the descriptions for them +static const wxChar* gs_encodingDescs[] = +{ + wxTRANSLATE( "Western European (ISO-8859-1)" ), + wxTRANSLATE( "Central European (ISO-8859-2)" ), + wxTRANSLATE( "Esperanto (ISO-8859-3)" ), + wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ), + wxTRANSLATE( "Cyrillic (ISO-8859-5)" ), + wxTRANSLATE( "Arabic (ISO-8859-6)" ), + wxTRANSLATE( "Greek (ISO-8859-7)" ), + wxTRANSLATE( "Hebrew (ISO-8859-8)" ), + wxTRANSLATE( "Turkish (ISO-8859-9)" ), + wxTRANSLATE( "Nordic (ISO-8859-10)" ), + wxTRANSLATE( "Thai (ISO-8859-11)" ), + wxTRANSLATE( "Indian (ISO-8859-12)" ), + wxTRANSLATE( "Baltic (ISO-8859-13)" ), + wxTRANSLATE( "Celtic (ISO-8859-14)" ), + wxTRANSLATE( "Western European with Euro (ISO-8859-15)" ), + wxTRANSLATE( "KOI8-R" ), + wxTRANSLATE( "KOI8-U" ), + wxTRANSLATE( "Windows Thai (CP 874)" ), + wxTRANSLATE( "Windows Japanese (CP 932)" ), + wxTRANSLATE( "Windows Chinese Simplified (CP 936)" ), + wxTRANSLATE( "Windows Korean (CP 949)" ), + wxTRANSLATE( "Windows Chinese Traditional (CP 950)" ), + wxTRANSLATE( "Windows Central European (CP 1250)" ), + wxTRANSLATE( "Windows Cyrillic (CP 1251)" ), + wxTRANSLATE( "Windows Western European (CP 1252)" ), + wxTRANSLATE( "Windows Greek (CP 1253)" ), + wxTRANSLATE( "Windows Turkish (CP 1254)" ), + wxTRANSLATE( "Windows Hebrew (CP 1255)" ), + wxTRANSLATE( "Windows Arabic (CP 1256)" ), + wxTRANSLATE( "Windows Baltic (CP 1257)" ), + wxTRANSLATE( "Windows/DOS OEM (CP 437)" ), + wxTRANSLATE( "Unicode 7 bit (UTF-7)" ), + wxTRANSLATE( "Unicode 8 bit (UTF-8)" ), +#ifdef WORDS_BIGENDIAN + wxTRANSLATE( "Unicode 16 bit (UTF-16)" ), + wxTRANSLATE( "Unicode 16 bit Little Endian (UTF-16LE)" ), + wxTRANSLATE( "Unicode 32 bit (UTF-32)" ), + wxTRANSLATE( "Unicode 32 bit Little Endian (UTF-32LE)" ), +#else // WORDS_BIGENDIAN + wxTRANSLATE( "Unicode 16 bit Big Endian (UTF-16BE)" ), + wxTRANSLATE( "Unicode 16 bit (UTF-16)" ), + wxTRANSLATE( "Unicode 32 bit Big Endian (UTF-32BE)" ), + wxTRANSLATE( "Unicode 32 bit (UTF-32)" ), +#endif // WORDS_BIGENDIAN + wxTRANSLATE( "Extended Unix Codepage for Japanese (EUC-JP)" ), + wxTRANSLATE( "US-ASCII" ), + wxTRANSLATE( "BIG5" ), + wxTRANSLATE( "SHIFT-JIS" ), + wxTRANSLATE( "GB-2312" ), +}; + +// and the internal names (these are not translated on purpose!) +static const wxChar* gs_encodingNames[WXSIZEOF(gs_encodingDescs)][9] = +{ + // names from the columns correspond to these OS: + // Linux Solaris and IRIX HP-UX AIX + { _T("ISO-8859-1"), _T("ISO8859-1"), _T("iso88591"), _T("8859-1"), wxT("iso_8859_1"), NULL }, + { _T("ISO-8859-2"), _T("ISO8859-2"), _T("iso88592"), _T("8859-2"), NULL }, + { _T("ISO-8859-3"), _T("ISO8859-3"), _T("iso88593"), _T("8859-3"), NULL }, + { _T("ISO-8859-4"), _T("ISO8859-4"), _T("iso88594"), _T("8859-4"), NULL }, + { _T("ISO-8859-5"), _T("ISO8859-5"), _T("iso88595"), _T("8859-5"), NULL }, + { _T("ISO-8859-6"), _T("ISO8859-6"), _T("iso88596"), _T("8859-6"), NULL }, + { _T("ISO-8859-7"), _T("ISO8859-7"), _T("iso88597"), _T("8859-7"), NULL }, + { _T("ISO-8859-8"), _T("ISO8859-8"), _T("iso88598"), _T("8859-8"), NULL }, + { _T("ISO-8859-9"), _T("ISO8859-9"), _T("iso88599"), _T("8859-9"), NULL }, + { _T("ISO-8859-10"), _T("ISO8859-10"), _T("iso885910"), _T("8859-10"), NULL }, + { _T("ISO-8859-11"), _T("ISO8859-11"), _T("iso885911"), _T("8859-11"), NULL }, + { _T("ISO-8859-12"), _T("ISO8859-12"), _T("iso885912"), _T("8859-12"), NULL }, + { _T("ISO-8859-13"), _T("ISO8859-13"), _T("iso885913"), _T("8859-13"), NULL }, + { _T("ISO-8859-14"), _T("ISO8859-14"), _T("iso885914"), _T("8859-14"), NULL }, + { _T("ISO-8859-15"), _T("ISO8859-15"), _T("iso885915"), _T("8859-15"), NULL }, + + // although koi8-ru is not strictly speaking the same as koi8-r, + // they are similar enough to make mapping it to koi8 better than + // not recognizing it at all + { wxT( "KOI8-R" ), wxT( "KOI8-RU" ), NULL }, + { wxT( "KOI8-U" ), NULL }, + + { wxT( "WINDOWS-874" ), wxT( "CP-874" ), NULL }, + { wxT( "WINDOWS-932" ), wxT( "CP-932" ), NULL }, + { wxT( "WINDOWS-936" ), wxT( "CP-936" ), NULL }, + { wxT( "WINDOWS-949" ), wxT( "CP-949" ), wxT( "EUC-KR" ), wxT( "eucKR" ), wxT( "euc_kr" ), NULL }, + { wxT( "WINDOWS-950" ), wxT( "CP-950" ), NULL }, + { wxT( "WINDOWS-1250" ),wxT( "CP-1250" ), NULL }, + { wxT( "WINDOWS-1251" ),wxT( "CP-1251" ), NULL }, + { wxT( "WINDOWS-1252" ),wxT( "CP-1252" ), wxT("IBM-1252"), NULL }, + { wxT( "WINDOWS-1253" ),wxT( "CP-1253" ), NULL }, + { wxT( "WINDOWS-1254" ),wxT( "CP-1254" ), NULL }, + { wxT( "WINDOWS-1255" ),wxT( "CP-1255" ), NULL }, + { wxT( "WINDOWS-1256" ),wxT( "CP-1256" ), NULL }, + { wxT( "WINDOWS-1257" ),wxT( "CP-1257" ), NULL }, + { wxT( "WINDOWS-437" ), wxT( "CP-437" ), NULL }, + + { wxT( "UTF-7" ), wxT("utf7"), NULL }, + { wxT( "UTF-8" ), wxT("utf8"), NULL }, +#ifdef WORDS_BIGENDIAN + { wxT( "UTF-16BE" ), wxT("UCS-2BE"), wxT( "UTF-16" ), wxT("UCS-2"), wxT("UCS2"), NULL }, + { wxT( "UTF-16LE" ), wxT("UCS-2LE"), NULL }, + { wxT( "UTF-32BE" ), wxT( "UCS-4BE" ), wxT( "UTF-32" ), wxT( "UCS-4" ), wxT("UCS4"), NULL }, + { wxT( "UTF-32LE" ), wxT( "UCS-4LE" ), NULL }, +#else // WORDS_BIGENDIAN + { wxT( "UTF-16BE" ), wxT("UCS-2BE"), NULL }, + { wxT( "UTF-16LE" ), wxT("UCS-2LE"), wxT( "UTF-16" ), wxT("UCS-2"), wxT("UCS2"), NULL }, + { wxT( "UTF-32BE" ), wxT( "UCS-4BE" ), NULL }, + { wxT( "UTF-32LE" ), wxT( "UCS-4LE" ), wxT( "UTF-32" ), wxT( "UCS-4" ), wxT("UCS4"), NULL }, +#endif // WORDS_BIGENDIAN + + { wxT( "EUC-JP" ), wxT( "eucJP" ), wxT( "euc_jp" ), wxT( "IBM-eucJP" ), NULL }, + + // 646 is for Solaris, roman8 -- for HP-UX + { wxT( "US-ASCII" ), wxT( "ASCII" ), wxT("C"), wxT("POSIX"), wxT("ANSI_X3.4-1968"), + wxT("646"), wxT("roman8"), wxT( "" ), NULL }, + + { wxT( "BIG5" ), wxT("big5"), NULL }, + { wxT( "SJIS" ), wxT( "SHIFT-JIS" ), wxT( "SHIFT_JIS" ), NULL }, + { wxT( "GB2312" ), NULL }, +}; + +wxCOMPILE_TIME_ASSERT( WXSIZEOF(gs_encodingDescs) == WXSIZEOF(gs_encodings), EncodingsArraysNotInSync ); +wxCOMPILE_TIME_ASSERT( WXSIZEOF(gs_encodingNames) == WXSIZEOF(gs_encodings), EncodingsArraysNotInSync ); + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// clean up the font mapper object +class wxFontMapperModule : public wxModule +{ +public: + wxFontMapperModule() : wxModule() { } + + virtual bool OnInit() + { + // a dummy wxFontMapperBase object could have been created during the + // program startup before wxApp was created, we have to delete it to + // allow creating the real font mapper next time it is needed now that + // we can create it (when the modules are initialized, wxApp object + // already exists) + wxFontMapperBase *fm = wxFontMapperBase::Get(); + if ( fm && fm->IsDummy() ) + wxFontMapperBase::Reset(); + + return true; + } + + virtual void OnExit() + { + wxFontMapperBase::Reset(); + } + + DECLARE_DYNAMIC_CLASS(wxFontMapperModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxFontMapperModule, wxModule) + + +// ============================================================================ +// wxFontMapperBase implementation +// ============================================================================ + +wxFontMapper *wxFontMapperBase::sm_instance = NULL; + +// ---------------------------------------------------------------------------- +// ctor and dtor +// ---------------------------------------------------------------------------- + +wxFontMapperBase::wxFontMapperBase() +{ +#if wxUSE_CONFIG && wxUSE_FILECONFIG + m_configDummy = NULL; +#endif // wxUSE_CONFIG +} + +wxFontMapperBase::~wxFontMapperBase() +{ +#if wxUSE_CONFIG && wxUSE_FILECONFIG + if ( m_configDummy ) + delete m_configDummy; +#endif // wxUSE_CONFIG +} + +/* static */ +wxFontMapperBase *wxFontMapperBase::Get() +{ + if ( !sm_instance ) + { + wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; + if ( traits ) + { + sm_instance = traits->CreateFontMapper(); + + wxASSERT_MSG( sm_instance, + _T("wxAppTraits::CreateFontMapper() failed") ); + } + + if ( !sm_instance ) + { + // last resort: we must create something because the existing code + // relies on always having a valid font mapper object + sm_instance = (wxFontMapper *)new wxFontMapperBase; + } + } + + return (wxFontMapperBase*)sm_instance; +} + +/* static */ +wxFontMapper *wxFontMapperBase::Set(wxFontMapper *mapper) +{ + wxFontMapper *old = sm_instance; + sm_instance = mapper; + return old; +} + +/* static */ +void wxFontMapperBase::Reset() +{ + if ( sm_instance ) + { + // we need a cast as wxFontMapper is not fully declared here and so the + // compiler can't know that it derives from wxFontMapperBase (but + // run-time behaviour will be correct because the dtor is virtual) + delete (wxFontMapperBase *)sm_instance; + sm_instance = NULL; + } +} + +#if wxUSE_CONFIG && wxUSE_FILECONFIG + +// ---------------------------------------------------------------------------- +// config usage customisation +// ---------------------------------------------------------------------------- + +/* static */ +const wxChar *wxFontMapperBase::GetDefaultConfigPath() +{ + return FONTMAPPER_ROOT_PATH; +} + +void wxFontMapperBase::SetConfigPath(const wxString& prefix) +{ + wxCHECK_RET( !prefix.empty() && prefix[0] == wxCONFIG_PATH_SEPARATOR, + wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") ); + + m_configRootPath = prefix; +} + +// ---------------------------------------------------------------------------- +// get config object and path for it +// ---------------------------------------------------------------------------- + +wxConfigBase *wxFontMapperBase::GetConfig() +{ + wxConfigBase *config = wxConfig::Get(false); + + // If there is no global configuration, use an internal memory configuration + if ( !config ) + { + if ( !m_configDummy ) + m_configDummy = new wxMemoryConfig; + config = m_configDummy; + + // FIXME: ideally, we should add keys from dummy config to a real one later, + // but it is a low-priority task because typical wxWin application + // either doesn't use wxConfig at all or creates wxConfig object in + // wxApp::OnInit(), before any real interaction with the user takes + // place... + } + + return config; +} + +const wxString& wxFontMapperBase::GetConfigPath() +{ + if ( !m_configRootPath ) + { + // use the default + m_configRootPath = GetDefaultConfigPath(); + } + + return m_configRootPath; +} + +// ---------------------------------------------------------------------------- +// config helpers +// ---------------------------------------------------------------------------- + +bool wxFontMapperBase::ChangePath(const wxString& pathNew, wxString *pathOld) +{ + wxConfigBase *config = GetConfig(); + if ( !config ) + return false; + + *pathOld = config->GetPath(); + + wxString path = GetConfigPath(); + if ( path.empty() || path.Last() != wxCONFIG_PATH_SEPARATOR ) + { + path += wxCONFIG_PATH_SEPARATOR; + } + + wxASSERT_MSG( !pathNew || (pathNew[0] != wxCONFIG_PATH_SEPARATOR), + wxT("should be a relative path") ); + + path += pathNew; + + config->SetPath(path); + + return true; +} + +void wxFontMapperBase::RestorePath(const wxString& pathOld) +{ + GetConfig()->SetPath(pathOld); +} + +#endif + +// ---------------------------------------------------------------------------- +// charset/encoding correspondence +// ---------------------------------------------------------------------------- + +wxFontEncoding +wxFontMapperBase::CharsetToEncoding(const wxString& charset, + bool WXUNUSED(interactive)) +{ + int enc = NonInteractiveCharsetToEncoding(charset); + if ( enc == wxFONTENCODING_UNKNOWN ) + { + // we should return wxFONTENCODING_SYSTEM from here for unknown + // encodings + enc = wxFONTENCODING_SYSTEM; + } + + return (wxFontEncoding)enc; +} + +int +wxFontMapperBase::NonInteractiveCharsetToEncoding(const wxString& charset) +{ + wxFontEncoding encoding = wxFONTENCODING_SYSTEM; + + // we're going to modify it, make a copy + wxString cs = charset; + +#if wxUSE_CONFIG && wxUSE_FILECONFIG + // first try the user-defined settings + wxFontMapperPathChanger path(this, FONTMAPPER_CHARSET_PATH); + if ( path.IsOk() ) + { + wxConfigBase *config = GetConfig(); + + // do we have an encoding for this charset? + long value = config->Read(charset, -1l); + if ( value != -1 ) + { + if ( value == wxFONTENCODING_UNKNOWN ) + { + // don't try to find it, in particular don't ask the user + return value; + } + + if ( value >= 0 && value <= wxFONTENCODING_MAX ) + { + encoding = (wxFontEncoding)value; + } + else + { + wxLogDebug(wxT("corrupted config data: invalid encoding %ld for charset '%s' ignored"), + value, charset.c_str()); + } + } + + if ( encoding == wxFONTENCODING_SYSTEM ) + { + // may be we have an alias? + config->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH); + + wxString alias = config->Read(charset); + if ( !alias.empty() ) + { + // yes, we do - use it instead + cs = alias; + } + } + } +#endif // wxUSE_CONFIG + + // if didn't find it there, try to recognize it ourselves + if ( encoding == wxFONTENCODING_SYSTEM ) + { + // trim any spaces + cs.Trim(true); + cs.Trim(false); + + // discard the optional quotes + if ( !cs.empty() ) + { + if ( cs[0u] == _T('"') && cs.Last() == _T('"') ) + { + cs = wxString(cs.c_str(), cs.length() - 1); + } + } + + for ( size_t i = 0; i < WXSIZEOF(gs_encodingNames); ++i ) + { + for ( const wxChar** encName = gs_encodingNames[i]; *encName; ++encName ) + { + if ( cs.CmpNoCase(*encName) == 0 ) + return gs_encodings[i]; + } + } + + cs.MakeUpper(); + + if ( cs.Left(3) == wxT("ISO") ) + { + // the dash is optional (or, to be exact, it is not, but + // several brokenmails "forget" it) + const wxChar *p = cs.c_str() + 3; + if ( *p == wxT('-') ) + p++; + + // printf( "iso %s\n", (const char*) cs.ToAscii() ); + + unsigned int value; + if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 ) + { + // printf( "value %d\n", (int)value ); + + // make it 0 based and check that it is strictly positive in + // the process (no such thing as iso8859-0 encoding) + if ( (value-- > 0) && + (value < wxFONTENCODING_ISO8859_MAX - + wxFONTENCODING_ISO8859_1) ) + { + // it's a valid ISO8859 encoding + value += wxFONTENCODING_ISO8859_1; + encoding = (wxFontEncoding)value; + } + } + } + else if ( cs.Left(4) == wxT("8859") ) + { + const wxChar *p = cs.c_str(); + + unsigned int value; + if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 ) + { + // printf( "value %d\n", (int)value ); + + // make it 0 based and check that it is strictly positive in + // the process (no such thing as iso8859-0 encoding) + if ( (value-- > 0) && + (value < wxFONTENCODING_ISO8859_MAX - + wxFONTENCODING_ISO8859_1) ) + { + // it's a valid ISO8859 encoding + value += wxFONTENCODING_ISO8859_1; + encoding = (wxFontEncoding)value; + } + } + } + else // check for Windows charsets + { + size_t len; + if ( cs.Left(7) == wxT("WINDOWS") ) + { + len = 7; + } + else if ( cs.Left(2) == wxT("CP") ) + { + len = 2; + } + else // not a Windows encoding + { + len = 0; + } + + if ( len ) + { + const wxChar *p = cs.c_str() + len; + if ( *p == wxT('-') ) + p++; + + unsigned int value; + if ( wxSscanf(p, wxT("%u"), &value) == 1 ) + { + if ( value >= 1250 ) + { + value -= 1250; + if ( value < wxFONTENCODING_CP12_MAX - + wxFONTENCODING_CP1250 ) + { + // a valid Windows code page + value += wxFONTENCODING_CP1250; + encoding = (wxFontEncoding)value; + } + } + + switch ( value ) + { + case 866: + encoding = wxFONTENCODING_CP866; + break; + + case 874: + encoding = wxFONTENCODING_CP874; + break; + + case 932: + encoding = wxFONTENCODING_CP932; + break; + + case 936: + encoding = wxFONTENCODING_CP936; + break; + + case 949: + encoding = wxFONTENCODING_CP949; + break; + + case 950: + encoding = wxFONTENCODING_CP950; + break; + } + } + } + } + //else: unknown + } + + return encoding; +} + +/* static */ +size_t wxFontMapperBase::GetSupportedEncodingsCount() +{ + return WXSIZEOF(gs_encodings); +} + +/* static */ +wxFontEncoding wxFontMapperBase::GetEncoding(size_t n) +{ + wxCHECK_MSG( n < WXSIZEOF(gs_encodings), wxFONTENCODING_SYSTEM, + _T("wxFontMapper::GetEncoding(): invalid index") ); + + return gs_encodings[n]; +} + +/* static */ +wxString wxFontMapperBase::GetEncodingDescription(wxFontEncoding encoding) +{ + if ( encoding == wxFONTENCODING_DEFAULT ) + { + return _("Default encoding"); + } + + const size_t count = WXSIZEOF(gs_encodingDescs); + + for ( size_t i = 0; i < count; i++ ) + { + if ( gs_encodings[i] == encoding ) + { + return wxGetTranslation(gs_encodingDescs[i]); + } + } + + wxString str; + str.Printf(_("Unknown encoding (%d)"), encoding); + + return str; +} + +/* static */ +wxString wxFontMapperBase::GetEncodingName(wxFontEncoding encoding) +{ + if ( encoding == wxFONTENCODING_DEFAULT ) + { + return _("default"); + } + + const size_t count = WXSIZEOF(gs_encodingNames); + + for ( size_t i = 0; i < count; i++ ) + { + if ( gs_encodings[i] == encoding ) + { + return gs_encodingNames[i][0]; + } + } + + wxString str; + str.Printf(_("unknown-%d"), encoding); + + return str; +} + +/* static */ +const wxChar** wxFontMapperBase::GetAllEncodingNames(wxFontEncoding encoding) +{ + static const wxChar* dummy[] = { NULL }; + + for ( size_t i = 0; i < WXSIZEOF(gs_encodingNames); i++ ) + { + if ( gs_encodings[i] == encoding ) + { + return gs_encodingNames[i]; + } + } + + return dummy; +} + +/* static */ +wxFontEncoding wxFontMapperBase::GetEncodingFromName(const wxString& name) +{ + const size_t count = WXSIZEOF(gs_encodingNames); + + for ( size_t i = 0; i < count; i++ ) + { + for ( const wxChar** encName = gs_encodingNames[i]; *encName; ++encName ) + { + if ( name.CmpNoCase(*encName) == 0 ) + return gs_encodings[i]; + } + } + + return wxFONTENCODING_MAX; +} + +#endif // wxUSE_FONTMAP diff --git a/Source/3rd Party/wx/src/common/fontcmn.cpp b/Source/3rd Party/wx/src/common/fontcmn.cpp index fe34d8a52..f88b54dcb 100644 --- a/Source/3rd Party/wx/src/common/fontcmn.cpp +++ b/Source/3rd Party/wx/src/common/fontcmn.cpp @@ -1,784 +1,784 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fontcmn.cpp -// Purpose: implementation of wxFontBase methods -// Author: Vadim Zeitlin -// Modified by: -// Created: 20.09.99 -// RCS-ID: $Id: fontcmn.cpp 43661 2006-11-26 20:18:53Z VZ $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/font.h" - -#ifndef WX_PRECOMP - #include "wx/dc.h" - #include "wx/intl.h" - #include "wx/dcscreen.h" - #include "wx/log.h" - #include "wx/gdicmn.h" -#endif // WX_PRECOMP - -#if defined(__WXMSW__) - #include "wx/msw/private.h" // includes windows.h for LOGFONT - #include "wx/msw/winundef.h" -#endif - -#include "wx/fontutil.h" // for wxNativeFontInfo -#include "wx/fontmap.h" -#include "wx/fontenum.h" - -#include "wx/tokenzr.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// helper functions -// ---------------------------------------------------------------------------- - -static void AdjustFontSize(wxFont& font, wxDC& dc, const wxSize& pixelSize) -{ - int currentSize = 0; - int largestGood = 0; - int smallestBad = 0; - - bool initialGoodFound = false; - bool initialBadFound = false; - - // NB: this assignment was separated from the variable definition - // in order to fix a gcc v3.3.3 compiler crash - currentSize = font.GetPointSize(); - while (currentSize > 0) - { - dc.SetFont(font); - - // if currentSize (in points) results in a font that is smaller - // than required by pixelSize it is considered a good size - if (dc.GetCharHeight() <= pixelSize.GetHeight() && - (!pixelSize.GetWidth() || - dc.GetCharWidth() <= pixelSize.GetWidth())) - { - largestGood = currentSize; - initialGoodFound = true; - } - else - { - smallestBad = currentSize; - initialBadFound = true; - } - if (!initialGoodFound) - { - currentSize /= 2; - } - else if (!initialBadFound) - { - currentSize *= 2; - } - else - { - int distance = smallestBad - largestGood; - if (distance == 1) - break; - - currentSize = largestGood + distance / 2; - } - - font.SetPointSize(currentSize); - } - - if (currentSize != largestGood) - font.SetPointSize(largestGood); -} - -// ---------------------------------------------------------------------------- -// wxFontBase -// ---------------------------------------------------------------------------- - -wxFontEncoding wxFontBase::ms_encodingDefault = wxFONTENCODING_SYSTEM; - -/* static */ -void wxFontBase::SetDefaultEncoding(wxFontEncoding encoding) -{ - // GetDefaultEncoding() should return something != wxFONTENCODING_DEFAULT - // and, besides, using this value here doesn't make any sense - wxCHECK_RET( encoding != wxFONTENCODING_DEFAULT, - _T("can't set default encoding to wxFONTENCODING_DEFAULT") ); - - ms_encodingDefault = encoding; -} - -wxFontBase::~wxFontBase() -{ - // this destructor is required for Darwin -} - -/* static */ -wxFont *wxFontBase::New(int size, - int family, - int style, - int weight, - bool underlined, - const wxString& face, - wxFontEncoding encoding) -{ - return new wxFont(size, family, style, weight, underlined, face, encoding); -} - -static inline int flags2Style(int flags) -{ - return flags & wxFONTFLAG_ITALIC - ? wxFONTSTYLE_ITALIC - : flags & wxFONTFLAG_SLANT - ? wxFONTSTYLE_SLANT - : wxFONTSTYLE_NORMAL; -} - -static inline int flags2Weight(int flags) -{ - return flags & wxFONTFLAG_LIGHT - ? wxFONTWEIGHT_LIGHT - : flags & wxFONTFLAG_BOLD - ? wxFONTWEIGHT_BOLD - : wxFONTWEIGHT_NORMAL; -} - -static inline bool flags2Underlined(int flags) -{ - return (flags & wxFONTFLAG_UNDERLINED) != 0; -} - -/* static */ -wxFont *wxFontBase::New(int pointSize, - wxFontFamily family, - int flags, - const wxString& face, - wxFontEncoding encoding) -{ - return New(pointSize, family, flags2Style(flags), flags2Weight(flags), - flags2Underlined(flags), face, encoding); -} - -/* static */ -wxFont *wxFontBase::New(const wxSize& pixelSize, - int family, - int style, - int weight, - bool underlined, - const wxString& face, - wxFontEncoding encoding) -{ -#if defined(__WXMSW__) - return new wxFont(pixelSize, family, style, weight, underlined, - face, encoding); -#else - wxFont *self = New(10, family, style, weight, underlined, face, encoding); - wxScreenDC dc; - AdjustFontSize(*(wxFont *)self, dc, pixelSize); - return self; -#endif -} - -/* static */ -wxFont *wxFontBase::New(const wxSize& pixelSize, - wxFontFamily family, - int flags, - const wxString& face, - wxFontEncoding encoding) -{ - return New(pixelSize, family, flags2Style(flags), flags2Weight(flags), - flags2Underlined(flags), face, encoding); -} - -wxSize wxFontBase::GetPixelSize() const -{ - wxScreenDC dc; - dc.SetFont(*(wxFont *)this); - return wxSize(dc.GetCharWidth(), dc.GetCharHeight()); -} - -bool wxFontBase::IsUsingSizeInPixels() const -{ - return false; -} - -void wxFontBase::SetPixelSize( const wxSize& pixelSize ) -{ - wxScreenDC dc; - AdjustFontSize(*(wxFont *)this, dc, pixelSize); -} - -/* static */ -wxFont *wxFontBase::New(const wxNativeFontInfo& info) -{ - return new wxFont(info); -} - -/* static */ -wxFont *wxFontBase::New(const wxString& strNativeFontDesc) -{ - wxNativeFontInfo fontInfo; - if ( !fontInfo.FromString(strNativeFontDesc) ) - return new wxFont(*wxNORMAL_FONT); - - return New(fontInfo); -} - -bool wxFontBase::IsFixedWidth() const -{ - return GetFamily() == wxFONTFAMILY_TELETYPE; -} - -void wxFontBase::DoSetNativeFontInfo(const wxNativeFontInfo& info) -{ -#ifdef wxNO_NATIVE_FONTINFO - SetPointSize(info.pointSize); - SetFamily(info.family); - SetStyle(info.style); - SetWeight(info.weight); - SetUnderlined(info.underlined); - SetFaceName(info.faceName); - SetEncoding(info.encoding); -#else - (void)info; -#endif -} - -wxString wxFontBase::GetNativeFontInfoDesc() const -{ - wxString fontDesc; - const wxNativeFontInfo *fontInfo = GetNativeFontInfo(); - if ( fontInfo ) - { - fontDesc = fontInfo->ToString(); - wxASSERT_MSG(!fontDesc.empty(), wxT("This should be a non-empty string!")); - } - else - { - wxFAIL_MSG(wxT("Derived class should have created the wxNativeFontInfo!")); - } - - return fontDesc; -} - -wxString wxFontBase::GetNativeFontInfoUserDesc() const -{ - wxString fontDesc; - const wxNativeFontInfo *fontInfo = GetNativeFontInfo(); - if ( fontInfo ) - { - fontDesc = fontInfo->ToUserString(); - wxASSERT_MSG(!fontDesc.empty(), wxT("This should be a non-empty string!")); - } - else - { - wxFAIL_MSG(wxT("Derived class should have created the wxNativeFontInfo!")); - } - - return fontDesc; -} - -bool wxFontBase::SetNativeFontInfo(const wxString& info) -{ - wxNativeFontInfo fontInfo; - if ( !info.empty() && fontInfo.FromString(info) ) - { - SetNativeFontInfo(fontInfo); - return true; - } - - UnRef(); - return false; -} - -bool wxFontBase::SetNativeFontInfoUserDesc(const wxString& info) -{ - wxNativeFontInfo fontInfo; - if ( !info.empty() && fontInfo.FromUserString(info) ) - { - SetNativeFontInfo(fontInfo); - return true; - } - - UnRef(); - return false; -} - -bool wxFontBase::operator==(const wxFont& font) const -{ - // either it is the same font, i.e. they share the same common data or they - // have different ref datas but still describe the same font - return IsSameAs(font) || - ( - Ok() == font.Ok() && - GetPointSize() == font.GetPointSize() && - // in wxGTK1 GetPixelSize() calls GetInternalFont() which uses - // operator==() resulting in infinite recursion so we can't use it - // in that port -#if !defined(__WXGTK__) || defined(__WXGTK20__) - GetPixelSize() == font.GetPixelSize() && -#endif - GetFamily() == font.GetFamily() && - GetStyle() == font.GetStyle() && - GetWeight() == font.GetWeight() && - GetUnderlined() == font.GetUnderlined() && - GetFaceName().IsSameAs(font.GetFaceName(), false) && - GetEncoding() == font.GetEncoding() - ); -} - -bool wxFontBase::operator!=(const wxFont& font) const -{ - return !(*this == font); -} - -wxString wxFontBase::GetFamilyString() const -{ - wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") ); - - switch ( GetFamily() ) - { - case wxDECORATIVE: return wxT("wxDECORATIVE"); - case wxROMAN: return wxT("wxROMAN"); - case wxSCRIPT: return wxT("wxSCRIPT"); - case wxSWISS: return wxT("wxSWISS"); - case wxMODERN: return wxT("wxMODERN"); - case wxTELETYPE: return wxT("wxTELETYPE"); - default: return wxT("wxDEFAULT"); - } -} - -wxString wxFontBase::GetStyleString() const -{ - wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") ); - - switch ( GetStyle() ) - { - case wxNORMAL: return wxT("wxNORMAL"); - case wxSLANT: return wxT("wxSLANT"); - case wxITALIC: return wxT("wxITALIC"); - default: return wxT("wxDEFAULT"); - } -} - -wxString wxFontBase::GetWeightString() const -{ - wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") ); - - switch ( GetWeight() ) - { - case wxNORMAL: return wxT("wxNORMAL"); - case wxBOLD: return wxT("wxBOLD"); - case wxLIGHT: return wxT("wxLIGHT"); - default: return wxT("wxDEFAULT"); - } -} - -bool wxFontBase::SetFaceName(const wxString &facename) -{ - if (!wxFontEnumerator::IsValidFacename(facename)) - { - UnRef(); // make Ok() return false - return false; - } - - return true; -} - - -// ---------------------------------------------------------------------------- -// wxNativeFontInfo -// ---------------------------------------------------------------------------- - -// Up to now, there are no native implementations of this function: -void wxNativeFontInfo::SetFaceName(const wxArrayString &facenames) -{ - for (size_t i=0; i < facenames.GetCount(); i++) - { - if (wxFontEnumerator::IsValidFacename(facenames[i])) - { - SetFaceName(facenames[i]); - return; - } - } - - // set the first valid facename we can find on this system - wxString validfacename = wxFontEnumerator::GetFacenames().Item(0); - wxLogTrace(wxT("font"), wxT("Falling back to '%s'"), validfacename.c_str()); - SetFaceName(validfacename); -} - - -#ifdef wxNO_NATIVE_FONTINFO - -// These are the generic forms of FromString()/ToString. -// -// convert to/from the string representation: format is -// version;pointsize;family;style;weight;underlined;facename;encoding - -bool wxNativeFontInfo::FromString(const wxString& s) -{ - long l; - - wxStringTokenizer tokenizer(s, _T(";")); - - wxString token = tokenizer.GetNextToken(); - // - // Ignore the version for now - // - - token = tokenizer.GetNextToken(); - if ( !token.ToLong(&l) ) - return false; - pointSize = (int)l; - - token = tokenizer.GetNextToken(); - if ( !token.ToLong(&l) ) - return false; - family = (wxFontFamily)l; - - token = tokenizer.GetNextToken(); - if ( !token.ToLong(&l) ) - return false; - style = (wxFontStyle)l; - - token = tokenizer.GetNextToken(); - if ( !token.ToLong(&l) ) - return false; - weight = (wxFontWeight)l; - - token = tokenizer.GetNextToken(); - if ( !token.ToLong(&l) ) - return false; - underlined = l != 0; - - faceName = tokenizer.GetNextToken(); - -#ifndef __WXMAC__ - if( !faceName ) - return false; -#endif - - token = tokenizer.GetNextToken(); - if ( !token.ToLong(&l) ) - return false; - encoding = (wxFontEncoding)l; - - return true; -} - -wxString wxNativeFontInfo::ToString() const -{ - wxString s; - - s.Printf(_T("%d;%d;%d;%d;%d;%d;%s;%d"), - 0, // version - pointSize, - family, - (int)style, - (int)weight, - underlined, - faceName.GetData(), - (int)encoding); - - return s; -} - -void wxNativeFontInfo::Init() -{ - pointSize = 0; - family = wxFONTFAMILY_DEFAULT; - style = wxFONTSTYLE_NORMAL; - weight = wxFONTWEIGHT_NORMAL; - underlined = false; - faceName.clear(); - encoding = wxFONTENCODING_DEFAULT; -} - -int wxNativeFontInfo::GetPointSize() const -{ - return pointSize; -} - -wxFontStyle wxNativeFontInfo::GetStyle() const -{ - return style; -} - -wxFontWeight wxNativeFontInfo::GetWeight() const -{ - return weight; -} - -bool wxNativeFontInfo::GetUnderlined() const -{ - return underlined; -} - -wxString wxNativeFontInfo::GetFaceName() const -{ - return faceName; -} - -wxFontFamily wxNativeFontInfo::GetFamily() const -{ - return family; -} - -wxFontEncoding wxNativeFontInfo::GetEncoding() const -{ - return encoding; -} - -void wxNativeFontInfo::SetPointSize(int pointsize) -{ - pointSize = pointsize; -} - -void wxNativeFontInfo::SetStyle(wxFontStyle style_) -{ - style = style_; -} - -void wxNativeFontInfo::SetWeight(wxFontWeight weight_) -{ - weight = weight_; -} - -void wxNativeFontInfo::SetUnderlined(bool underlined_) -{ - underlined = underlined_; -} - -bool wxNativeFontInfo::SetFaceName(const wxString& facename_) -{ - faceName = facename_; - return true; -} - -void wxNativeFontInfo::SetFamily(wxFontFamily family_) -{ - family = family_; -} - -void wxNativeFontInfo::SetEncoding(wxFontEncoding encoding_) -{ - encoding = encoding_; -} - -#endif // generic wxNativeFontInfo implementation - -// conversion to/from user-readable string: this is used in the generic -// versions and under MSW as well because there is no standard font description -// format there anyhow (but there is a well-defined standard for X11 fonts used -// by wxGTK and wxMotif) - -#if defined(wxNO_NATIVE_FONTINFO) || defined(__WXMSW__) || defined (__WXPM__) - -wxString wxNativeFontInfo::ToUserString() const -{ - wxString desc; - - // first put the adjectives, if any - this is English-centric, of course, - // but what else can we do? - if ( GetUnderlined() ) - { - desc << _("underlined"); - } - - switch ( GetWeight() ) - { - default: - wxFAIL_MSG( _T("unknown font weight") ); - // fall through - - case wxFONTWEIGHT_NORMAL: - break; - - case wxFONTWEIGHT_LIGHT: - desc << _(" light"); - break; - - case wxFONTWEIGHT_BOLD: - desc << _(" bold"); - break; - } - - switch ( GetStyle() ) - { - default: - wxFAIL_MSG( _T("unknown font style") ); - // fall through - - case wxFONTSTYLE_NORMAL: - break; - - // we don't distinguish between the two for now anyhow... - case wxFONTSTYLE_ITALIC: - case wxFONTSTYLE_SLANT: - desc << _(" italic"); - break; - } - - wxString face = GetFaceName(); - if ( !face.empty() ) - { - desc << _T(' ') << face; - } - - int size = GetPointSize(); - if ( size != wxNORMAL_FONT->GetPointSize() ) - { - desc << _T(' ') << size; - } - -#if wxUSE_FONTMAP - wxFontEncoding enc = GetEncoding(); - if ( enc != wxFONTENCODING_DEFAULT && enc != wxFONTENCODING_SYSTEM ) - { - desc << _T(' ') << wxFontMapper::GetEncodingName(enc); - } -#endif // wxUSE_FONTMAP - - return desc.Strip(wxString::both).MakeLower(); -} - -bool wxNativeFontInfo::FromUserString(const wxString& s) -{ - // reset to the default state - Init(); - - // parse a more or less free form string - // - // TODO: we should handle at least the quoted facenames - wxStringTokenizer tokenizer(s, _T(";, "), wxTOKEN_STRTOK); - - wxString face; - unsigned long size; - bool weightfound = false, pointsizefound = false; -#if wxUSE_FONTMAP - bool encodingfound = false; -#endif - - while ( tokenizer.HasMoreTokens() ) - { - wxString token = tokenizer.GetNextToken(); - - // normalize it - token.Trim(true).Trim(false).MakeLower(); - - // look for the known tokens - if ( token == _T("underlined") || token == _("underlined") ) - { - SetUnderlined(true); - } - else if ( token == _T("light") || token == _("light") ) - { - SetWeight(wxFONTWEIGHT_LIGHT); - weightfound = true; - } - else if ( token == _T("bold") || token == _("bold") ) - { - SetWeight(wxFONTWEIGHT_BOLD); - weightfound = true; - } - else if ( token == _T("italic") || token == _("italic") ) - { - SetStyle(wxFONTSTYLE_ITALIC); - } - else if ( token.ToULong(&size) ) - { - SetPointSize(size); - pointsizefound = true; - } - else - { -#if wxUSE_FONTMAP - // try to interpret this as an encoding - wxFontEncoding encoding = wxFontMapper::Get()->CharsetToEncoding(token, false); - if ( encoding != wxFONTENCODING_DEFAULT && - encoding != wxFONTENCODING_SYSTEM ) // returned when the recognition failed - { - SetEncoding(encoding); - encodingfound = true; - } - else - { -#endif // wxUSE_FONTMAP - - // assume it is the face name - if ( !face.empty() ) - { - face += _T(' '); - } - - face += token; - - // skip the code which resets face below - continue; - -#if wxUSE_FONTMAP - } -#endif // wxUSE_FONTMAP - } - - // if we had had the facename, we shouldn't continue appending tokens - // to it (i.e. "foo bold bar" shouldn't result in the facename "foo - // bar") - if ( !face.empty() ) - { - // NB: the check on the facename is implemented in wxFontBase::SetFaceName - // and not in wxNativeFontInfo::SetFaceName thus we need to explicitely - // call here wxFontEnumerator::IsValidFacename - if (!wxFontEnumerator::IsValidFacename(face) || - !SetFaceName(face)) - SetFaceName(wxNORMAL_FONT->GetFaceName()); - face.clear(); - } - } - - // we might not have flushed it inside the loop - if ( !face.empty() ) - { - // NB: the check on the facename is implemented in wxFontBase::SetFaceName - // and not in wxNativeFontInfo::SetFaceName thus we need to explicitely - // call here wxFontEnumerator::IsValidFacename - if (!wxFontEnumerator::IsValidFacename(face) || - !SetFaceName(face)) - SetFaceName(wxNORMAL_FONT->GetFaceName()); - } - - // set point size to default value if size was not given - if ( !pointsizefound ) - SetPointSize(wxNORMAL_FONT->GetPointSize()); - - // set font weight to default value if weight was not given - if ( !weightfound ) - SetWeight(wxFONTWEIGHT_NORMAL); - -#if wxUSE_FONTMAP - // set font encoding to default value if encoding was not given - if ( !encodingfound ) - SetEncoding(wxFONTENCODING_SYSTEM); -#endif // wxUSE_FONTMAP - - return true; -} - -#endif // generic or wxMSW or wxOS2 +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fontcmn.cpp +// Purpose: implementation of wxFontBase methods +// Author: Vadim Zeitlin +// Modified by: +// Created: 20.09.99 +// RCS-ID: $Id: fontcmn.cpp 43661 2006-11-26 20:18:53Z VZ $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/font.h" + +#ifndef WX_PRECOMP + #include "wx/dc.h" + #include "wx/intl.h" + #include "wx/dcscreen.h" + #include "wx/log.h" + #include "wx/gdicmn.h" +#endif // WX_PRECOMP + +#if defined(__WXMSW__) + #include "wx/msw/private.h" // includes windows.h for LOGFONT + #include "wx/msw/winundef.h" +#endif + +#include "wx/fontutil.h" // for wxNativeFontInfo +#include "wx/fontmap.h" +#include "wx/fontenum.h" + +#include "wx/tokenzr.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// helper functions +// ---------------------------------------------------------------------------- + +static void AdjustFontSize(wxFont& font, wxDC& dc, const wxSize& pixelSize) +{ + int currentSize = 0; + int largestGood = 0; + int smallestBad = 0; + + bool initialGoodFound = false; + bool initialBadFound = false; + + // NB: this assignment was separated from the variable definition + // in order to fix a gcc v3.3.3 compiler crash + currentSize = font.GetPointSize(); + while (currentSize > 0) + { + dc.SetFont(font); + + // if currentSize (in points) results in a font that is smaller + // than required by pixelSize it is considered a good size + if (dc.GetCharHeight() <= pixelSize.GetHeight() && + (!pixelSize.GetWidth() || + dc.GetCharWidth() <= pixelSize.GetWidth())) + { + largestGood = currentSize; + initialGoodFound = true; + } + else + { + smallestBad = currentSize; + initialBadFound = true; + } + if (!initialGoodFound) + { + currentSize /= 2; + } + else if (!initialBadFound) + { + currentSize *= 2; + } + else + { + int distance = smallestBad - largestGood; + if (distance == 1) + break; + + currentSize = largestGood + distance / 2; + } + + font.SetPointSize(currentSize); + } + + if (currentSize != largestGood) + font.SetPointSize(largestGood); +} + +// ---------------------------------------------------------------------------- +// wxFontBase +// ---------------------------------------------------------------------------- + +wxFontEncoding wxFontBase::ms_encodingDefault = wxFONTENCODING_SYSTEM; + +/* static */ +void wxFontBase::SetDefaultEncoding(wxFontEncoding encoding) +{ + // GetDefaultEncoding() should return something != wxFONTENCODING_DEFAULT + // and, besides, using this value here doesn't make any sense + wxCHECK_RET( encoding != wxFONTENCODING_DEFAULT, + _T("can't set default encoding to wxFONTENCODING_DEFAULT") ); + + ms_encodingDefault = encoding; +} + +wxFontBase::~wxFontBase() +{ + // this destructor is required for Darwin +} + +/* static */ +wxFont *wxFontBase::New(int size, + int family, + int style, + int weight, + bool underlined, + const wxString& face, + wxFontEncoding encoding) +{ + return new wxFont(size, family, style, weight, underlined, face, encoding); +} + +static inline int flags2Style(int flags) +{ + return flags & wxFONTFLAG_ITALIC + ? wxFONTSTYLE_ITALIC + : flags & wxFONTFLAG_SLANT + ? wxFONTSTYLE_SLANT + : wxFONTSTYLE_NORMAL; +} + +static inline int flags2Weight(int flags) +{ + return flags & wxFONTFLAG_LIGHT + ? wxFONTWEIGHT_LIGHT + : flags & wxFONTFLAG_BOLD + ? wxFONTWEIGHT_BOLD + : wxFONTWEIGHT_NORMAL; +} + +static inline bool flags2Underlined(int flags) +{ + return (flags & wxFONTFLAG_UNDERLINED) != 0; +} + +/* static */ +wxFont *wxFontBase::New(int pointSize, + wxFontFamily family, + int flags, + const wxString& face, + wxFontEncoding encoding) +{ + return New(pointSize, family, flags2Style(flags), flags2Weight(flags), + flags2Underlined(flags), face, encoding); +} + +/* static */ +wxFont *wxFontBase::New(const wxSize& pixelSize, + int family, + int style, + int weight, + bool underlined, + const wxString& face, + wxFontEncoding encoding) +{ +#if defined(__WXMSW__) + return new wxFont(pixelSize, family, style, weight, underlined, + face, encoding); +#else + wxFont *self = New(10, family, style, weight, underlined, face, encoding); + wxScreenDC dc; + AdjustFontSize(*(wxFont *)self, dc, pixelSize); + return self; +#endif +} + +/* static */ +wxFont *wxFontBase::New(const wxSize& pixelSize, + wxFontFamily family, + int flags, + const wxString& face, + wxFontEncoding encoding) +{ + return New(pixelSize, family, flags2Style(flags), flags2Weight(flags), + flags2Underlined(flags), face, encoding); +} + +wxSize wxFontBase::GetPixelSize() const +{ + wxScreenDC dc; + dc.SetFont(*(wxFont *)this); + return wxSize(dc.GetCharWidth(), dc.GetCharHeight()); +} + +bool wxFontBase::IsUsingSizeInPixels() const +{ + return false; +} + +void wxFontBase::SetPixelSize( const wxSize& pixelSize ) +{ + wxScreenDC dc; + AdjustFontSize(*(wxFont *)this, dc, pixelSize); +} + +/* static */ +wxFont *wxFontBase::New(const wxNativeFontInfo& info) +{ + return new wxFont(info); +} + +/* static */ +wxFont *wxFontBase::New(const wxString& strNativeFontDesc) +{ + wxNativeFontInfo fontInfo; + if ( !fontInfo.FromString(strNativeFontDesc) ) + return new wxFont(*wxNORMAL_FONT); + + return New(fontInfo); +} + +bool wxFontBase::IsFixedWidth() const +{ + return GetFamily() == wxFONTFAMILY_TELETYPE; +} + +void wxFontBase::DoSetNativeFontInfo(const wxNativeFontInfo& info) +{ +#ifdef wxNO_NATIVE_FONTINFO + SetPointSize(info.pointSize); + SetFamily(info.family); + SetStyle(info.style); + SetWeight(info.weight); + SetUnderlined(info.underlined); + SetFaceName(info.faceName); + SetEncoding(info.encoding); +#else + (void)info; +#endif +} + +wxString wxFontBase::GetNativeFontInfoDesc() const +{ + wxString fontDesc; + const wxNativeFontInfo *fontInfo = GetNativeFontInfo(); + if ( fontInfo ) + { + fontDesc = fontInfo->ToString(); + wxASSERT_MSG(!fontDesc.empty(), wxT("This should be a non-empty string!")); + } + else + { + wxFAIL_MSG(wxT("Derived class should have created the wxNativeFontInfo!")); + } + + return fontDesc; +} + +wxString wxFontBase::GetNativeFontInfoUserDesc() const +{ + wxString fontDesc; + const wxNativeFontInfo *fontInfo = GetNativeFontInfo(); + if ( fontInfo ) + { + fontDesc = fontInfo->ToUserString(); + wxASSERT_MSG(!fontDesc.empty(), wxT("This should be a non-empty string!")); + } + else + { + wxFAIL_MSG(wxT("Derived class should have created the wxNativeFontInfo!")); + } + + return fontDesc; +} + +bool wxFontBase::SetNativeFontInfo(const wxString& info) +{ + wxNativeFontInfo fontInfo; + if ( !info.empty() && fontInfo.FromString(info) ) + { + SetNativeFontInfo(fontInfo); + return true; + } + + UnRef(); + return false; +} + +bool wxFontBase::SetNativeFontInfoUserDesc(const wxString& info) +{ + wxNativeFontInfo fontInfo; + if ( !info.empty() && fontInfo.FromUserString(info) ) + { + SetNativeFontInfo(fontInfo); + return true; + } + + UnRef(); + return false; +} + +bool wxFontBase::operator==(const wxFont& font) const +{ + // either it is the same font, i.e. they share the same common data or they + // have different ref datas but still describe the same font + return IsSameAs(font) || + ( + Ok() == font.Ok() && + GetPointSize() == font.GetPointSize() && + // in wxGTK1 GetPixelSize() calls GetInternalFont() which uses + // operator==() resulting in infinite recursion so we can't use it + // in that port +#if !defined(__WXGTK__) || defined(__WXGTK20__) + GetPixelSize() == font.GetPixelSize() && +#endif + GetFamily() == font.GetFamily() && + GetStyle() == font.GetStyle() && + GetWeight() == font.GetWeight() && + GetUnderlined() == font.GetUnderlined() && + GetFaceName().IsSameAs(font.GetFaceName(), false) && + GetEncoding() == font.GetEncoding() + ); +} + +bool wxFontBase::operator!=(const wxFont& font) const +{ + return !(*this == font); +} + +wxString wxFontBase::GetFamilyString() const +{ + wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") ); + + switch ( GetFamily() ) + { + case wxDECORATIVE: return wxT("wxDECORATIVE"); + case wxROMAN: return wxT("wxROMAN"); + case wxSCRIPT: return wxT("wxSCRIPT"); + case wxSWISS: return wxT("wxSWISS"); + case wxMODERN: return wxT("wxMODERN"); + case wxTELETYPE: return wxT("wxTELETYPE"); + default: return wxT("wxDEFAULT"); + } +} + +wxString wxFontBase::GetStyleString() const +{ + wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") ); + + switch ( GetStyle() ) + { + case wxNORMAL: return wxT("wxNORMAL"); + case wxSLANT: return wxT("wxSLANT"); + case wxITALIC: return wxT("wxITALIC"); + default: return wxT("wxDEFAULT"); + } +} + +wxString wxFontBase::GetWeightString() const +{ + wxCHECK_MSG( Ok(), wxT("wxDEFAULT"), wxT("invalid font") ); + + switch ( GetWeight() ) + { + case wxNORMAL: return wxT("wxNORMAL"); + case wxBOLD: return wxT("wxBOLD"); + case wxLIGHT: return wxT("wxLIGHT"); + default: return wxT("wxDEFAULT"); + } +} + +bool wxFontBase::SetFaceName(const wxString &facename) +{ + if (!wxFontEnumerator::IsValidFacename(facename)) + { + UnRef(); // make Ok() return false + return false; + } + + return true; +} + + +// ---------------------------------------------------------------------------- +// wxNativeFontInfo +// ---------------------------------------------------------------------------- + +// Up to now, there are no native implementations of this function: +void wxNativeFontInfo::SetFaceName(const wxArrayString &facenames) +{ + for (size_t i=0; i < facenames.GetCount(); i++) + { + if (wxFontEnumerator::IsValidFacename(facenames[i])) + { + SetFaceName(facenames[i]); + return; + } + } + + // set the first valid facename we can find on this system + wxString validfacename = wxFontEnumerator::GetFacenames().Item(0); + wxLogTrace(wxT("font"), wxT("Falling back to '%s'"), validfacename.c_str()); + SetFaceName(validfacename); +} + + +#ifdef wxNO_NATIVE_FONTINFO + +// These are the generic forms of FromString()/ToString. +// +// convert to/from the string representation: format is +// version;pointsize;family;style;weight;underlined;facename;encoding + +bool wxNativeFontInfo::FromString(const wxString& s) +{ + long l; + + wxStringTokenizer tokenizer(s, _T(";")); + + wxString token = tokenizer.GetNextToken(); + // + // Ignore the version for now + // + + token = tokenizer.GetNextToken(); + if ( !token.ToLong(&l) ) + return false; + pointSize = (int)l; + + token = tokenizer.GetNextToken(); + if ( !token.ToLong(&l) ) + return false; + family = (wxFontFamily)l; + + token = tokenizer.GetNextToken(); + if ( !token.ToLong(&l) ) + return false; + style = (wxFontStyle)l; + + token = tokenizer.GetNextToken(); + if ( !token.ToLong(&l) ) + return false; + weight = (wxFontWeight)l; + + token = tokenizer.GetNextToken(); + if ( !token.ToLong(&l) ) + return false; + underlined = l != 0; + + faceName = tokenizer.GetNextToken(); + +#ifndef __WXMAC__ + if( !faceName ) + return false; +#endif + + token = tokenizer.GetNextToken(); + if ( !token.ToLong(&l) ) + return false; + encoding = (wxFontEncoding)l; + + return true; +} + +wxString wxNativeFontInfo::ToString() const +{ + wxString s; + + s.Printf(_T("%d;%d;%d;%d;%d;%d;%s;%d"), + 0, // version + pointSize, + family, + (int)style, + (int)weight, + underlined, + faceName.GetData(), + (int)encoding); + + return s; +} + +void wxNativeFontInfo::Init() +{ + pointSize = 0; + family = wxFONTFAMILY_DEFAULT; + style = wxFONTSTYLE_NORMAL; + weight = wxFONTWEIGHT_NORMAL; + underlined = false; + faceName.clear(); + encoding = wxFONTENCODING_DEFAULT; +} + +int wxNativeFontInfo::GetPointSize() const +{ + return pointSize; +} + +wxFontStyle wxNativeFontInfo::GetStyle() const +{ + return style; +} + +wxFontWeight wxNativeFontInfo::GetWeight() const +{ + return weight; +} + +bool wxNativeFontInfo::GetUnderlined() const +{ + return underlined; +} + +wxString wxNativeFontInfo::GetFaceName() const +{ + return faceName; +} + +wxFontFamily wxNativeFontInfo::GetFamily() const +{ + return family; +} + +wxFontEncoding wxNativeFontInfo::GetEncoding() const +{ + return encoding; +} + +void wxNativeFontInfo::SetPointSize(int pointsize) +{ + pointSize = pointsize; +} + +void wxNativeFontInfo::SetStyle(wxFontStyle style_) +{ + style = style_; +} + +void wxNativeFontInfo::SetWeight(wxFontWeight weight_) +{ + weight = weight_; +} + +void wxNativeFontInfo::SetUnderlined(bool underlined_) +{ + underlined = underlined_; +} + +bool wxNativeFontInfo::SetFaceName(const wxString& facename_) +{ + faceName = facename_; + return true; +} + +void wxNativeFontInfo::SetFamily(wxFontFamily family_) +{ + family = family_; +} + +void wxNativeFontInfo::SetEncoding(wxFontEncoding encoding_) +{ + encoding = encoding_; +} + +#endif // generic wxNativeFontInfo implementation + +// conversion to/from user-readable string: this is used in the generic +// versions and under MSW as well because there is no standard font description +// format there anyhow (but there is a well-defined standard for X11 fonts used +// by wxGTK and wxMotif) + +#if defined(wxNO_NATIVE_FONTINFO) || defined(__WXMSW__) || defined (__WXPM__) + +wxString wxNativeFontInfo::ToUserString() const +{ + wxString desc; + + // first put the adjectives, if any - this is English-centric, of course, + // but what else can we do? + if ( GetUnderlined() ) + { + desc << _("underlined"); + } + + switch ( GetWeight() ) + { + default: + wxFAIL_MSG( _T("unknown font weight") ); + // fall through + + case wxFONTWEIGHT_NORMAL: + break; + + case wxFONTWEIGHT_LIGHT: + desc << _(" light"); + break; + + case wxFONTWEIGHT_BOLD: + desc << _(" bold"); + break; + } + + switch ( GetStyle() ) + { + default: + wxFAIL_MSG( _T("unknown font style") ); + // fall through + + case wxFONTSTYLE_NORMAL: + break; + + // we don't distinguish between the two for now anyhow... + case wxFONTSTYLE_ITALIC: + case wxFONTSTYLE_SLANT: + desc << _(" italic"); + break; + } + + wxString face = GetFaceName(); + if ( !face.empty() ) + { + desc << _T(' ') << face; + } + + int size = GetPointSize(); + if ( size != wxNORMAL_FONT->GetPointSize() ) + { + desc << _T(' ') << size; + } + +#if wxUSE_FONTMAP + wxFontEncoding enc = GetEncoding(); + if ( enc != wxFONTENCODING_DEFAULT && enc != wxFONTENCODING_SYSTEM ) + { + desc << _T(' ') << wxFontMapper::GetEncodingName(enc); + } +#endif // wxUSE_FONTMAP + + return desc.Strip(wxString::both).MakeLower(); +} + +bool wxNativeFontInfo::FromUserString(const wxString& s) +{ + // reset to the default state + Init(); + + // parse a more or less free form string + // + // TODO: we should handle at least the quoted facenames + wxStringTokenizer tokenizer(s, _T(";, "), wxTOKEN_STRTOK); + + wxString face; + unsigned long size; + bool weightfound = false, pointsizefound = false; +#if wxUSE_FONTMAP + bool encodingfound = false; +#endif + + while ( tokenizer.HasMoreTokens() ) + { + wxString token = tokenizer.GetNextToken(); + + // normalize it + token.Trim(true).Trim(false).MakeLower(); + + // look for the known tokens + if ( token == _T("underlined") || token == _("underlined") ) + { + SetUnderlined(true); + } + else if ( token == _T("light") || token == _("light") ) + { + SetWeight(wxFONTWEIGHT_LIGHT); + weightfound = true; + } + else if ( token == _T("bold") || token == _("bold") ) + { + SetWeight(wxFONTWEIGHT_BOLD); + weightfound = true; + } + else if ( token == _T("italic") || token == _("italic") ) + { + SetStyle(wxFONTSTYLE_ITALIC); + } + else if ( token.ToULong(&size) ) + { + SetPointSize(size); + pointsizefound = true; + } + else + { +#if wxUSE_FONTMAP + // try to interpret this as an encoding + wxFontEncoding encoding = wxFontMapper::Get()->CharsetToEncoding(token, false); + if ( encoding != wxFONTENCODING_DEFAULT && + encoding != wxFONTENCODING_SYSTEM ) // returned when the recognition failed + { + SetEncoding(encoding); + encodingfound = true; + } + else + { +#endif // wxUSE_FONTMAP + + // assume it is the face name + if ( !face.empty() ) + { + face += _T(' '); + } + + face += token; + + // skip the code which resets face below + continue; + +#if wxUSE_FONTMAP + } +#endif // wxUSE_FONTMAP + } + + // if we had had the facename, we shouldn't continue appending tokens + // to it (i.e. "foo bold bar" shouldn't result in the facename "foo + // bar") + if ( !face.empty() ) + { + // NB: the check on the facename is implemented in wxFontBase::SetFaceName + // and not in wxNativeFontInfo::SetFaceName thus we need to explicitely + // call here wxFontEnumerator::IsValidFacename + if (!wxFontEnumerator::IsValidFacename(face) || + !SetFaceName(face)) + SetFaceName(wxNORMAL_FONT->GetFaceName()); + face.clear(); + } + } + + // we might not have flushed it inside the loop + if ( !face.empty() ) + { + // NB: the check on the facename is implemented in wxFontBase::SetFaceName + // and not in wxNativeFontInfo::SetFaceName thus we need to explicitely + // call here wxFontEnumerator::IsValidFacename + if (!wxFontEnumerator::IsValidFacename(face) || + !SetFaceName(face)) + SetFaceName(wxNORMAL_FONT->GetFaceName()); + } + + // set point size to default value if size was not given + if ( !pointsizefound ) + SetPointSize(wxNORMAL_FONT->GetPointSize()); + + // set font weight to default value if weight was not given + if ( !weightfound ) + SetWeight(wxFONTWEIGHT_NORMAL); + +#if wxUSE_FONTMAP + // set font encoding to default value if encoding was not given + if ( !encodingfound ) + SetEncoding(wxFONTENCODING_SYSTEM); +#endif // wxUSE_FONTMAP + + return true; +} + +#endif // generic or wxMSW or wxOS2 diff --git a/Source/3rd Party/wx/src/common/fontenumcmn.cpp b/Source/3rd Party/wx/src/common/fontenumcmn.cpp index 0b64d0f4d..6ea8a30cb 100644 --- a/Source/3rd Party/wx/src/common/fontenumcmn.cpp +++ b/Source/3rd Party/wx/src/common/fontenumcmn.cpp @@ -1,131 +1,131 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fontenumcmn.cpp -// Purpose: wxFontEnumerator class -// Author: Vadim Zeitlin -// Modified by: -// Created: 7/5/2006 -// RCS-ID: $Id: fontenumcmn.cpp 43727 2006-12-01 10:14:28Z VS $ -// Copyright: (c) 1999-2003 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/fontenum.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// A simple wxFontEnumerator which doesn't perform any filtering and -// just returns all facenames and encodings found in the system -class WXDLLEXPORT wxSimpleFontEnumerator : public wxFontEnumerator -{ -public: - wxSimpleFontEnumerator() { } - - // called by EnumerateFacenames - virtual bool OnFacename(const wxString& facename) - { - m_arrFacenames.Add(facename); - return true; - } - - // called by EnumerateEncodings - virtual bool OnFontEncoding(const wxString& WXUNUSED(facename), - const wxString& encoding) - { - m_arrEncodings.Add(encoding); - return true; - } - -public: - wxArrayString m_arrFacenames, m_arrEncodings; -}; - - -/* static */ -wxArrayString wxFontEnumerator::GetFacenames(wxFontEncoding encoding, bool fixedWidthOnly) -{ - wxSimpleFontEnumerator temp; - temp.EnumerateFacenames(encoding, fixedWidthOnly); - return temp.m_arrFacenames; -} - -/* static */ -wxArrayString wxFontEnumerator::GetEncodings(const wxString& facename) -{ - wxSimpleFontEnumerator temp; - temp.EnumerateEncodings(facename); - return temp.m_arrEncodings; -} - -/* static */ -bool wxFontEnumerator::IsValidFacename(const wxString &facename) -{ - // we cache the result of wxFontEnumerator::GetFacenames supposing that - // the array of face names won't change in the session of this program - static wxArrayString s_arr = wxFontEnumerator::GetFacenames(); - -#ifdef __WXMSW__ - // Quoting the MSDN: - // "MS Shell Dlg is a mapping mechanism that enables - // U.S. English Microsoft Windows NT, and Microsoft Windows 2000 to - // support locales that have characters that are not contained in code - // page 1252. It is not a font but a face name for a nonexistent font." - // Thus we need to consider "Ms Shell Dlg" and "Ms Shell Dlg 2" as valid - // font face names even if they are enumerated by wxFontEnumerator - if (facename.IsSameAs(wxT("Ms Shell Dlg"), false) || - facename.IsSameAs(wxT("Ms Shell Dlg 2"), false)) - return true; -#endif - - // is given font face name a valid one ? - if (s_arr.Index(facename, false) == wxNOT_FOUND) - return false; - - return true; -} - -#ifdef wxHAS_UTF8_FONTS -bool wxFontEnumerator::EnumerateEncodingsUTF8(const wxString& facename) -{ - // name of UTF-8 encoding: no need to use wxFontMapper for it as it's - // unlikely to change - const wxString utf8(_T("UTF-8")); - - // all fonts are in UTF-8 only if this code is used - if ( !facename.empty() ) - { - OnFontEncoding(facename, utf8); - return true; - } - - // so enumerating all facenames supporting this encoding is the same as - // enumerating all facenames - const wxArrayString facenames(GetFacenames(wxFONTENCODING_UTF8)); - const size_t count = facenames.size(); - if ( !count ) - return false; - - for ( size_t n = 0; n < count; n++ ) - { - OnFontEncoding(facenames[n], utf8); - } - - return true; -} -#endif // wxHAS_UTF8_FONTS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fontenumcmn.cpp +// Purpose: wxFontEnumerator class +// Author: Vadim Zeitlin +// Modified by: +// Created: 7/5/2006 +// RCS-ID: $Id: fontenumcmn.cpp 43727 2006-12-01 10:14:28Z VS $ +// Copyright: (c) 1999-2003 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/fontenum.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// A simple wxFontEnumerator which doesn't perform any filtering and +// just returns all facenames and encodings found in the system +class WXDLLEXPORT wxSimpleFontEnumerator : public wxFontEnumerator +{ +public: + wxSimpleFontEnumerator() { } + + // called by EnumerateFacenames + virtual bool OnFacename(const wxString& facename) + { + m_arrFacenames.Add(facename); + return true; + } + + // called by EnumerateEncodings + virtual bool OnFontEncoding(const wxString& WXUNUSED(facename), + const wxString& encoding) + { + m_arrEncodings.Add(encoding); + return true; + } + +public: + wxArrayString m_arrFacenames, m_arrEncodings; +}; + + +/* static */ +wxArrayString wxFontEnumerator::GetFacenames(wxFontEncoding encoding, bool fixedWidthOnly) +{ + wxSimpleFontEnumerator temp; + temp.EnumerateFacenames(encoding, fixedWidthOnly); + return temp.m_arrFacenames; +} + +/* static */ +wxArrayString wxFontEnumerator::GetEncodings(const wxString& facename) +{ + wxSimpleFontEnumerator temp; + temp.EnumerateEncodings(facename); + return temp.m_arrEncodings; +} + +/* static */ +bool wxFontEnumerator::IsValidFacename(const wxString &facename) +{ + // we cache the result of wxFontEnumerator::GetFacenames supposing that + // the array of face names won't change in the session of this program + static wxArrayString s_arr = wxFontEnumerator::GetFacenames(); + +#ifdef __WXMSW__ + // Quoting the MSDN: + // "MS Shell Dlg is a mapping mechanism that enables + // U.S. English Microsoft Windows NT, and Microsoft Windows 2000 to + // support locales that have characters that are not contained in code + // page 1252. It is not a font but a face name for a nonexistent font." + // Thus we need to consider "Ms Shell Dlg" and "Ms Shell Dlg 2" as valid + // font face names even if they are enumerated by wxFontEnumerator + if (facename.IsSameAs(wxT("Ms Shell Dlg"), false) || + facename.IsSameAs(wxT("Ms Shell Dlg 2"), false)) + return true; +#endif + + // is given font face name a valid one ? + if (s_arr.Index(facename, false) == wxNOT_FOUND) + return false; + + return true; +} + +#ifdef wxHAS_UTF8_FONTS +bool wxFontEnumerator::EnumerateEncodingsUTF8(const wxString& facename) +{ + // name of UTF-8 encoding: no need to use wxFontMapper for it as it's + // unlikely to change + const wxString utf8(_T("UTF-8")); + + // all fonts are in UTF-8 only if this code is used + if ( !facename.empty() ) + { + OnFontEncoding(facename, utf8); + return true; + } + + // so enumerating all facenames supporting this encoding is the same as + // enumerating all facenames + const wxArrayString facenames(GetFacenames(wxFONTENCODING_UTF8)); + const size_t count = facenames.size(); + if ( !count ) + return false; + + for ( size_t n = 0; n < count; n++ ) + { + OnFontEncoding(facenames[n], utf8); + } + + return true; +} +#endif // wxHAS_UTF8_FONTS diff --git a/Source/3rd Party/wx/src/common/fontmap.cpp b/Source/3rd Party/wx/src/common/fontmap.cpp index cf53fd914..3d3800766 100644 --- a/Source/3rd Party/wx/src/common/fontmap.cpp +++ b/Source/3rd Party/wx/src/common/fontmap.cpp @@ -1,519 +1,519 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fontmap.cpp -// Purpose: wxFontMapper class -// Author: Vadim Zeitlin -// Modified by: -// Created: 04.11.99 -// RCS-ID: $Id: fontmap.cpp 39651 2006-06-09 17:50:46Z ABX $ -// Copyright: (c) 1999-2003 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FONTMAP - -#include "wx/fontmap.h" - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/msgdlg.h" - #include "wx/choicdlg.h" -#endif // PCH - -#if wxUSE_CONFIG - #include "wx/config.h" -#endif // wxUSE_CONFIG - -#if defined(__WXMSW__) - #include "wx/msw/private.h" // includes windows.h for LOGFONT - #include "wx/msw/winundef.h" -#endif - -#include "wx/fmappriv.h" -#include "wx/fontutil.h" -#include "wx/fontdlg.h" -#include "wx/encinfo.h" - -#include "wx/encconv.h" - -#if wxUSE_EXTENDED_RTTI - -wxBEGIN_ENUM( wxFontEncoding ) - wxENUM_MEMBER( wxFONTENCODING_SYSTEM ) - wxENUM_MEMBER( wxFONTENCODING_DEFAULT ) - - wxENUM_MEMBER( wxFONTENCODING_ISO8859_1 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_2 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_3 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_4 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_5 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_6 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_7 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_8 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_9 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_10 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_11 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_12 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_13 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_14 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_15 ) - wxENUM_MEMBER( wxFONTENCODING_ISO8859_MAX ) - wxENUM_MEMBER( wxFONTENCODING_KOI8 ) - wxENUM_MEMBER( wxFONTENCODING_KOI8_U ) - wxENUM_MEMBER( wxFONTENCODING_ALTERNATIVE ) - wxENUM_MEMBER( wxFONTENCODING_BULGARIAN ) - wxENUM_MEMBER( wxFONTENCODING_CP437 ) - wxENUM_MEMBER( wxFONTENCODING_CP850 ) - wxENUM_MEMBER( wxFONTENCODING_CP852 ) - wxENUM_MEMBER( wxFONTENCODING_CP855 ) - wxENUM_MEMBER( wxFONTENCODING_CP866 ) - - wxENUM_MEMBER( wxFONTENCODING_CP874 ) - wxENUM_MEMBER( wxFONTENCODING_CP932 ) - wxENUM_MEMBER( wxFONTENCODING_CP936 ) - wxENUM_MEMBER( wxFONTENCODING_CP949 ) - wxENUM_MEMBER( wxFONTENCODING_CP950 ) - wxENUM_MEMBER( wxFONTENCODING_CP1250 ) - wxENUM_MEMBER( wxFONTENCODING_CP1251 ) - wxENUM_MEMBER( wxFONTENCODING_CP1252 ) - wxENUM_MEMBER( wxFONTENCODING_CP1253 ) - wxENUM_MEMBER( wxFONTENCODING_CP1254 ) - wxENUM_MEMBER( wxFONTENCODING_CP1255 ) - wxENUM_MEMBER( wxFONTENCODING_CP1256 ) - wxENUM_MEMBER( wxFONTENCODING_CP1257 ) - wxENUM_MEMBER( wxFONTENCODING_CP12_MAX ) - wxENUM_MEMBER( wxFONTENCODING_UTF7 ) - wxENUM_MEMBER( wxFONTENCODING_UTF8 ) - wxENUM_MEMBER( wxFONTENCODING_GB2312 ) - wxENUM_MEMBER( wxFONTENCODING_BIG5 ) - wxENUM_MEMBER( wxFONTENCODING_SHIFT_JIS ) - wxENUM_MEMBER( wxFONTENCODING_EUC_JP ) - wxENUM_MEMBER( wxFONTENCODING_UNICODE ) -wxEND_ENUM( wxFontEncoding ) -#endif - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// the config paths we use -#if wxUSE_CONFIG - -static const wxChar* FONTMAPPER_FONT_FROM_ENCODING_PATH = wxT("Encodings"); -static const wxChar* FONTMAPPER_FONT_DONT_ASK = wxT("none"); - -#endif // wxUSE_CONFIG - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -// it may happen that while we're showing a dialog asking the user about -// something, another request for an encoding mapping arrives: in this case it -// is best to not do anything because otherwise we risk to enter an infinite -// loop so we create an object of this class on stack to test for this in all -// interactive functions -class ReentrancyBlocker -{ -public: - ReentrancyBlocker(bool& flag) : m_flagOld(flag), m_flag(flag) - { m_flag = true; } - ~ReentrancyBlocker() { m_flag = m_flagOld; } - -private: - bool m_flagOld; - bool& m_flag; - - DECLARE_NO_COPY_CLASS(ReentrancyBlocker) -}; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// ctor and dtor -// ---------------------------------------------------------------------------- - -wxFontMapper::wxFontMapper() -{ - m_windowParent = NULL; -} - -wxFontMapper::~wxFontMapper() -{ -} - -/* static */ -wxFontMapper *wxFontMapper::Get() -{ - wxFontMapperBase *fontmapper = wxFontMapperBase::Get(); - wxASSERT_MSG( !fontmapper->IsDummy(), - wxT("GUI code requested a wxFontMapper but we only have a wxFontMapperBase.") ); - - // Now return it anyway because there's a chance the GUI code might just - // only want to call wxFontMapperBase functions and it's better than - // crashing by returning NULL - return (wxFontMapper *)fontmapper; -} - -wxFontEncoding -wxFontMapper::CharsetToEncoding(const wxString& charset, bool interactive) -{ - // try the ways not needing the users intervention first - int encoding = wxFontMapperBase::NonInteractiveCharsetToEncoding(charset); - - // if we failed to find the encoding, ask the user -- unless disabled - if ( encoding == wxFONTENCODING_UNKNOWN ) - { - // this is the special value which disables asking the user (he had - // chosen to suppress this the last time) - encoding = wxFONTENCODING_SYSTEM; - } -#if wxUSE_CHOICEDLG - else if ( (encoding == wxFONTENCODING_SYSTEM) && interactive ) - { - // prepare the dialog data - - // the dialog title - wxString title(m_titleDialog); - if ( !title ) - title << wxTheApp->GetAppName() << _(": unknown charset"); - - // the message - wxString msg; - msg.Printf(_("The charset '%s' is unknown. You may select\nanother charset to replace it with or choose\n[Cancel] if it cannot be replaced"), charset.c_str()); - - // the list of choices - const size_t count = GetSupportedEncodingsCount(); - - wxString *encodingNamesTranslated = new wxString[count]; - - for ( size_t i = 0; i < count; i++ ) - { - encodingNamesTranslated[i] = GetEncodingDescription(GetEncoding(i)); - } - - // the parent window - wxWindow *parent = m_windowParent; - if ( !parent ) - parent = wxTheApp->GetTopWindow(); - - // do ask the user and get back the index in encodings table - int n = wxGetSingleChoiceIndex(msg, title, - count, - encodingNamesTranslated, - parent); - - delete [] encodingNamesTranslated; - - if ( n != -1 ) - { - encoding = GetEncoding(n); - } - -#if wxUSE_CONFIG && wxUSE_FILECONFIG - // save the result in the config now - wxFontMapperPathChanger path(this, FONTMAPPER_CHARSET_PATH); - if ( path.IsOk() ) - { - wxConfigBase *config = GetConfig(); - - // remember the alt encoding for this charset -- or remember that - // we don't know it - long value = n == -1 ? (long)wxFONTENCODING_UNKNOWN : (long)encoding; - if ( !config->Write(charset, value) ) - { - wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset.c_str()); - } - } -#endif // wxUSE_CONFIG - } -#else - wxUnusedVar(interactive); -#endif // wxUSE_CHOICEDLG - - return (wxFontEncoding)encoding; -} - -// ---------------------------------------------------------------------------- -// support for unknown encodings: we maintain a map between the -// (platform-specific) strings identifying them and our wxFontEncodings they -// correspond to which is used by GetFontForEncoding() function -// ---------------------------------------------------------------------------- - -bool wxFontMapper::TestAltEncoding(const wxString& configEntry, - wxFontEncoding encReplacement, - wxNativeEncodingInfo *info) -{ - if ( wxGetNativeFontEncoding(encReplacement, info) && - wxTestFontEncoding(*info) ) - { -#if wxUSE_CONFIG && wxUSE_FILECONFIG - // remember the mapping in the config - wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH); - - if ( path.IsOk() ) - { - GetConfig()->Write(configEntry, info->ToString()); - } -#else - wxUnusedVar(configEntry); -#endif // wxUSE_CONFIG - return true; - } - - return false; -} - -bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding, - wxNativeEncodingInfo *info, - const wxString& facename, - bool interactive) -{ -#if wxUSE_GUI - // we need a flag to prevent infinite recursion which happens, for - // example, when GetAltForEncoding() is called from an OnPaint() handler: - // in this case, wxYield() which is called from wxMessageBox() we use here - // will lead to another call of OnPaint() and hence to another call of - // GetAltForEncoding() -- and it is impossible to catch this from the user - // code because we are called from wxFont ctor implicitly. - - // assume we're always called from the main thread, so that it is safe to - // use a static var - static bool s_inGetAltForEncoding = false; - - if ( interactive && s_inGetAltForEncoding ) - return false; - - ReentrancyBlocker blocker(s_inGetAltForEncoding); -#endif // wxUSE_GUI - - wxCHECK_MSG( info, false, wxT("bad pointer in GetAltForEncoding") ); - - info->facename = facename; - - if ( encoding == wxFONTENCODING_DEFAULT ) - { - encoding = wxFont::GetDefaultEncoding(); - } - - // if we failed to load the system default encoding, something is really - // wrong and we'd better stop now -- otherwise we will go into endless - // recursion trying to create the font in the msg box with the error - // message - if ( encoding == wxFONTENCODING_SYSTEM ) - { - wxLogFatalError(_("can't load any font, aborting")); - - // wxLogFatalError doesn't return - } - - wxString configEntry, - encName = GetEncodingName(encoding); - if ( !facename.empty() ) - { - configEntry = facename + _T("_"); - } - configEntry += encName; - -#if wxUSE_CONFIG && wxUSE_FILECONFIG - // do we have a font spec for this encoding? - wxString fontinfo; - wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH); - if ( path.IsOk() ) - { - fontinfo = GetConfig()->Read(configEntry); - } - - // this special value means that we don't know of fonts for this - // encoding but, moreover, have already asked the user as well and he - // didn't specify any font neither - if ( fontinfo == FONTMAPPER_FONT_DONT_ASK ) - { - interactive = false; - } - else // use the info entered the last time - { - if ( !fontinfo.empty() && !facename.empty() ) - { - // we tried to find a match with facename -- now try without it - fontinfo = GetConfig()->Read(encName); - } - - if ( !fontinfo.empty() ) - { - if ( info->FromString(fontinfo) ) - { - if ( wxTestFontEncoding(*info) ) - { - // ok, got something - return true; - } - //else: no such fonts, look for something else - // (should we erase the outdated value?) - } - else - { - wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"), - fontinfo.c_str()); - } - } - //else: there is no information in config about this encoding - } -#endif // wxUSE_CONFIG - - // now try to map this encoding to a compatible one which we have on this - // system - wxFontEncodingArray equiv = wxEncodingConverter::GetAllEquivalents(encoding); - size_t count = equiv.GetCount(); - bool foundEquivEncoding = false; - wxFontEncoding equivEncoding = wxFONTENCODING_SYSTEM; - if ( count ) - { - for ( size_t i = 0; i < count && !foundEquivEncoding; i++ ) - { - // don't test for encoding itself, we already know we don't have it - if ( equiv[i] == encoding ) - continue; - - if ( TestAltEncoding(configEntry, equiv[i], info) ) - { - equivEncoding = equiv[i]; - - foundEquivEncoding = true; - } - } - } - - // ask the user -#if wxUSE_FONTDLG - if ( interactive ) - { - wxString title(m_titleDialog); - if ( !title ) - title << wxTheApp->GetAppName() << _(": unknown encoding"); - - // built the message - wxString encDesc = GetEncodingDescription(encoding), - msg; - if ( foundEquivEncoding ) - { - // ask the user if he wants to override found alternative encoding - msg.Printf(_("No font for displaying text in encoding '%s' found,\nbut an alternative encoding '%s' is available.\nDo you want to use this encoding (otherwise you will have to choose another one)?"), - encDesc.c_str(), GetEncodingDescription(equivEncoding).c_str()); - } - else - { - msg.Printf(_("No font for displaying text in encoding '%s' found.\nWould you like to select a font to be used for this encoding\n(otherwise the text in this encoding will not be shown correctly)?"), - encDesc.c_str()); - } - - // the question is different in 2 cases so the answer has to be - // interpreted differently as well - int answer = foundEquivEncoding ? wxNO : wxYES; - - if ( wxMessageBox(msg, title, - wxICON_QUESTION | wxYES_NO, - m_windowParent) == answer ) - { - wxFontData data; - data.SetEncoding(encoding); - data.EncodingInfo() = *info; - wxFontDialog dialog(m_windowParent, data); - if ( dialog.ShowModal() == wxID_OK ) - { - wxFontData retData = dialog.GetFontData(); - - *info = retData.EncodingInfo(); - info->encoding = retData.GetEncoding(); - -#if wxUSE_CONFIG && wxUSE_FILECONFIG - // remember this in the config - wxFontMapperPathChanger path2(this, - FONTMAPPER_FONT_FROM_ENCODING_PATH); - if ( path2.IsOk() ) - { - GetConfig()->Write(configEntry, info->ToString()); - } -#endif // wxUSE_CONFIG - - return true; - } - //else: the user canceled the font selection dialog - } - else - { - // the user doesn't want to select a font for this encoding - // or selected to use equivalent encoding - // - // remember it to avoid asking the same question again later -#if wxUSE_CONFIG && wxUSE_FILECONFIG - wxFontMapperPathChanger path2(this, - FONTMAPPER_FONT_FROM_ENCODING_PATH); - if ( path2.IsOk() ) - { - GetConfig()->Write - ( - configEntry, - foundEquivEncoding ? info->ToString().c_str() - : FONTMAPPER_FONT_DONT_ASK - ); - } -#endif // wxUSE_CONFIG - } - } - //else: we're in non-interactive mode -#else - wxUnusedVar(equivEncoding); -#endif // wxUSE_FONTDLG - - return foundEquivEncoding; -} - -bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding, - wxFontEncoding *encodingAlt, - const wxString& facename, - bool interactive) -{ - wxCHECK_MSG( encodingAlt, false, - _T("wxFontEncoding::GetAltForEncoding(): NULL pointer") ); - - wxNativeEncodingInfo info; - if ( !GetAltForEncoding(encoding, &info, facename, interactive) ) - return false; - - *encodingAlt = info.encoding; - - return true; -} - -bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding, - const wxString& facename) -{ - wxNativeEncodingInfo info; - - if ( !wxGetNativeFontEncoding(encoding, &info) ) - return false; - - info.facename = facename; - return wxTestFontEncoding(info); -} - -#endif // wxUSE_FONTMAP +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fontmap.cpp +// Purpose: wxFontMapper class +// Author: Vadim Zeitlin +// Modified by: +// Created: 04.11.99 +// RCS-ID: $Id: fontmap.cpp 39651 2006-06-09 17:50:46Z ABX $ +// Copyright: (c) 1999-2003 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FONTMAP + +#include "wx/fontmap.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/msgdlg.h" + #include "wx/choicdlg.h" +#endif // PCH + +#if wxUSE_CONFIG + #include "wx/config.h" +#endif // wxUSE_CONFIG + +#if defined(__WXMSW__) + #include "wx/msw/private.h" // includes windows.h for LOGFONT + #include "wx/msw/winundef.h" +#endif + +#include "wx/fmappriv.h" +#include "wx/fontutil.h" +#include "wx/fontdlg.h" +#include "wx/encinfo.h" + +#include "wx/encconv.h" + +#if wxUSE_EXTENDED_RTTI + +wxBEGIN_ENUM( wxFontEncoding ) + wxENUM_MEMBER( wxFONTENCODING_SYSTEM ) + wxENUM_MEMBER( wxFONTENCODING_DEFAULT ) + + wxENUM_MEMBER( wxFONTENCODING_ISO8859_1 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_2 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_3 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_4 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_5 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_6 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_7 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_8 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_9 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_10 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_11 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_12 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_13 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_14 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_15 ) + wxENUM_MEMBER( wxFONTENCODING_ISO8859_MAX ) + wxENUM_MEMBER( wxFONTENCODING_KOI8 ) + wxENUM_MEMBER( wxFONTENCODING_KOI8_U ) + wxENUM_MEMBER( wxFONTENCODING_ALTERNATIVE ) + wxENUM_MEMBER( wxFONTENCODING_BULGARIAN ) + wxENUM_MEMBER( wxFONTENCODING_CP437 ) + wxENUM_MEMBER( wxFONTENCODING_CP850 ) + wxENUM_MEMBER( wxFONTENCODING_CP852 ) + wxENUM_MEMBER( wxFONTENCODING_CP855 ) + wxENUM_MEMBER( wxFONTENCODING_CP866 ) + + wxENUM_MEMBER( wxFONTENCODING_CP874 ) + wxENUM_MEMBER( wxFONTENCODING_CP932 ) + wxENUM_MEMBER( wxFONTENCODING_CP936 ) + wxENUM_MEMBER( wxFONTENCODING_CP949 ) + wxENUM_MEMBER( wxFONTENCODING_CP950 ) + wxENUM_MEMBER( wxFONTENCODING_CP1250 ) + wxENUM_MEMBER( wxFONTENCODING_CP1251 ) + wxENUM_MEMBER( wxFONTENCODING_CP1252 ) + wxENUM_MEMBER( wxFONTENCODING_CP1253 ) + wxENUM_MEMBER( wxFONTENCODING_CP1254 ) + wxENUM_MEMBER( wxFONTENCODING_CP1255 ) + wxENUM_MEMBER( wxFONTENCODING_CP1256 ) + wxENUM_MEMBER( wxFONTENCODING_CP1257 ) + wxENUM_MEMBER( wxFONTENCODING_CP12_MAX ) + wxENUM_MEMBER( wxFONTENCODING_UTF7 ) + wxENUM_MEMBER( wxFONTENCODING_UTF8 ) + wxENUM_MEMBER( wxFONTENCODING_GB2312 ) + wxENUM_MEMBER( wxFONTENCODING_BIG5 ) + wxENUM_MEMBER( wxFONTENCODING_SHIFT_JIS ) + wxENUM_MEMBER( wxFONTENCODING_EUC_JP ) + wxENUM_MEMBER( wxFONTENCODING_UNICODE ) +wxEND_ENUM( wxFontEncoding ) +#endif + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// the config paths we use +#if wxUSE_CONFIG + +static const wxChar* FONTMAPPER_FONT_FROM_ENCODING_PATH = wxT("Encodings"); +static const wxChar* FONTMAPPER_FONT_DONT_ASK = wxT("none"); + +#endif // wxUSE_CONFIG + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// it may happen that while we're showing a dialog asking the user about +// something, another request for an encoding mapping arrives: in this case it +// is best to not do anything because otherwise we risk to enter an infinite +// loop so we create an object of this class on stack to test for this in all +// interactive functions +class ReentrancyBlocker +{ +public: + ReentrancyBlocker(bool& flag) : m_flagOld(flag), m_flag(flag) + { m_flag = true; } + ~ReentrancyBlocker() { m_flag = m_flagOld; } + +private: + bool m_flagOld; + bool& m_flag; + + DECLARE_NO_COPY_CLASS(ReentrancyBlocker) +}; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// ctor and dtor +// ---------------------------------------------------------------------------- + +wxFontMapper::wxFontMapper() +{ + m_windowParent = NULL; +} + +wxFontMapper::~wxFontMapper() +{ +} + +/* static */ +wxFontMapper *wxFontMapper::Get() +{ + wxFontMapperBase *fontmapper = wxFontMapperBase::Get(); + wxASSERT_MSG( !fontmapper->IsDummy(), + wxT("GUI code requested a wxFontMapper but we only have a wxFontMapperBase.") ); + + // Now return it anyway because there's a chance the GUI code might just + // only want to call wxFontMapperBase functions and it's better than + // crashing by returning NULL + return (wxFontMapper *)fontmapper; +} + +wxFontEncoding +wxFontMapper::CharsetToEncoding(const wxString& charset, bool interactive) +{ + // try the ways not needing the users intervention first + int encoding = wxFontMapperBase::NonInteractiveCharsetToEncoding(charset); + + // if we failed to find the encoding, ask the user -- unless disabled + if ( encoding == wxFONTENCODING_UNKNOWN ) + { + // this is the special value which disables asking the user (he had + // chosen to suppress this the last time) + encoding = wxFONTENCODING_SYSTEM; + } +#if wxUSE_CHOICEDLG + else if ( (encoding == wxFONTENCODING_SYSTEM) && interactive ) + { + // prepare the dialog data + + // the dialog title + wxString title(m_titleDialog); + if ( !title ) + title << wxTheApp->GetAppName() << _(": unknown charset"); + + // the message + wxString msg; + msg.Printf(_("The charset '%s' is unknown. You may select\nanother charset to replace it with or choose\n[Cancel] if it cannot be replaced"), charset.c_str()); + + // the list of choices + const size_t count = GetSupportedEncodingsCount(); + + wxString *encodingNamesTranslated = new wxString[count]; + + for ( size_t i = 0; i < count; i++ ) + { + encodingNamesTranslated[i] = GetEncodingDescription(GetEncoding(i)); + } + + // the parent window + wxWindow *parent = m_windowParent; + if ( !parent ) + parent = wxTheApp->GetTopWindow(); + + // do ask the user and get back the index in encodings table + int n = wxGetSingleChoiceIndex(msg, title, + count, + encodingNamesTranslated, + parent); + + delete [] encodingNamesTranslated; + + if ( n != -1 ) + { + encoding = GetEncoding(n); + } + +#if wxUSE_CONFIG && wxUSE_FILECONFIG + // save the result in the config now + wxFontMapperPathChanger path(this, FONTMAPPER_CHARSET_PATH); + if ( path.IsOk() ) + { + wxConfigBase *config = GetConfig(); + + // remember the alt encoding for this charset -- or remember that + // we don't know it + long value = n == -1 ? (long)wxFONTENCODING_UNKNOWN : (long)encoding; + if ( !config->Write(charset, value) ) + { + wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset.c_str()); + } + } +#endif // wxUSE_CONFIG + } +#else + wxUnusedVar(interactive); +#endif // wxUSE_CHOICEDLG + + return (wxFontEncoding)encoding; +} + +// ---------------------------------------------------------------------------- +// support for unknown encodings: we maintain a map between the +// (platform-specific) strings identifying them and our wxFontEncodings they +// correspond to which is used by GetFontForEncoding() function +// ---------------------------------------------------------------------------- + +bool wxFontMapper::TestAltEncoding(const wxString& configEntry, + wxFontEncoding encReplacement, + wxNativeEncodingInfo *info) +{ + if ( wxGetNativeFontEncoding(encReplacement, info) && + wxTestFontEncoding(*info) ) + { +#if wxUSE_CONFIG && wxUSE_FILECONFIG + // remember the mapping in the config + wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH); + + if ( path.IsOk() ) + { + GetConfig()->Write(configEntry, info->ToString()); + } +#else + wxUnusedVar(configEntry); +#endif // wxUSE_CONFIG + return true; + } + + return false; +} + +bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding, + wxNativeEncodingInfo *info, + const wxString& facename, + bool interactive) +{ +#if wxUSE_GUI + // we need a flag to prevent infinite recursion which happens, for + // example, when GetAltForEncoding() is called from an OnPaint() handler: + // in this case, wxYield() which is called from wxMessageBox() we use here + // will lead to another call of OnPaint() and hence to another call of + // GetAltForEncoding() -- and it is impossible to catch this from the user + // code because we are called from wxFont ctor implicitly. + + // assume we're always called from the main thread, so that it is safe to + // use a static var + static bool s_inGetAltForEncoding = false; + + if ( interactive && s_inGetAltForEncoding ) + return false; + + ReentrancyBlocker blocker(s_inGetAltForEncoding); +#endif // wxUSE_GUI + + wxCHECK_MSG( info, false, wxT("bad pointer in GetAltForEncoding") ); + + info->facename = facename; + + if ( encoding == wxFONTENCODING_DEFAULT ) + { + encoding = wxFont::GetDefaultEncoding(); + } + + // if we failed to load the system default encoding, something is really + // wrong and we'd better stop now -- otherwise we will go into endless + // recursion trying to create the font in the msg box with the error + // message + if ( encoding == wxFONTENCODING_SYSTEM ) + { + wxLogFatalError(_("can't load any font, aborting")); + + // wxLogFatalError doesn't return + } + + wxString configEntry, + encName = GetEncodingName(encoding); + if ( !facename.empty() ) + { + configEntry = facename + _T("_"); + } + configEntry += encName; + +#if wxUSE_CONFIG && wxUSE_FILECONFIG + // do we have a font spec for this encoding? + wxString fontinfo; + wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH); + if ( path.IsOk() ) + { + fontinfo = GetConfig()->Read(configEntry); + } + + // this special value means that we don't know of fonts for this + // encoding but, moreover, have already asked the user as well and he + // didn't specify any font neither + if ( fontinfo == FONTMAPPER_FONT_DONT_ASK ) + { + interactive = false; + } + else // use the info entered the last time + { + if ( !fontinfo.empty() && !facename.empty() ) + { + // we tried to find a match with facename -- now try without it + fontinfo = GetConfig()->Read(encName); + } + + if ( !fontinfo.empty() ) + { + if ( info->FromString(fontinfo) ) + { + if ( wxTestFontEncoding(*info) ) + { + // ok, got something + return true; + } + //else: no such fonts, look for something else + // (should we erase the outdated value?) + } + else + { + wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"), + fontinfo.c_str()); + } + } + //else: there is no information in config about this encoding + } +#endif // wxUSE_CONFIG + + // now try to map this encoding to a compatible one which we have on this + // system + wxFontEncodingArray equiv = wxEncodingConverter::GetAllEquivalents(encoding); + size_t count = equiv.GetCount(); + bool foundEquivEncoding = false; + wxFontEncoding equivEncoding = wxFONTENCODING_SYSTEM; + if ( count ) + { + for ( size_t i = 0; i < count && !foundEquivEncoding; i++ ) + { + // don't test for encoding itself, we already know we don't have it + if ( equiv[i] == encoding ) + continue; + + if ( TestAltEncoding(configEntry, equiv[i], info) ) + { + equivEncoding = equiv[i]; + + foundEquivEncoding = true; + } + } + } + + // ask the user +#if wxUSE_FONTDLG + if ( interactive ) + { + wxString title(m_titleDialog); + if ( !title ) + title << wxTheApp->GetAppName() << _(": unknown encoding"); + + // built the message + wxString encDesc = GetEncodingDescription(encoding), + msg; + if ( foundEquivEncoding ) + { + // ask the user if he wants to override found alternative encoding + msg.Printf(_("No font for displaying text in encoding '%s' found,\nbut an alternative encoding '%s' is available.\nDo you want to use this encoding (otherwise you will have to choose another one)?"), + encDesc.c_str(), GetEncodingDescription(equivEncoding).c_str()); + } + else + { + msg.Printf(_("No font for displaying text in encoding '%s' found.\nWould you like to select a font to be used for this encoding\n(otherwise the text in this encoding will not be shown correctly)?"), + encDesc.c_str()); + } + + // the question is different in 2 cases so the answer has to be + // interpreted differently as well + int answer = foundEquivEncoding ? wxNO : wxYES; + + if ( wxMessageBox(msg, title, + wxICON_QUESTION | wxYES_NO, + m_windowParent) == answer ) + { + wxFontData data; + data.SetEncoding(encoding); + data.EncodingInfo() = *info; + wxFontDialog dialog(m_windowParent, data); + if ( dialog.ShowModal() == wxID_OK ) + { + wxFontData retData = dialog.GetFontData(); + + *info = retData.EncodingInfo(); + info->encoding = retData.GetEncoding(); + +#if wxUSE_CONFIG && wxUSE_FILECONFIG + // remember this in the config + wxFontMapperPathChanger path2(this, + FONTMAPPER_FONT_FROM_ENCODING_PATH); + if ( path2.IsOk() ) + { + GetConfig()->Write(configEntry, info->ToString()); + } +#endif // wxUSE_CONFIG + + return true; + } + //else: the user canceled the font selection dialog + } + else + { + // the user doesn't want to select a font for this encoding + // or selected to use equivalent encoding + // + // remember it to avoid asking the same question again later +#if wxUSE_CONFIG && wxUSE_FILECONFIG + wxFontMapperPathChanger path2(this, + FONTMAPPER_FONT_FROM_ENCODING_PATH); + if ( path2.IsOk() ) + { + GetConfig()->Write + ( + configEntry, + foundEquivEncoding ? info->ToString().c_str() + : FONTMAPPER_FONT_DONT_ASK + ); + } +#endif // wxUSE_CONFIG + } + } + //else: we're in non-interactive mode +#else + wxUnusedVar(equivEncoding); +#endif // wxUSE_FONTDLG + + return foundEquivEncoding; +} + +bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding, + wxFontEncoding *encodingAlt, + const wxString& facename, + bool interactive) +{ + wxCHECK_MSG( encodingAlt, false, + _T("wxFontEncoding::GetAltForEncoding(): NULL pointer") ); + + wxNativeEncodingInfo info; + if ( !GetAltForEncoding(encoding, &info, facename, interactive) ) + return false; + + *encodingAlt = info.encoding; + + return true; +} + +bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding, + const wxString& facename) +{ + wxNativeEncodingInfo info; + + if ( !wxGetNativeFontEncoding(encoding, &info) ) + return false; + + info.facename = facename; + return wxTestFontEncoding(info); +} + +#endif // wxUSE_FONTMAP diff --git a/Source/3rd Party/wx/src/common/fontpickercmn.cpp b/Source/3rd Party/wx/src/common/fontpickercmn.cpp index 08808e996..c4af53f25 100644 --- a/Source/3rd Party/wx/src/common/fontpickercmn.cpp +++ b/Source/3rd Party/wx/src/common/fontpickercmn.cpp @@ -1,181 +1,181 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/fontpickercmn.cpp -// Purpose: wxFontPickerCtrl class implementation -// Author: Francesco Montorsi -// Modified by: -// Created: 15/04/2006 -// RCS-ID: $Id: fontpickercmn.cpp 42999 2006-11-03 21:54:13Z VZ $ -// Copyright: (c) Francesco Montorsi -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FONTPICKERCTRL - -#include "wx/fontpicker.h" - -#ifndef WX_PRECOMP - #include "wx/textctrl.h" -#endif - -#include "wx/fontenum.h" -#include "wx/tokenzr.h" - -// ============================================================================ -// implementation -// ============================================================================ - -const wxChar wxFontPickerCtrlNameStr[] = wxT("fontpicker"); -const wxChar wxFontPickerWidgetNameStr[] = wxT("fontpickerwidget"); - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_FONTPICKER_CHANGED) -IMPLEMENT_DYNAMIC_CLASS(wxFontPickerCtrl, wxPickerBase) -IMPLEMENT_DYNAMIC_CLASS(wxFontPickerEvent, wxCommandEvent) - -// ---------------------------------------------------------------------------- -// wxFontPickerCtrl -// ---------------------------------------------------------------------------- - -#define M_PICKER ((wxFontPickerWidget*)m_picker) - -bool wxFontPickerCtrl::Create( wxWindow *parent, wxWindowID id, - const wxFont &initial, - const wxPoint &pos, const wxSize &size, - long style, const wxValidator& validator, - const wxString &name ) -{ - if (!wxPickerBase::CreateBase(parent, id, - Font2String(initial.IsOk() ? initial - : *wxNORMAL_FONT), - pos, size, style, validator, name)) - return false; - - // the picker of a wxFontPickerCtrl is a wxFontPickerWidget - m_picker = new wxFontPickerWidget(this, wxID_ANY, initial, - wxDefaultPosition, wxDefaultSize, - GetPickerStyle(style)); - // complete sizer creation - wxPickerBase::PostCreation(); - - m_picker->Connect(wxEVT_COMMAND_FONTPICKER_CHANGED, - wxFontPickerEventHandler(wxFontPickerCtrl::OnFontChange), - NULL, this); - - return true; -} - -wxString wxFontPickerCtrl::Font2String(const wxFont &f) -{ - wxString ret = f.GetNativeFontInfoUserDesc(); -#ifdef __WXMSW__ - // on wxMSW the encoding of the font is appended at the end of the string; - // since encoding is not very user-friendly we remove it. - wxFontEncoding enc = f.GetEncoding(); - if ( enc != wxFONTENCODING_DEFAULT && enc != wxFONTENCODING_SYSTEM ) - ret = ret.BeforeLast(wxT(' ')); -#endif - return ret; -} - -wxFont wxFontPickerCtrl::String2Font(const wxString &s) -{ - wxString str(s); - wxFont ret; - double n; - - // put a limit on the maximum point size which the user can enter - // NOTE: we suppose the last word of given string is the pointsize - wxString size = str.AfterLast(wxT(' ')); - if (size.ToDouble(&n)) - { - if (n < 1) - str = str.Left(str.length() - size.length()) + wxT("1"); - else if (n >= m_nMaxPointSize) - str = str.Left(str.length() - size.length()) + - wxString::Format(wxT("%d"), m_nMaxPointSize); - } - - if (!ret.SetNativeFontInfoUserDesc(str)) - return wxNullFont; - - return ret; -} - -void wxFontPickerCtrl::SetSelectedFont(const wxFont &f) -{ - M_PICKER->SetSelectedFont(f); - UpdateTextCtrlFromPicker(); -} - -void wxFontPickerCtrl::UpdatePickerFromTextCtrl() -{ - wxASSERT(m_text); - - if (m_bIgnoreNextTextCtrlUpdate) - { - // ignore this update - m_bIgnoreNextTextCtrlUpdate = false; - return; - } - - // NB: we don't use the wxFont::wxFont(const wxString &) constructor - // since that constructor expects the native font description - // string returned by wxFont::GetNativeFontInfoDesc() and not - // the user-friendly one returned by wxFont::GetNativeFontInfoUserDesc() - wxFont f = String2Font(m_text->GetValue()); - if (!f.Ok()) - return; // invalid user input - - if (M_PICKER->GetSelectedFont() != f) - { - M_PICKER->SetSelectedFont(f); - - // fire an event - wxFontPickerEvent event(this, GetId(), f); - GetEventHandler()->ProcessEvent(event); - } -} - -void wxFontPickerCtrl::UpdateTextCtrlFromPicker() -{ - if (!m_text) - return; // no textctrl to update - - // NOTE: this SetValue() will generate an unwanted wxEVT_COMMAND_TEXT_UPDATED - // which will trigger a unneeded UpdateFromTextCtrl(); thus before using - // SetValue() we set the m_bIgnoreNextTextCtrlUpdate flag... - m_bIgnoreNextTextCtrlUpdate = true; - m_text->SetValue(Font2String(M_PICKER->GetSelectedFont())); -} - - - -// ---------------------------------------------------------------------------- -// wxFontPickerCtrl - event handlers -// ---------------------------------------------------------------------------- - -void wxFontPickerCtrl::OnFontChange(wxFontPickerEvent &ev) -{ - UpdateTextCtrlFromPicker(); - - // the wxFontPickerWidget sent us a colour-change notification. - // forward this event to our parent - wxFontPickerEvent event(this, GetId(), ev.GetFont()); - GetEventHandler()->ProcessEvent(event); -} - -#endif // wxUSE_FONTPICKERCTRL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/fontpickercmn.cpp +// Purpose: wxFontPickerCtrl class implementation +// Author: Francesco Montorsi +// Modified by: +// Created: 15/04/2006 +// RCS-ID: $Id: fontpickercmn.cpp 42999 2006-11-03 21:54:13Z VZ $ +// Copyright: (c) Francesco Montorsi +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FONTPICKERCTRL + +#include "wx/fontpicker.h" + +#ifndef WX_PRECOMP + #include "wx/textctrl.h" +#endif + +#include "wx/fontenum.h" +#include "wx/tokenzr.h" + +// ============================================================================ +// implementation +// ============================================================================ + +const wxChar wxFontPickerCtrlNameStr[] = wxT("fontpicker"); +const wxChar wxFontPickerWidgetNameStr[] = wxT("fontpickerwidget"); + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_FONTPICKER_CHANGED) +IMPLEMENT_DYNAMIC_CLASS(wxFontPickerCtrl, wxPickerBase) +IMPLEMENT_DYNAMIC_CLASS(wxFontPickerEvent, wxCommandEvent) + +// ---------------------------------------------------------------------------- +// wxFontPickerCtrl +// ---------------------------------------------------------------------------- + +#define M_PICKER ((wxFontPickerWidget*)m_picker) + +bool wxFontPickerCtrl::Create( wxWindow *parent, wxWindowID id, + const wxFont &initial, + const wxPoint &pos, const wxSize &size, + long style, const wxValidator& validator, + const wxString &name ) +{ + if (!wxPickerBase::CreateBase(parent, id, + Font2String(initial.IsOk() ? initial + : *wxNORMAL_FONT), + pos, size, style, validator, name)) + return false; + + // the picker of a wxFontPickerCtrl is a wxFontPickerWidget + m_picker = new wxFontPickerWidget(this, wxID_ANY, initial, + wxDefaultPosition, wxDefaultSize, + GetPickerStyle(style)); + // complete sizer creation + wxPickerBase::PostCreation(); + + m_picker->Connect(wxEVT_COMMAND_FONTPICKER_CHANGED, + wxFontPickerEventHandler(wxFontPickerCtrl::OnFontChange), + NULL, this); + + return true; +} + +wxString wxFontPickerCtrl::Font2String(const wxFont &f) +{ + wxString ret = f.GetNativeFontInfoUserDesc(); +#ifdef __WXMSW__ + // on wxMSW the encoding of the font is appended at the end of the string; + // since encoding is not very user-friendly we remove it. + wxFontEncoding enc = f.GetEncoding(); + if ( enc != wxFONTENCODING_DEFAULT && enc != wxFONTENCODING_SYSTEM ) + ret = ret.BeforeLast(wxT(' ')); +#endif + return ret; +} + +wxFont wxFontPickerCtrl::String2Font(const wxString &s) +{ + wxString str(s); + wxFont ret; + double n; + + // put a limit on the maximum point size which the user can enter + // NOTE: we suppose the last word of given string is the pointsize + wxString size = str.AfterLast(wxT(' ')); + if (size.ToDouble(&n)) + { + if (n < 1) + str = str.Left(str.length() - size.length()) + wxT("1"); + else if (n >= m_nMaxPointSize) + str = str.Left(str.length() - size.length()) + + wxString::Format(wxT("%d"), m_nMaxPointSize); + } + + if (!ret.SetNativeFontInfoUserDesc(str)) + return wxNullFont; + + return ret; +} + +void wxFontPickerCtrl::SetSelectedFont(const wxFont &f) +{ + M_PICKER->SetSelectedFont(f); + UpdateTextCtrlFromPicker(); +} + +void wxFontPickerCtrl::UpdatePickerFromTextCtrl() +{ + wxASSERT(m_text); + + if (m_bIgnoreNextTextCtrlUpdate) + { + // ignore this update + m_bIgnoreNextTextCtrlUpdate = false; + return; + } + + // NB: we don't use the wxFont::wxFont(const wxString &) constructor + // since that constructor expects the native font description + // string returned by wxFont::GetNativeFontInfoDesc() and not + // the user-friendly one returned by wxFont::GetNativeFontInfoUserDesc() + wxFont f = String2Font(m_text->GetValue()); + if (!f.Ok()) + return; // invalid user input + + if (M_PICKER->GetSelectedFont() != f) + { + M_PICKER->SetSelectedFont(f); + + // fire an event + wxFontPickerEvent event(this, GetId(), f); + GetEventHandler()->ProcessEvent(event); + } +} + +void wxFontPickerCtrl::UpdateTextCtrlFromPicker() +{ + if (!m_text) + return; // no textctrl to update + + // NOTE: this SetValue() will generate an unwanted wxEVT_COMMAND_TEXT_UPDATED + // which will trigger a unneeded UpdateFromTextCtrl(); thus before using + // SetValue() we set the m_bIgnoreNextTextCtrlUpdate flag... + m_bIgnoreNextTextCtrlUpdate = true; + m_text->SetValue(Font2String(M_PICKER->GetSelectedFont())); +} + + + +// ---------------------------------------------------------------------------- +// wxFontPickerCtrl - event handlers +// ---------------------------------------------------------------------------- + +void wxFontPickerCtrl::OnFontChange(wxFontPickerEvent &ev) +{ + UpdateTextCtrlFromPicker(); + + // the wxFontPickerWidget sent us a colour-change notification. + // forward this event to our parent + wxFontPickerEvent event(this, GetId(), ev.GetFont()); + GetEventHandler()->ProcessEvent(event); +} + +#endif // wxUSE_FONTPICKERCTRL diff --git a/Source/3rd Party/wx/src/common/framecmn.cpp b/Source/3rd Party/wx/src/common/framecmn.cpp index 4b7e3bc17..65c3c48ac 100644 --- a/Source/3rd Party/wx/src/common/framecmn.cpp +++ b/Source/3rd Party/wx/src/common/framecmn.cpp @@ -1,590 +1,590 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/framecmn.cpp -// Purpose: common (for all platforms) wxFrame functions -// Author: Julian Smart, Vadim Zeitlin -// Created: 01/02/97 -// Id: $Id: framecmn.cpp 51463 2008-01-30 21:31:03Z VZ $ -// Copyright: (c) 1998 Robert Roebling and Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/frame.h" - -#ifndef WX_PRECOMP - #include "wx/menu.h" - #include "wx/menuitem.h" - #include "wx/dcclient.h" - #include "wx/toolbar.h" - #include "wx/statusbr.h" -#endif // WX_PRECOMP - -// ---------------------------------------------------------------------------- -// event table -// ---------------------------------------------------------------------------- - -#if wxUSE_MENUS && wxUSE_STATUSBAR - -BEGIN_EVENT_TABLE(wxFrameBase, wxTopLevelWindow) - EVT_MENU_OPEN(wxFrameBase::OnMenuOpen) - EVT_MENU_CLOSE(wxFrameBase::OnMenuClose) - - EVT_MENU_HIGHLIGHT_ALL(wxFrameBase::OnMenuHighlight) -END_EVENT_TABLE() - -#endif // wxUSE_MENUS && wxUSE_STATUSBAR - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// construction/destruction -// ---------------------------------------------------------------------------- - -wxFrameBase::wxFrameBase() -{ -#if wxUSE_MENUS - m_frameMenuBar = NULL; -#endif // wxUSE_MENUS - -#if wxUSE_TOOLBAR - m_frameToolBar = NULL; -#endif // wxUSE_TOOLBAR - -#if wxUSE_STATUSBAR - m_frameStatusBar = NULL; -#endif // wxUSE_STATUSBAR - - m_statusBarPane = 0; -} - -wxFrameBase::~wxFrameBase() -{ - // this destructor is required for Darwin -} - -wxFrame *wxFrameBase::New(wxWindow *parent, - wxWindowID id, - const wxString& title, - const wxPoint& pos, - const wxSize& size, - long style, - const wxString& name) -{ - return new wxFrame(parent, id, title, pos, size, style, name); -} - -void wxFrameBase::DeleteAllBars() -{ -#if wxUSE_MENUS - if ( m_frameMenuBar ) - { - delete m_frameMenuBar; - m_frameMenuBar = (wxMenuBar *) NULL; - } -#endif // wxUSE_MENUS - -#if wxUSE_STATUSBAR - if ( m_frameStatusBar ) - { - delete m_frameStatusBar; - m_frameStatusBar = (wxStatusBar *) NULL; - } -#endif // wxUSE_STATUSBAR - -#if wxUSE_TOOLBAR - if ( m_frameToolBar ) - { - delete m_frameToolBar; - m_frameToolBar = (wxToolBar *) NULL; - } -#endif // wxUSE_TOOLBAR -} - -bool wxFrameBase::IsOneOfBars(const wxWindow *win) const -{ -#if wxUSE_MENUS - if ( win == GetMenuBar() ) - return true; -#endif // wxUSE_MENUS - -#if wxUSE_STATUSBAR - if ( win == GetStatusBar() ) - return true; -#endif // wxUSE_STATUSBAR - -#if wxUSE_TOOLBAR - if ( win == GetToolBar() ) - return true; -#endif // wxUSE_TOOLBAR - - return false; -} - -// ---------------------------------------------------------------------------- -// wxFrame size management: we exclude the areas taken by menu/status/toolbars -// from the client area, so the client area is what's really available for the -// frame contents -// ---------------------------------------------------------------------------- - -// get the origin of the client area in the client coordinates -wxPoint wxFrameBase::GetClientAreaOrigin() const -{ - wxPoint pt = wxTopLevelWindow::GetClientAreaOrigin(); - -#if wxUSE_TOOLBAR && !defined(__WXUNIVERSAL__) - wxToolBar *toolbar = GetToolBar(); - if ( toolbar && toolbar->IsShown() ) - { - int w, h; - toolbar->GetSize(&w, &h); - - if ( toolbar->GetWindowStyleFlag() & wxTB_VERTICAL ) - { - pt.x += w; - } - else - { - pt.y += h; - } - } -#endif // wxUSE_TOOLBAR - - return pt; -} - - -void wxFrameBase::SendSizeEvent() -{ - const wxSize size = GetSize(); - wxSizeEvent event( size, GetId() ); - event.SetEventObject( this ); - GetEventHandler()->AddPendingEvent( event ); - -#ifdef __WXGTK__ - // SendSizeEvent is typically called when a toolbar is shown - // or hidden, but sending the size event alone is not enough - // to trigger a full layout. - ((wxFrame*)this)->GtkOnSize( -#ifndef __WXGTK20__ - 0, 0, size.x, size.y -#endif // __WXGTK20__ - ); -#endif // __WXGTK__ -} - - -// ---------------------------------------------------------------------------- -// misc -// ---------------------------------------------------------------------------- - -bool wxFrameBase::ProcessCommand(int id) -{ -#if wxUSE_MENUS - wxMenuBar *bar = GetMenuBar(); - if ( !bar ) - return false; - - wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id); - commandEvent.SetEventObject(this); - - wxMenuItem *item = bar->FindItem(id); - if (item) - { - if (!item->IsEnabled()) - return true; - - if ((item->GetKind() == wxITEM_RADIO) && item->IsChecked() ) - return true; - - if (item->IsCheckable()) - { - item->Toggle(); - - // use the new value - commandEvent.SetInt(item->IsChecked()); - } - } - - return GetEventHandler()->ProcessEvent(commandEvent); -#else // !wxUSE_MENUS - return false; -#endif // wxUSE_MENUS/!wxUSE_MENUS -} - -// Do the UI update processing for this window. This is -// provided for the application to call if it wants to -// force a UI update, particularly for the menus and toolbar. -void wxFrameBase::UpdateWindowUI(long flags) -{ - wxWindowBase::UpdateWindowUI(flags); - -#if wxUSE_TOOLBAR - if (GetToolBar()) - GetToolBar()->UpdateWindowUI(flags); -#endif - -#if wxUSE_MENUS - if (GetMenuBar()) - { - if ((flags & wxUPDATE_UI_FROMIDLE) && !wxUSE_IDLEMENUUPDATES) - { - // If coming from an idle event, we only - // want to update the menus if we're - // in the wxUSE_IDLEMENUUPDATES configuration: - // so if we're not, do nothing - } - else - DoMenuUpdates(); - } -#endif // wxUSE_MENUS -} - -// ---------------------------------------------------------------------------- -// event handlers for status bar updates from menus -// ---------------------------------------------------------------------------- - -#if wxUSE_MENUS && wxUSE_STATUSBAR - -void wxFrameBase::OnMenuHighlight(wxMenuEvent& event) -{ -#if wxUSE_STATUSBAR - (void)ShowMenuHelp(GetStatusBar(), event.GetMenuId()); -#endif // wxUSE_STATUSBAR -} - -#if !wxUSE_IDLEMENUUPDATES -void wxFrameBase::OnMenuOpen(wxMenuEvent& event) -#else -void wxFrameBase::OnMenuOpen(wxMenuEvent& WXUNUSED(event)) -#endif -{ -#if !wxUSE_IDLEMENUUPDATES - DoMenuUpdates(event.GetMenu()); -#endif // !wxUSE_IDLEMENUUPDATES -} - -void wxFrameBase::OnMenuClose(wxMenuEvent& WXUNUSED(event)) -{ - // do we have real status text to restore? - if ( !m_oldStatusText.empty() ) - { - if ( m_statusBarPane >= 0 ) - { - wxStatusBar *statbar = GetStatusBar(); - if ( statbar ) - statbar->SetStatusText(m_oldStatusText, m_statusBarPane); - } - - m_oldStatusText.clear(); - } -} - -#endif // wxUSE_MENUS && wxUSE_STATUSBAR - -// Implement internal behaviour (menu updating on some platforms) -void wxFrameBase::OnInternalIdle() -{ - wxTopLevelWindow::OnInternalIdle(); - -#if wxUSE_MENUS && wxUSE_IDLEMENUUPDATES - if (wxUpdateUIEvent::CanUpdate(this)) - DoMenuUpdates(); -#endif -} - -// ---------------------------------------------------------------------------- -// status bar stuff -// ---------------------------------------------------------------------------- - -#if wxUSE_STATUSBAR - -wxStatusBar* wxFrameBase::CreateStatusBar(int number, - long style, - wxWindowID id, - const wxString& name) -{ - // the main status bar can only be created once (or else it should be - // deleted before calling CreateStatusBar() again) - wxCHECK_MSG( !m_frameStatusBar, (wxStatusBar *)NULL, - wxT("recreating status bar in wxFrame") ); - - SetStatusBar(OnCreateStatusBar(number, style, id, name)); - - return m_frameStatusBar; -} - -wxStatusBar *wxFrameBase::OnCreateStatusBar(int number, - long style, - wxWindowID id, - const wxString& name) -{ - wxStatusBar *statusBar = new wxStatusBar(this, id, style, name); - - statusBar->SetFieldsCount(number); - - return statusBar; -} - -void wxFrameBase::SetStatusText(const wxString& text, int number) -{ - wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") ); - - m_frameStatusBar->SetStatusText(text, number); -} - -void wxFrameBase::SetStatusWidths(int n, const int widths_field[] ) -{ - wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set widths for") ); - - m_frameStatusBar->SetStatusWidths(n, widths_field); - - PositionStatusBar(); -} - -void wxFrameBase::PushStatusText(const wxString& text, int number) -{ - wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") ); - - m_frameStatusBar->PushStatusText(text, number); -} - -void wxFrameBase::PopStatusText(int number) -{ - wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") ); - - m_frameStatusBar->PopStatusText(number); -} - -bool wxFrameBase::ShowMenuHelp(wxStatusBar *WXUNUSED(statbar), int menuId) -{ -#if wxUSE_MENUS - // if no help string found, we will clear the status bar text - wxString helpString; - bool show = menuId != wxID_SEPARATOR && menuId != -2 /* wxID_TITLE */; - - if ( show ) - { - wxMenuBar *menuBar = GetMenuBar(); - if ( menuBar ) - { - // it's ok if we don't find the item because it might belong - // to the popup menu - wxMenuItem *item = menuBar->FindItem(menuId); - if ( item ) - helpString = item->GetHelp(); - } - } - - DoGiveHelp(helpString, show); - - return !helpString.empty(); -#else // !wxUSE_MENUS - return false; -#endif // wxUSE_MENUS/!wxUSE_MENUS -} - -void wxFrameBase::SetStatusBar(wxStatusBar *statBar) -{ - bool hadBar = m_frameStatusBar != NULL; - m_frameStatusBar = statBar; - - if ( (m_frameStatusBar != NULL) != hadBar ) - { - PositionStatusBar(); - - DoLayout(); - } -} - -#endif // wxUSE_STATUSBAR - -#if wxUSE_MENUS || wxUSE_TOOLBAR -void wxFrameBase::DoGiveHelp(const wxString& text, bool show) -{ -#if wxUSE_STATUSBAR - if ( m_statusBarPane < 0 ) - { - // status bar messages disabled - return; - } - - wxStatusBar *statbar = GetStatusBar(); - if ( !statbar ) - return; - - wxString help; - if ( show ) - { - help = text; - - // remember the old status bar text if this is the first time we're - // called since the menu has been opened as we're going to overwrite it - // in our DoGiveHelp() and we want to restore it when the menu is - // closed - // - // note that it would be logical to do this in OnMenuOpen() but under - // MSW we get an EVT_MENU_HIGHLIGHT before EVT_MENU_OPEN, strangely - // enough, and so this doesn't work and instead we use the ugly trick - // with using special m_oldStatusText value as "menu opened" (but it is - // arguably better than adding yet another member variable to wxFrame - // on all platforms) - if ( m_oldStatusText.empty() ) - { - m_oldStatusText = statbar->GetStatusText(m_statusBarPane); - if ( m_oldStatusText.empty() ) - { - // use special value to prevent us from doing this the next time - m_oldStatusText += _T('\0'); - } - } - } - else // hide the status bar text - { - // i.e. restore the old one - help = m_oldStatusText; - - // make sure we get the up to date text when showing it the next time - m_oldStatusText.clear(); - } - - statbar->SetStatusText(help, m_statusBarPane); -#else - wxUnusedVar(text); - wxUnusedVar(show); -#endif // wxUSE_STATUSBAR -} -#endif // wxUSE_MENUS || wxUSE_TOOLBAR - - -// ---------------------------------------------------------------------------- -// toolbar stuff -// ---------------------------------------------------------------------------- - -#if wxUSE_TOOLBAR - -wxToolBar* wxFrameBase::CreateToolBar(long style, - wxWindowID id, - const wxString& name) -{ - // the main toolbar can't be recreated (unless it was explicitly deleted - // before) - wxCHECK_MSG( !m_frameToolBar, (wxToolBar *)NULL, - wxT("recreating toolbar in wxFrame") ); - - if ( style == -1 ) - { - // use default style - // - // NB: we don't specify the default value in the method declaration - // because - // a) this allows us to have different defaults for different - // platforms (even if we don't have them right now) - // b) we don't need to include wx/toolbar.h in the header then - style = wxBORDER_NONE | wxTB_HORIZONTAL | wxTB_FLAT; - } - - SetToolBar(OnCreateToolBar(style, id, name)); - - return m_frameToolBar; -} - -wxToolBar* wxFrameBase::OnCreateToolBar(long style, - wxWindowID id, - const wxString& name) -{ -#if defined(__WXWINCE__) && defined(__POCKETPC__) - return new wxToolMenuBar(this, id, - wxDefaultPosition, wxDefaultSize, - style, name); -#else - return new wxToolBar(this, id, - wxDefaultPosition, wxDefaultSize, - style, name); -#endif -} - -void wxFrameBase::SetToolBar(wxToolBar *toolbar) -{ - bool hadBar = m_frameToolBar != NULL; - m_frameToolBar = toolbar; - - if ( (m_frameToolBar != NULL) != hadBar ) - { - PositionToolBar(); - - DoLayout(); - } -} - -#endif // wxUSE_TOOLBAR - -// ---------------------------------------------------------------------------- -// menus -// ---------------------------------------------------------------------------- - -#if wxUSE_MENUS - -// update all menus -void wxFrameBase::DoMenuUpdates(wxMenu* menu) -{ - if (menu) - { - wxEvtHandler* source = GetEventHandler(); - menu->UpdateUI(source); - } - else - { - wxMenuBar* bar = GetMenuBar(); - if (bar != NULL) - bar->UpdateMenus(); - } -} - -void wxFrameBase::DetachMenuBar() -{ - if ( m_frameMenuBar ) - { - m_frameMenuBar->Detach(); - m_frameMenuBar = NULL; - } -} - -void wxFrameBase::AttachMenuBar(wxMenuBar *menubar) -{ - if ( menubar ) - { - menubar->Attach((wxFrame *)this); - m_frameMenuBar = menubar; - } -} - -void wxFrameBase::SetMenuBar(wxMenuBar *menubar) -{ - if ( menubar == GetMenuBar() ) - { - // nothing to do - return; - } - - DetachMenuBar(); - - this->AttachMenuBar(menubar); -} - -#endif // wxUSE_MENUS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/framecmn.cpp +// Purpose: common (for all platforms) wxFrame functions +// Author: Julian Smart, Vadim Zeitlin +// Created: 01/02/97 +// Id: $Id: framecmn.cpp 51463 2008-01-30 21:31:03Z VZ $ +// Copyright: (c) 1998 Robert Roebling and Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/frame.h" + +#ifndef WX_PRECOMP + #include "wx/menu.h" + #include "wx/menuitem.h" + #include "wx/dcclient.h" + #include "wx/toolbar.h" + #include "wx/statusbr.h" +#endif // WX_PRECOMP + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +#if wxUSE_MENUS && wxUSE_STATUSBAR + +BEGIN_EVENT_TABLE(wxFrameBase, wxTopLevelWindow) + EVT_MENU_OPEN(wxFrameBase::OnMenuOpen) + EVT_MENU_CLOSE(wxFrameBase::OnMenuClose) + + EVT_MENU_HIGHLIGHT_ALL(wxFrameBase::OnMenuHighlight) +END_EVENT_TABLE() + +#endif // wxUSE_MENUS && wxUSE_STATUSBAR + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// construction/destruction +// ---------------------------------------------------------------------------- + +wxFrameBase::wxFrameBase() +{ +#if wxUSE_MENUS + m_frameMenuBar = NULL; +#endif // wxUSE_MENUS + +#if wxUSE_TOOLBAR + m_frameToolBar = NULL; +#endif // wxUSE_TOOLBAR + +#if wxUSE_STATUSBAR + m_frameStatusBar = NULL; +#endif // wxUSE_STATUSBAR + + m_statusBarPane = 0; +} + +wxFrameBase::~wxFrameBase() +{ + // this destructor is required for Darwin +} + +wxFrame *wxFrameBase::New(wxWindow *parent, + wxWindowID id, + const wxString& title, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + return new wxFrame(parent, id, title, pos, size, style, name); +} + +void wxFrameBase::DeleteAllBars() +{ +#if wxUSE_MENUS + if ( m_frameMenuBar ) + { + delete m_frameMenuBar; + m_frameMenuBar = (wxMenuBar *) NULL; + } +#endif // wxUSE_MENUS + +#if wxUSE_STATUSBAR + if ( m_frameStatusBar ) + { + delete m_frameStatusBar; + m_frameStatusBar = (wxStatusBar *) NULL; + } +#endif // wxUSE_STATUSBAR + +#if wxUSE_TOOLBAR + if ( m_frameToolBar ) + { + delete m_frameToolBar; + m_frameToolBar = (wxToolBar *) NULL; + } +#endif // wxUSE_TOOLBAR +} + +bool wxFrameBase::IsOneOfBars(const wxWindow *win) const +{ +#if wxUSE_MENUS + if ( win == GetMenuBar() ) + return true; +#endif // wxUSE_MENUS + +#if wxUSE_STATUSBAR + if ( win == GetStatusBar() ) + return true; +#endif // wxUSE_STATUSBAR + +#if wxUSE_TOOLBAR + if ( win == GetToolBar() ) + return true; +#endif // wxUSE_TOOLBAR + + return false; +} + +// ---------------------------------------------------------------------------- +// wxFrame size management: we exclude the areas taken by menu/status/toolbars +// from the client area, so the client area is what's really available for the +// frame contents +// ---------------------------------------------------------------------------- + +// get the origin of the client area in the client coordinates +wxPoint wxFrameBase::GetClientAreaOrigin() const +{ + wxPoint pt = wxTopLevelWindow::GetClientAreaOrigin(); + +#if wxUSE_TOOLBAR && !defined(__WXUNIVERSAL__) + wxToolBar *toolbar = GetToolBar(); + if ( toolbar && toolbar->IsShown() ) + { + int w, h; + toolbar->GetSize(&w, &h); + + if ( toolbar->GetWindowStyleFlag() & wxTB_VERTICAL ) + { + pt.x += w; + } + else + { + pt.y += h; + } + } +#endif // wxUSE_TOOLBAR + + return pt; +} + + +void wxFrameBase::SendSizeEvent() +{ + const wxSize size = GetSize(); + wxSizeEvent event( size, GetId() ); + event.SetEventObject( this ); + GetEventHandler()->AddPendingEvent( event ); + +#ifdef __WXGTK__ + // SendSizeEvent is typically called when a toolbar is shown + // or hidden, but sending the size event alone is not enough + // to trigger a full layout. + ((wxFrame*)this)->GtkOnSize( +#ifndef __WXGTK20__ + 0, 0, size.x, size.y +#endif // __WXGTK20__ + ); +#endif // __WXGTK__ +} + + +// ---------------------------------------------------------------------------- +// misc +// ---------------------------------------------------------------------------- + +bool wxFrameBase::ProcessCommand(int id) +{ +#if wxUSE_MENUS + wxMenuBar *bar = GetMenuBar(); + if ( !bar ) + return false; + + wxCommandEvent commandEvent(wxEVT_COMMAND_MENU_SELECTED, id); + commandEvent.SetEventObject(this); + + wxMenuItem *item = bar->FindItem(id); + if (item) + { + if (!item->IsEnabled()) + return true; + + if ((item->GetKind() == wxITEM_RADIO) && item->IsChecked() ) + return true; + + if (item->IsCheckable()) + { + item->Toggle(); + + // use the new value + commandEvent.SetInt(item->IsChecked()); + } + } + + return GetEventHandler()->ProcessEvent(commandEvent); +#else // !wxUSE_MENUS + return false; +#endif // wxUSE_MENUS/!wxUSE_MENUS +} + +// Do the UI update processing for this window. This is +// provided for the application to call if it wants to +// force a UI update, particularly for the menus and toolbar. +void wxFrameBase::UpdateWindowUI(long flags) +{ + wxWindowBase::UpdateWindowUI(flags); + +#if wxUSE_TOOLBAR + if (GetToolBar()) + GetToolBar()->UpdateWindowUI(flags); +#endif + +#if wxUSE_MENUS + if (GetMenuBar()) + { + if ((flags & wxUPDATE_UI_FROMIDLE) && !wxUSE_IDLEMENUUPDATES) + { + // If coming from an idle event, we only + // want to update the menus if we're + // in the wxUSE_IDLEMENUUPDATES configuration: + // so if we're not, do nothing + } + else + DoMenuUpdates(); + } +#endif // wxUSE_MENUS +} + +// ---------------------------------------------------------------------------- +// event handlers for status bar updates from menus +// ---------------------------------------------------------------------------- + +#if wxUSE_MENUS && wxUSE_STATUSBAR + +void wxFrameBase::OnMenuHighlight(wxMenuEvent& event) +{ +#if wxUSE_STATUSBAR + (void)ShowMenuHelp(GetStatusBar(), event.GetMenuId()); +#endif // wxUSE_STATUSBAR +} + +#if !wxUSE_IDLEMENUUPDATES +void wxFrameBase::OnMenuOpen(wxMenuEvent& event) +#else +void wxFrameBase::OnMenuOpen(wxMenuEvent& WXUNUSED(event)) +#endif +{ +#if !wxUSE_IDLEMENUUPDATES + DoMenuUpdates(event.GetMenu()); +#endif // !wxUSE_IDLEMENUUPDATES +} + +void wxFrameBase::OnMenuClose(wxMenuEvent& WXUNUSED(event)) +{ + // do we have real status text to restore? + if ( !m_oldStatusText.empty() ) + { + if ( m_statusBarPane >= 0 ) + { + wxStatusBar *statbar = GetStatusBar(); + if ( statbar ) + statbar->SetStatusText(m_oldStatusText, m_statusBarPane); + } + + m_oldStatusText.clear(); + } +} + +#endif // wxUSE_MENUS && wxUSE_STATUSBAR + +// Implement internal behaviour (menu updating on some platforms) +void wxFrameBase::OnInternalIdle() +{ + wxTopLevelWindow::OnInternalIdle(); + +#if wxUSE_MENUS && wxUSE_IDLEMENUUPDATES + if (wxUpdateUIEvent::CanUpdate(this)) + DoMenuUpdates(); +#endif +} + +// ---------------------------------------------------------------------------- +// status bar stuff +// ---------------------------------------------------------------------------- + +#if wxUSE_STATUSBAR + +wxStatusBar* wxFrameBase::CreateStatusBar(int number, + long style, + wxWindowID id, + const wxString& name) +{ + // the main status bar can only be created once (or else it should be + // deleted before calling CreateStatusBar() again) + wxCHECK_MSG( !m_frameStatusBar, (wxStatusBar *)NULL, + wxT("recreating status bar in wxFrame") ); + + SetStatusBar(OnCreateStatusBar(number, style, id, name)); + + return m_frameStatusBar; +} + +wxStatusBar *wxFrameBase::OnCreateStatusBar(int number, + long style, + wxWindowID id, + const wxString& name) +{ + wxStatusBar *statusBar = new wxStatusBar(this, id, style, name); + + statusBar->SetFieldsCount(number); + + return statusBar; +} + +void wxFrameBase::SetStatusText(const wxString& text, int number) +{ + wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") ); + + m_frameStatusBar->SetStatusText(text, number); +} + +void wxFrameBase::SetStatusWidths(int n, const int widths_field[] ) +{ + wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set widths for") ); + + m_frameStatusBar->SetStatusWidths(n, widths_field); + + PositionStatusBar(); +} + +void wxFrameBase::PushStatusText(const wxString& text, int number) +{ + wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") ); + + m_frameStatusBar->PushStatusText(text, number); +} + +void wxFrameBase::PopStatusText(int number) +{ + wxCHECK_RET( m_frameStatusBar != NULL, wxT("no statusbar to set text for") ); + + m_frameStatusBar->PopStatusText(number); +} + +bool wxFrameBase::ShowMenuHelp(wxStatusBar *WXUNUSED(statbar), int menuId) +{ +#if wxUSE_MENUS + // if no help string found, we will clear the status bar text + wxString helpString; + bool show = menuId != wxID_SEPARATOR && menuId != -2 /* wxID_TITLE */; + + if ( show ) + { + wxMenuBar *menuBar = GetMenuBar(); + if ( menuBar ) + { + // it's ok if we don't find the item because it might belong + // to the popup menu + wxMenuItem *item = menuBar->FindItem(menuId); + if ( item ) + helpString = item->GetHelp(); + } + } + + DoGiveHelp(helpString, show); + + return !helpString.empty(); +#else // !wxUSE_MENUS + return false; +#endif // wxUSE_MENUS/!wxUSE_MENUS +} + +void wxFrameBase::SetStatusBar(wxStatusBar *statBar) +{ + bool hadBar = m_frameStatusBar != NULL; + m_frameStatusBar = statBar; + + if ( (m_frameStatusBar != NULL) != hadBar ) + { + PositionStatusBar(); + + DoLayout(); + } +} + +#endif // wxUSE_STATUSBAR + +#if wxUSE_MENUS || wxUSE_TOOLBAR +void wxFrameBase::DoGiveHelp(const wxString& text, bool show) +{ +#if wxUSE_STATUSBAR + if ( m_statusBarPane < 0 ) + { + // status bar messages disabled + return; + } + + wxStatusBar *statbar = GetStatusBar(); + if ( !statbar ) + return; + + wxString help; + if ( show ) + { + help = text; + + // remember the old status bar text if this is the first time we're + // called since the menu has been opened as we're going to overwrite it + // in our DoGiveHelp() and we want to restore it when the menu is + // closed + // + // note that it would be logical to do this in OnMenuOpen() but under + // MSW we get an EVT_MENU_HIGHLIGHT before EVT_MENU_OPEN, strangely + // enough, and so this doesn't work and instead we use the ugly trick + // with using special m_oldStatusText value as "menu opened" (but it is + // arguably better than adding yet another member variable to wxFrame + // on all platforms) + if ( m_oldStatusText.empty() ) + { + m_oldStatusText = statbar->GetStatusText(m_statusBarPane); + if ( m_oldStatusText.empty() ) + { + // use special value to prevent us from doing this the next time + m_oldStatusText += _T('\0'); + } + } + } + else // hide the status bar text + { + // i.e. restore the old one + help = m_oldStatusText; + + // make sure we get the up to date text when showing it the next time + m_oldStatusText.clear(); + } + + statbar->SetStatusText(help, m_statusBarPane); +#else + wxUnusedVar(text); + wxUnusedVar(show); +#endif // wxUSE_STATUSBAR +} +#endif // wxUSE_MENUS || wxUSE_TOOLBAR + + +// ---------------------------------------------------------------------------- +// toolbar stuff +// ---------------------------------------------------------------------------- + +#if wxUSE_TOOLBAR + +wxToolBar* wxFrameBase::CreateToolBar(long style, + wxWindowID id, + const wxString& name) +{ + // the main toolbar can't be recreated (unless it was explicitly deleted + // before) + wxCHECK_MSG( !m_frameToolBar, (wxToolBar *)NULL, + wxT("recreating toolbar in wxFrame") ); + + if ( style == -1 ) + { + // use default style + // + // NB: we don't specify the default value in the method declaration + // because + // a) this allows us to have different defaults for different + // platforms (even if we don't have them right now) + // b) we don't need to include wx/toolbar.h in the header then + style = wxBORDER_NONE | wxTB_HORIZONTAL | wxTB_FLAT; + } + + SetToolBar(OnCreateToolBar(style, id, name)); + + return m_frameToolBar; +} + +wxToolBar* wxFrameBase::OnCreateToolBar(long style, + wxWindowID id, + const wxString& name) +{ +#if defined(__WXWINCE__) && defined(__POCKETPC__) + return new wxToolMenuBar(this, id, + wxDefaultPosition, wxDefaultSize, + style, name); +#else + return new wxToolBar(this, id, + wxDefaultPosition, wxDefaultSize, + style, name); +#endif +} + +void wxFrameBase::SetToolBar(wxToolBar *toolbar) +{ + bool hadBar = m_frameToolBar != NULL; + m_frameToolBar = toolbar; + + if ( (m_frameToolBar != NULL) != hadBar ) + { + PositionToolBar(); + + DoLayout(); + } +} + +#endif // wxUSE_TOOLBAR + +// ---------------------------------------------------------------------------- +// menus +// ---------------------------------------------------------------------------- + +#if wxUSE_MENUS + +// update all menus +void wxFrameBase::DoMenuUpdates(wxMenu* menu) +{ + if (menu) + { + wxEvtHandler* source = GetEventHandler(); + menu->UpdateUI(source); + } + else + { + wxMenuBar* bar = GetMenuBar(); + if (bar != NULL) + bar->UpdateMenus(); + } +} + +void wxFrameBase::DetachMenuBar() +{ + if ( m_frameMenuBar ) + { + m_frameMenuBar->Detach(); + m_frameMenuBar = NULL; + } +} + +void wxFrameBase::AttachMenuBar(wxMenuBar *menubar) +{ + if ( menubar ) + { + menubar->Attach((wxFrame *)this); + m_frameMenuBar = menubar; + } +} + +void wxFrameBase::SetMenuBar(wxMenuBar *menubar) +{ + if ( menubar == GetMenuBar() ) + { + // nothing to do + return; + } + + DetachMenuBar(); + + this->AttachMenuBar(menubar); +} + +#endif // wxUSE_MENUS diff --git a/Source/3rd Party/wx/src/common/fs_arc.cpp b/Source/3rd Party/wx/src/common/fs_arc.cpp index dae1910a1..ee1220cfc 100644 --- a/Source/3rd Party/wx/src/common/fs_arc.cpp +++ b/Source/3rd Party/wx/src/common/fs_arc.cpp @@ -1,533 +1,533 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: fs_arc.cpp -// Purpose: wxArchive file system -// Author: Vaclav Slavik, Mike Wetherell -// Copyright: (c) 1999 Vaclav Slavik, (c) 2006 Mike Wetherell -// CVS-ID: $Id: fs_arc.cpp 51495 2008-02-01 16:44:56Z MW $ -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#if wxUSE_FS_ARCHIVE - -#include "wx/fs_arc.h" - -#ifndef WXPRECOMP - #include "wx/intl.h" - #include "wx/log.h" -#endif - -#if WXWIN_COMPATIBILITY_2_6 && wxUSE_ZIPSTREAM - #include "wx/zipstrm.h" -#else - #include "wx/archive.h" -#endif - -#include "wx/private/fileback.h" - -//--------------------------------------------------------------------------- -// wxArchiveFSCacheDataImpl -// -// Holds the catalog of an archive file, and if it is being read from a -// non-seekable stream, a copy of its backing file. -// -// This class is actually the reference counted implementation for the -// wxArchiveFSCacheData class below. It was done that way to allow sharing -// between instances of wxFileSystem, though that's a feature not used in this -// version. -//--------------------------------------------------------------------------- - -WX_DECLARE_STRING_HASH_MAP(wxArchiveEntry*, wxArchiveFSEntryHash); - -struct wxArchiveFSEntry -{ - wxArchiveEntry *entry; - wxArchiveFSEntry *next; -}; - -class wxArchiveFSCacheDataImpl -{ -public: - wxArchiveFSCacheDataImpl(const wxArchiveClassFactory& factory, - const wxBackingFile& backer); - wxArchiveFSCacheDataImpl(const wxArchiveClassFactory& factory, - wxInputStream *stream); - - ~wxArchiveFSCacheDataImpl(); - - void Release() { if (--m_refcount == 0) delete this; } - wxArchiveFSCacheDataImpl *AddRef() { m_refcount++; return this; } - - wxArchiveEntry *Get(const wxString& name); - wxInputStream *NewStream() const; - - wxArchiveFSEntry *GetNext(wxArchiveFSEntry *fse); - -private: - wxArchiveFSEntry *AddToCache(wxArchiveEntry *entry); - void CloseStreams(); - - int m_refcount; - - wxArchiveFSEntryHash m_hash; - wxArchiveFSEntry *m_begin; - wxArchiveFSEntry **m_endptr; - - wxBackingFile m_backer; - wxInputStream *m_stream; - wxArchiveInputStream *m_archive; -}; - -wxArchiveFSCacheDataImpl::wxArchiveFSCacheDataImpl( - const wxArchiveClassFactory& factory, - const wxBackingFile& backer) - : m_refcount(1), - m_begin(NULL), - m_endptr(&m_begin), - m_backer(backer), - m_stream(new wxBackedInputStream(backer)), - m_archive(factory.NewStream(*m_stream)) -{ -} - -wxArchiveFSCacheDataImpl::wxArchiveFSCacheDataImpl( - const wxArchiveClassFactory& factory, - wxInputStream *stream) - : m_refcount(1), - m_begin(NULL), - m_endptr(&m_begin), - m_stream(stream), - m_archive(factory.NewStream(*m_stream)) -{ -} - -wxArchiveFSCacheDataImpl::~wxArchiveFSCacheDataImpl() -{ - WX_CLEAR_HASH_MAP(wxArchiveFSEntryHash, m_hash); - - wxArchiveFSEntry *entry = m_begin; - - while (entry) - { - wxArchiveFSEntry *next = entry->next; - delete entry; - entry = next; - } - - CloseStreams(); -} - -wxArchiveFSEntry *wxArchiveFSCacheDataImpl::AddToCache(wxArchiveEntry *entry) -{ - m_hash[entry->GetName(wxPATH_UNIX)] = entry; - wxArchiveFSEntry *fse = new wxArchiveFSEntry; - *m_endptr = fse; - (*m_endptr)->entry = entry; - (*m_endptr)->next = NULL; - m_endptr = &(*m_endptr)->next; - return fse; -} - -void wxArchiveFSCacheDataImpl::CloseStreams() -{ - delete m_archive; - m_archive = NULL; - delete m_stream; - m_stream = NULL; -} - -wxArchiveEntry *wxArchiveFSCacheDataImpl::Get(const wxString& name) -{ - wxArchiveFSEntryHash::iterator it = m_hash.find(name); - - if (it != m_hash.end()) - return it->second; - - if (!m_archive) - return NULL; - - wxArchiveEntry *entry; - - while ((entry = m_archive->GetNextEntry()) != NULL) - { - AddToCache(entry); - - if (entry->GetName(wxPATH_UNIX) == name) - return entry; - } - - CloseStreams(); - - return NULL; -} - -wxInputStream* wxArchiveFSCacheDataImpl::NewStream() const -{ - if (m_backer) - return new wxBackedInputStream(m_backer); - else - return NULL; -} - -wxArchiveFSEntry *wxArchiveFSCacheDataImpl::GetNext(wxArchiveFSEntry *fse) -{ - wxArchiveFSEntry *next = fse ? fse->next : m_begin; - - if (!next && m_archive) - { - wxArchiveEntry *entry = m_archive->GetNextEntry(); - - if (entry) - next = AddToCache(entry); - else - CloseStreams(); - } - - return next; -} - -//--------------------------------------------------------------------------- -// wxArchiveFSCacheData -// -// This is the inteface for wxArchiveFSCacheDataImpl above. Holds the catalog -// of an archive file, and if it is being read from a non-seekable stream, a -// copy of its backing file. -//--------------------------------------------------------------------------- - -class wxArchiveFSCacheData -{ -public: - wxArchiveFSCacheData() : m_impl(NULL) { } - wxArchiveFSCacheData(const wxArchiveClassFactory& factory, - const wxBackingFile& backer); - wxArchiveFSCacheData(const wxArchiveClassFactory& factory, - wxInputStream *stream); - - wxArchiveFSCacheData(const wxArchiveFSCacheData& data); - wxArchiveFSCacheData& operator=(const wxArchiveFSCacheData& data); - - ~wxArchiveFSCacheData() { if (m_impl) m_impl->Release(); } - - wxArchiveEntry *Get(const wxString& name) { return m_impl->Get(name); } - wxInputStream *NewStream() const { return m_impl->NewStream(); } - wxArchiveFSEntry *GetNext(wxArchiveFSEntry *fse) - { return m_impl->GetNext(fse); } - -private: - wxArchiveFSCacheDataImpl *m_impl; -}; - -wxArchiveFSCacheData::wxArchiveFSCacheData( - const wxArchiveClassFactory& factory, - const wxBackingFile& backer) - : m_impl(new wxArchiveFSCacheDataImpl(factory, backer)) -{ -} - -wxArchiveFSCacheData::wxArchiveFSCacheData( - const wxArchiveClassFactory& factory, - wxInputStream *stream) - : m_impl(new wxArchiveFSCacheDataImpl(factory, stream)) -{ -} - -wxArchiveFSCacheData::wxArchiveFSCacheData(const wxArchiveFSCacheData& data) - : m_impl(data.m_impl ? data.m_impl->AddRef() : NULL) -{ -} - -wxArchiveFSCacheData& wxArchiveFSCacheData::operator=( - const wxArchiveFSCacheData& data) -{ - if (data.m_impl != m_impl) - { - if (m_impl) - m_impl->Release(); - - m_impl = data.m_impl; - - if (m_impl) - m_impl->AddRef(); - } - - return *this; -} - -//--------------------------------------------------------------------------- -// wxArchiveFSCache -// -// wxArchiveFSCacheData caches a single archive, and this class holds a -// collection of them to cache all the archives accessed by this instance -// of wxFileSystem. -//--------------------------------------------------------------------------- - -WX_DECLARE_STRING_HASH_MAP(wxArchiveFSCacheData, wxArchiveFSCacheDataHash); - -class wxArchiveFSCache -{ -public: - wxArchiveFSCache() { } - ~wxArchiveFSCache() { } - - wxArchiveFSCacheData* Add(const wxString& name, - const wxArchiveClassFactory& factory, - wxInputStream *stream); - - wxArchiveFSCacheData *Get(const wxString& name); - -private: - wxArchiveFSCacheDataHash m_hash; -}; - -wxArchiveFSCacheData* wxArchiveFSCache::Add( - const wxString& name, - const wxArchiveClassFactory& factory, - wxInputStream *stream) -{ - wxArchiveFSCacheData& data = m_hash[name]; - - if (stream->IsSeekable()) - data = wxArchiveFSCacheData(factory, stream); - else - data = wxArchiveFSCacheData(factory, wxBackingFile(stream)); - - return &data; -} - -wxArchiveFSCacheData *wxArchiveFSCache::Get(const wxString& name) -{ - wxArchiveFSCacheDataHash::iterator it; - - if ((it = m_hash.find(name)) != m_hash.end()) - return &it->second; - - return NULL; -} - -//---------------------------------------------------------------------------- -// wxArchiveFSHandler -//---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxArchiveFSHandler, wxFileSystemHandler) - -wxArchiveFSHandler::wxArchiveFSHandler() - : wxFileSystemHandler() -{ - m_Archive = NULL; - m_FindEntry = NULL; - m_ZipFile = m_Pattern = m_BaseDir = wxEmptyString; - m_AllowDirs = m_AllowFiles = true; - m_DirsFound = NULL; - m_cache = NULL; -} - -wxArchiveFSHandler::~wxArchiveFSHandler() -{ - Cleanup(); - delete m_cache; -} - -void wxArchiveFSHandler::Cleanup() -{ - wxDELETE(m_DirsFound); -} - -bool wxArchiveFSHandler::CanOpen(const wxString& location) -{ - wxString p = GetProtocol(location); - return wxArchiveClassFactory::Find(p) != NULL; -} - -wxFSFile* wxArchiveFSHandler::OpenFile( - wxFileSystem& WXUNUSED(fs), - const wxString& location) -{ - wxString right = GetRightLocation(location); - wxString left = GetLeftLocation(location); - wxString protocol = GetProtocol(location); - wxString key = left + wxT("#") + protocol + wxT(":"); - - if (right.Contains(wxT("./"))) - { - if (right.GetChar(0) != wxT('/')) right = wxT('/') + right; - wxFileName rightPart(right, wxPATH_UNIX); - rightPart.Normalize(wxPATH_NORM_DOTS, wxT("/"), wxPATH_UNIX); - right = rightPart.GetFullPath(wxPATH_UNIX); - } - - if (right.GetChar(0) == wxT('/')) right = right.Mid(1); - - if (!m_cache) - m_cache = new wxArchiveFSCache; - - const wxArchiveClassFactory *factory; - factory = wxArchiveClassFactory::Find(protocol); - if (!factory) - return NULL; - - wxArchiveFSCacheData *cached = m_cache->Get(key); - if (!cached) - { - wxFSFile *leftFile = m_fs.OpenFile(left); - if (!leftFile) - return NULL; - cached = m_cache->Add(key, *factory, leftFile->DetachStream()); - delete leftFile; - } - - wxArchiveEntry *entry = cached->Get(right); - if (!entry) - return NULL; - - wxInputStream *leftStream = cached->NewStream(); - if (!leftStream) - { - wxFSFile *leftFile = m_fs.OpenFile(left); - if (!leftFile) - return NULL; - leftStream = leftFile->DetachStream(); - delete leftFile; - } - - wxArchiveInputStream *s = factory->NewStream(leftStream); - s->OpenEntry(*entry); - - if (s && s->IsOk()) - { -#if WXWIN_COMPATIBILITY_2_6 && wxUSE_ZIPSTREAM - if (factory->IsKindOf(CLASSINFO(wxZipClassFactory))) - ((wxZipInputStream*)s)->m_allowSeeking = true; -#endif // WXWIN_COMPATIBILITY_2_6 - - return new wxFSFile(s, - key + right, - GetMimeTypeFromExt(location), - GetAnchor(location) -#if wxUSE_DATETIME - , entry->GetDateTime() -#endif // wxUSE_DATETIME - ); - } - - delete s; - return NULL; -} - -wxString wxArchiveFSHandler::FindFirst(const wxString& spec, int flags) -{ - wxString right = GetRightLocation(spec); - wxString left = GetLeftLocation(spec); - wxString protocol = GetProtocol(spec); - wxString key = left + wxT("#") + protocol + wxT(":"); - - if (!right.empty() && right.Last() == wxT('/')) right.RemoveLast(); - - if (!m_cache) - m_cache = new wxArchiveFSCache; - - const wxArchiveClassFactory *factory; - factory = wxArchiveClassFactory::Find(protocol); - if (!factory) - return wxEmptyString; - - m_Archive = m_cache->Get(key); - if (!m_Archive) - { - wxFSFile *leftFile = m_fs.OpenFile(left); - if (!leftFile) - return wxEmptyString; - m_Archive = m_cache->Add(key, *factory, leftFile->DetachStream()); - delete leftFile; - } - - m_FindEntry = NULL; - - switch (flags) - { - case wxFILE: - m_AllowDirs = false, m_AllowFiles = true; break; - case wxDIR: - m_AllowDirs = true, m_AllowFiles = false; break; - default: - m_AllowDirs = m_AllowFiles = true; break; - } - - m_ZipFile = key; - - m_Pattern = right.AfterLast(wxT('/')); - m_BaseDir = right.BeforeLast(wxT('/')); - if (m_BaseDir.StartsWith(wxT("/"))) - m_BaseDir = m_BaseDir.Mid(1); - - if (m_Archive) - { - if (m_AllowDirs) - { - delete m_DirsFound; - m_DirsFound = new wxArchiveFilenameHashMap(); - if (right.empty()) // allow "/" to match the archive root - return spec; - } - return DoFind(); - } - return wxEmptyString; -} - -wxString wxArchiveFSHandler::FindNext() -{ - if (!m_Archive) return wxEmptyString; - return DoFind(); -} - -wxString wxArchiveFSHandler::DoFind() -{ - wxString namestr, dir, filename; - wxString match = wxEmptyString; - - while (match == wxEmptyString) - { - m_FindEntry = m_Archive->GetNext(m_FindEntry); - - if (!m_FindEntry) - { - m_Archive = NULL; - m_FindEntry = NULL; - break; - } - namestr = m_FindEntry->entry->GetName(wxPATH_UNIX); - - if (m_AllowDirs) - { - dir = namestr.BeforeLast(wxT('/')); - while (!dir.empty()) - { - if( m_DirsFound->find(dir) == m_DirsFound->end() ) - { - (*m_DirsFound)[dir] = 1; - filename = dir.AfterLast(wxT('/')); - dir = dir.BeforeLast(wxT('/')); - if (!filename.empty() && m_BaseDir == dir && - wxMatchWild(m_Pattern, filename, false)) - match = m_ZipFile + dir + wxT("/") + filename; - } - else - break; // already tranversed - } - } - - filename = namestr.AfterLast(wxT('/')); - dir = namestr.BeforeLast(wxT('/')); - if (m_AllowFiles && !filename.empty() && m_BaseDir == dir && - wxMatchWild(m_Pattern, filename, false)) - match = m_ZipFile + namestr; - } - - return match; -} - -#endif // wxUSE_FS_ARCHIVE +///////////////////////////////////////////////////////////////////////////// +// Name: fs_arc.cpp +// Purpose: wxArchive file system +// Author: Vaclav Slavik, Mike Wetherell +// Copyright: (c) 1999 Vaclav Slavik, (c) 2006 Mike Wetherell +// CVS-ID: $Id: fs_arc.cpp 51495 2008-02-01 16:44:56Z MW $ +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#if wxUSE_FS_ARCHIVE + +#include "wx/fs_arc.h" + +#ifndef WXPRECOMP + #include "wx/intl.h" + #include "wx/log.h" +#endif + +#if WXWIN_COMPATIBILITY_2_6 && wxUSE_ZIPSTREAM + #include "wx/zipstrm.h" +#else + #include "wx/archive.h" +#endif + +#include "wx/private/fileback.h" + +//--------------------------------------------------------------------------- +// wxArchiveFSCacheDataImpl +// +// Holds the catalog of an archive file, and if it is being read from a +// non-seekable stream, a copy of its backing file. +// +// This class is actually the reference counted implementation for the +// wxArchiveFSCacheData class below. It was done that way to allow sharing +// between instances of wxFileSystem, though that's a feature not used in this +// version. +//--------------------------------------------------------------------------- + +WX_DECLARE_STRING_HASH_MAP(wxArchiveEntry*, wxArchiveFSEntryHash); + +struct wxArchiveFSEntry +{ + wxArchiveEntry *entry; + wxArchiveFSEntry *next; +}; + +class wxArchiveFSCacheDataImpl +{ +public: + wxArchiveFSCacheDataImpl(const wxArchiveClassFactory& factory, + const wxBackingFile& backer); + wxArchiveFSCacheDataImpl(const wxArchiveClassFactory& factory, + wxInputStream *stream); + + ~wxArchiveFSCacheDataImpl(); + + void Release() { if (--m_refcount == 0) delete this; } + wxArchiveFSCacheDataImpl *AddRef() { m_refcount++; return this; } + + wxArchiveEntry *Get(const wxString& name); + wxInputStream *NewStream() const; + + wxArchiveFSEntry *GetNext(wxArchiveFSEntry *fse); + +private: + wxArchiveFSEntry *AddToCache(wxArchiveEntry *entry); + void CloseStreams(); + + int m_refcount; + + wxArchiveFSEntryHash m_hash; + wxArchiveFSEntry *m_begin; + wxArchiveFSEntry **m_endptr; + + wxBackingFile m_backer; + wxInputStream *m_stream; + wxArchiveInputStream *m_archive; +}; + +wxArchiveFSCacheDataImpl::wxArchiveFSCacheDataImpl( + const wxArchiveClassFactory& factory, + const wxBackingFile& backer) + : m_refcount(1), + m_begin(NULL), + m_endptr(&m_begin), + m_backer(backer), + m_stream(new wxBackedInputStream(backer)), + m_archive(factory.NewStream(*m_stream)) +{ +} + +wxArchiveFSCacheDataImpl::wxArchiveFSCacheDataImpl( + const wxArchiveClassFactory& factory, + wxInputStream *stream) + : m_refcount(1), + m_begin(NULL), + m_endptr(&m_begin), + m_stream(stream), + m_archive(factory.NewStream(*m_stream)) +{ +} + +wxArchiveFSCacheDataImpl::~wxArchiveFSCacheDataImpl() +{ + WX_CLEAR_HASH_MAP(wxArchiveFSEntryHash, m_hash); + + wxArchiveFSEntry *entry = m_begin; + + while (entry) + { + wxArchiveFSEntry *next = entry->next; + delete entry; + entry = next; + } + + CloseStreams(); +} + +wxArchiveFSEntry *wxArchiveFSCacheDataImpl::AddToCache(wxArchiveEntry *entry) +{ + m_hash[entry->GetName(wxPATH_UNIX)] = entry; + wxArchiveFSEntry *fse = new wxArchiveFSEntry; + *m_endptr = fse; + (*m_endptr)->entry = entry; + (*m_endptr)->next = NULL; + m_endptr = &(*m_endptr)->next; + return fse; +} + +void wxArchiveFSCacheDataImpl::CloseStreams() +{ + delete m_archive; + m_archive = NULL; + delete m_stream; + m_stream = NULL; +} + +wxArchiveEntry *wxArchiveFSCacheDataImpl::Get(const wxString& name) +{ + wxArchiveFSEntryHash::iterator it = m_hash.find(name); + + if (it != m_hash.end()) + return it->second; + + if (!m_archive) + return NULL; + + wxArchiveEntry *entry; + + while ((entry = m_archive->GetNextEntry()) != NULL) + { + AddToCache(entry); + + if (entry->GetName(wxPATH_UNIX) == name) + return entry; + } + + CloseStreams(); + + return NULL; +} + +wxInputStream* wxArchiveFSCacheDataImpl::NewStream() const +{ + if (m_backer) + return new wxBackedInputStream(m_backer); + else + return NULL; +} + +wxArchiveFSEntry *wxArchiveFSCacheDataImpl::GetNext(wxArchiveFSEntry *fse) +{ + wxArchiveFSEntry *next = fse ? fse->next : m_begin; + + if (!next && m_archive) + { + wxArchiveEntry *entry = m_archive->GetNextEntry(); + + if (entry) + next = AddToCache(entry); + else + CloseStreams(); + } + + return next; +} + +//--------------------------------------------------------------------------- +// wxArchiveFSCacheData +// +// This is the inteface for wxArchiveFSCacheDataImpl above. Holds the catalog +// of an archive file, and if it is being read from a non-seekable stream, a +// copy of its backing file. +//--------------------------------------------------------------------------- + +class wxArchiveFSCacheData +{ +public: + wxArchiveFSCacheData() : m_impl(NULL) { } + wxArchiveFSCacheData(const wxArchiveClassFactory& factory, + const wxBackingFile& backer); + wxArchiveFSCacheData(const wxArchiveClassFactory& factory, + wxInputStream *stream); + + wxArchiveFSCacheData(const wxArchiveFSCacheData& data); + wxArchiveFSCacheData& operator=(const wxArchiveFSCacheData& data); + + ~wxArchiveFSCacheData() { if (m_impl) m_impl->Release(); } + + wxArchiveEntry *Get(const wxString& name) { return m_impl->Get(name); } + wxInputStream *NewStream() const { return m_impl->NewStream(); } + wxArchiveFSEntry *GetNext(wxArchiveFSEntry *fse) + { return m_impl->GetNext(fse); } + +private: + wxArchiveFSCacheDataImpl *m_impl; +}; + +wxArchiveFSCacheData::wxArchiveFSCacheData( + const wxArchiveClassFactory& factory, + const wxBackingFile& backer) + : m_impl(new wxArchiveFSCacheDataImpl(factory, backer)) +{ +} + +wxArchiveFSCacheData::wxArchiveFSCacheData( + const wxArchiveClassFactory& factory, + wxInputStream *stream) + : m_impl(new wxArchiveFSCacheDataImpl(factory, stream)) +{ +} + +wxArchiveFSCacheData::wxArchiveFSCacheData(const wxArchiveFSCacheData& data) + : m_impl(data.m_impl ? data.m_impl->AddRef() : NULL) +{ +} + +wxArchiveFSCacheData& wxArchiveFSCacheData::operator=( + const wxArchiveFSCacheData& data) +{ + if (data.m_impl != m_impl) + { + if (m_impl) + m_impl->Release(); + + m_impl = data.m_impl; + + if (m_impl) + m_impl->AddRef(); + } + + return *this; +} + +//--------------------------------------------------------------------------- +// wxArchiveFSCache +// +// wxArchiveFSCacheData caches a single archive, and this class holds a +// collection of them to cache all the archives accessed by this instance +// of wxFileSystem. +//--------------------------------------------------------------------------- + +WX_DECLARE_STRING_HASH_MAP(wxArchiveFSCacheData, wxArchiveFSCacheDataHash); + +class wxArchiveFSCache +{ +public: + wxArchiveFSCache() { } + ~wxArchiveFSCache() { } + + wxArchiveFSCacheData* Add(const wxString& name, + const wxArchiveClassFactory& factory, + wxInputStream *stream); + + wxArchiveFSCacheData *Get(const wxString& name); + +private: + wxArchiveFSCacheDataHash m_hash; +}; + +wxArchiveFSCacheData* wxArchiveFSCache::Add( + const wxString& name, + const wxArchiveClassFactory& factory, + wxInputStream *stream) +{ + wxArchiveFSCacheData& data = m_hash[name]; + + if (stream->IsSeekable()) + data = wxArchiveFSCacheData(factory, stream); + else + data = wxArchiveFSCacheData(factory, wxBackingFile(stream)); + + return &data; +} + +wxArchiveFSCacheData *wxArchiveFSCache::Get(const wxString& name) +{ + wxArchiveFSCacheDataHash::iterator it; + + if ((it = m_hash.find(name)) != m_hash.end()) + return &it->second; + + return NULL; +} + +//---------------------------------------------------------------------------- +// wxArchiveFSHandler +//---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxArchiveFSHandler, wxFileSystemHandler) + +wxArchiveFSHandler::wxArchiveFSHandler() + : wxFileSystemHandler() +{ + m_Archive = NULL; + m_FindEntry = NULL; + m_ZipFile = m_Pattern = m_BaseDir = wxEmptyString; + m_AllowDirs = m_AllowFiles = true; + m_DirsFound = NULL; + m_cache = NULL; +} + +wxArchiveFSHandler::~wxArchiveFSHandler() +{ + Cleanup(); + delete m_cache; +} + +void wxArchiveFSHandler::Cleanup() +{ + wxDELETE(m_DirsFound); +} + +bool wxArchiveFSHandler::CanOpen(const wxString& location) +{ + wxString p = GetProtocol(location); + return wxArchiveClassFactory::Find(p) != NULL; +} + +wxFSFile* wxArchiveFSHandler::OpenFile( + wxFileSystem& WXUNUSED(fs), + const wxString& location) +{ + wxString right = GetRightLocation(location); + wxString left = GetLeftLocation(location); + wxString protocol = GetProtocol(location); + wxString key = left + wxT("#") + protocol + wxT(":"); + + if (right.Contains(wxT("./"))) + { + if (right.GetChar(0) != wxT('/')) right = wxT('/') + right; + wxFileName rightPart(right, wxPATH_UNIX); + rightPart.Normalize(wxPATH_NORM_DOTS, wxT("/"), wxPATH_UNIX); + right = rightPart.GetFullPath(wxPATH_UNIX); + } + + if (right.GetChar(0) == wxT('/')) right = right.Mid(1); + + if (!m_cache) + m_cache = new wxArchiveFSCache; + + const wxArchiveClassFactory *factory; + factory = wxArchiveClassFactory::Find(protocol); + if (!factory) + return NULL; + + wxArchiveFSCacheData *cached = m_cache->Get(key); + if (!cached) + { + wxFSFile *leftFile = m_fs.OpenFile(left); + if (!leftFile) + return NULL; + cached = m_cache->Add(key, *factory, leftFile->DetachStream()); + delete leftFile; + } + + wxArchiveEntry *entry = cached->Get(right); + if (!entry) + return NULL; + + wxInputStream *leftStream = cached->NewStream(); + if (!leftStream) + { + wxFSFile *leftFile = m_fs.OpenFile(left); + if (!leftFile) + return NULL; + leftStream = leftFile->DetachStream(); + delete leftFile; + } + + wxArchiveInputStream *s = factory->NewStream(leftStream); + s->OpenEntry(*entry); + + if (s && s->IsOk()) + { +#if WXWIN_COMPATIBILITY_2_6 && wxUSE_ZIPSTREAM + if (factory->IsKindOf(CLASSINFO(wxZipClassFactory))) + ((wxZipInputStream*)s)->m_allowSeeking = true; +#endif // WXWIN_COMPATIBILITY_2_6 + + return new wxFSFile(s, + key + right, + GetMimeTypeFromExt(location), + GetAnchor(location) +#if wxUSE_DATETIME + , entry->GetDateTime() +#endif // wxUSE_DATETIME + ); + } + + delete s; + return NULL; +} + +wxString wxArchiveFSHandler::FindFirst(const wxString& spec, int flags) +{ + wxString right = GetRightLocation(spec); + wxString left = GetLeftLocation(spec); + wxString protocol = GetProtocol(spec); + wxString key = left + wxT("#") + protocol + wxT(":"); + + if (!right.empty() && right.Last() == wxT('/')) right.RemoveLast(); + + if (!m_cache) + m_cache = new wxArchiveFSCache; + + const wxArchiveClassFactory *factory; + factory = wxArchiveClassFactory::Find(protocol); + if (!factory) + return wxEmptyString; + + m_Archive = m_cache->Get(key); + if (!m_Archive) + { + wxFSFile *leftFile = m_fs.OpenFile(left); + if (!leftFile) + return wxEmptyString; + m_Archive = m_cache->Add(key, *factory, leftFile->DetachStream()); + delete leftFile; + } + + m_FindEntry = NULL; + + switch (flags) + { + case wxFILE: + m_AllowDirs = false, m_AllowFiles = true; break; + case wxDIR: + m_AllowDirs = true, m_AllowFiles = false; break; + default: + m_AllowDirs = m_AllowFiles = true; break; + } + + m_ZipFile = key; + + m_Pattern = right.AfterLast(wxT('/')); + m_BaseDir = right.BeforeLast(wxT('/')); + if (m_BaseDir.StartsWith(wxT("/"))) + m_BaseDir = m_BaseDir.Mid(1); + + if (m_Archive) + { + if (m_AllowDirs) + { + delete m_DirsFound; + m_DirsFound = new wxArchiveFilenameHashMap(); + if (right.empty()) // allow "/" to match the archive root + return spec; + } + return DoFind(); + } + return wxEmptyString; +} + +wxString wxArchiveFSHandler::FindNext() +{ + if (!m_Archive) return wxEmptyString; + return DoFind(); +} + +wxString wxArchiveFSHandler::DoFind() +{ + wxString namestr, dir, filename; + wxString match = wxEmptyString; + + while (match == wxEmptyString) + { + m_FindEntry = m_Archive->GetNext(m_FindEntry); + + if (!m_FindEntry) + { + m_Archive = NULL; + m_FindEntry = NULL; + break; + } + namestr = m_FindEntry->entry->GetName(wxPATH_UNIX); + + if (m_AllowDirs) + { + dir = namestr.BeforeLast(wxT('/')); + while (!dir.empty()) + { + if( m_DirsFound->find(dir) == m_DirsFound->end() ) + { + (*m_DirsFound)[dir] = 1; + filename = dir.AfterLast(wxT('/')); + dir = dir.BeforeLast(wxT('/')); + if (!filename.empty() && m_BaseDir == dir && + wxMatchWild(m_Pattern, filename, false)) + match = m_ZipFile + dir + wxT("/") + filename; + } + else + break; // already tranversed + } + } + + filename = namestr.AfterLast(wxT('/')); + dir = namestr.BeforeLast(wxT('/')); + if (m_AllowFiles && !filename.empty() && m_BaseDir == dir && + wxMatchWild(m_Pattern, filename, false)) + match = m_ZipFile + namestr; + } + + return match; +} + +#endif // wxUSE_FS_ARCHIVE diff --git a/Source/3rd Party/wx/src/common/fs_filter.cpp b/Source/3rd Party/wx/src/common/fs_filter.cpp index adaf0cba1..d0fae32ba 100644 --- a/Source/3rd Party/wx/src/common/fs_filter.cpp +++ b/Source/3rd Party/wx/src/common/fs_filter.cpp @@ -1,92 +1,92 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fs_filter.cpp -// Purpose: wxFilter file system handler -// Author: Mike Wetherell -// Copyright: (c) 2006 Mike Wetherell -// CVS-ID: $Id: fs_filter.cpp 42514 2006-10-27 10:47:13Z MW $ -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FILESYSTEM - -#include "wx/fs_filter.h" - -#ifndef WXPRECOMP -#endif - -#include "wx/ptr_scpd.h" - -wxDEFINE_SCOPED_PTR_TYPE(wxFSFile) -wxDEFINE_SCOPED_PTR_TYPE(wxInputStream) - -//---------------------------------------------------------------------------- -// wxFilterFSHandler -//---------------------------------------------------------------------------- - -bool wxFilterFSHandler::CanOpen(const wxString& location) -{ - return wxFilterClassFactory::Find(GetProtocol(location)) != NULL; -} - -wxFSFile* wxFilterFSHandler::OpenFile( - wxFileSystem& fs, - const wxString& location) -{ - wxString right = GetRightLocation(location); - if (!right.empty()) - return NULL; - - wxString protocol = GetProtocol(location); - const wxFilterClassFactory *factory = wxFilterClassFactory::Find(protocol); - if (!factory) - return NULL; - - wxString left = GetLeftLocation(location); - wxFSFilePtr leftFile(fs.OpenFile(left)); - if (!leftFile.get()) - return NULL; - - wxInputStreamPtr leftStream(leftFile->DetachStream()); - if (!leftStream.get() || !leftStream->IsOk()) - return NULL; - - wxInputStreamPtr stream(factory->NewStream(leftStream.release())); - - // The way compressed streams are supposed to be served is e.g.: - // Content-type: application/postscript - // Content-encoding: gzip - // So the mime type should be just the mime type of the lhs. However check - // whether the mime type is that of this compression format (e.g. - // application/gzip). If so pop any extension and try GetMimeTypeFromExt, - // e.g. if it were '.ps.gz' pop the '.gz' and try looking up '.ps' - wxString mime = leftFile->GetMimeType(); - if (factory->CanHandle(mime, wxSTREAM_MIMETYPE)) - mime = GetMimeTypeFromExt(factory->PopExtension(left)); - - return new wxFSFile(stream.release(), - left + wxT("#") + protocol + wxT(":") + right, - mime, - GetAnchor(location) -#if wxUSE_DATETIME - , leftFile->GetModificationTime() -#endif // wxUSE_DATETIME - ); -} - -wxString wxFilterFSHandler::FindFirst(const wxString& WXUNUSED(spec), int WXUNUSED(flags)) -{ - return wxEmptyString; -} - -wxString wxFilterFSHandler::FindNext() -{ - return wxEmptyString; -} - -#endif //wxUSE_FILESYSTEM +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fs_filter.cpp +// Purpose: wxFilter file system handler +// Author: Mike Wetherell +// Copyright: (c) 2006 Mike Wetherell +// CVS-ID: $Id: fs_filter.cpp 42514 2006-10-27 10:47:13Z MW $ +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FILESYSTEM + +#include "wx/fs_filter.h" + +#ifndef WXPRECOMP +#endif + +#include "wx/ptr_scpd.h" + +wxDEFINE_SCOPED_PTR_TYPE(wxFSFile) +wxDEFINE_SCOPED_PTR_TYPE(wxInputStream) + +//---------------------------------------------------------------------------- +// wxFilterFSHandler +//---------------------------------------------------------------------------- + +bool wxFilterFSHandler::CanOpen(const wxString& location) +{ + return wxFilterClassFactory::Find(GetProtocol(location)) != NULL; +} + +wxFSFile* wxFilterFSHandler::OpenFile( + wxFileSystem& fs, + const wxString& location) +{ + wxString right = GetRightLocation(location); + if (!right.empty()) + return NULL; + + wxString protocol = GetProtocol(location); + const wxFilterClassFactory *factory = wxFilterClassFactory::Find(protocol); + if (!factory) + return NULL; + + wxString left = GetLeftLocation(location); + wxFSFilePtr leftFile(fs.OpenFile(left)); + if (!leftFile.get()) + return NULL; + + wxInputStreamPtr leftStream(leftFile->DetachStream()); + if (!leftStream.get() || !leftStream->IsOk()) + return NULL; + + wxInputStreamPtr stream(factory->NewStream(leftStream.release())); + + // The way compressed streams are supposed to be served is e.g.: + // Content-type: application/postscript + // Content-encoding: gzip + // So the mime type should be just the mime type of the lhs. However check + // whether the mime type is that of this compression format (e.g. + // application/gzip). If so pop any extension and try GetMimeTypeFromExt, + // e.g. if it were '.ps.gz' pop the '.gz' and try looking up '.ps' + wxString mime = leftFile->GetMimeType(); + if (factory->CanHandle(mime, wxSTREAM_MIMETYPE)) + mime = GetMimeTypeFromExt(factory->PopExtension(left)); + + return new wxFSFile(stream.release(), + left + wxT("#") + protocol + wxT(":") + right, + mime, + GetAnchor(location) +#if wxUSE_DATETIME + , leftFile->GetModificationTime() +#endif // wxUSE_DATETIME + ); +} + +wxString wxFilterFSHandler::FindFirst(const wxString& WXUNUSED(spec), int WXUNUSED(flags)) +{ + return wxEmptyString; +} + +wxString wxFilterFSHandler::FindNext() +{ + return wxEmptyString; +} + +#endif //wxUSE_FILESYSTEM diff --git a/Source/3rd Party/wx/src/common/fs_mem.cpp b/Source/3rd Party/wx/src/common/fs_mem.cpp index 9967b881b..3bf24969e 100644 --- a/Source/3rd Party/wx/src/common/fs_mem.cpp +++ b/Source/3rd Party/wx/src/common/fs_mem.cpp @@ -1,288 +1,288 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fs_mem.cpp -// Purpose: in-memory file system -// Author: Vaclav Slavik -// RCS-ID: $Id: fs_mem.cpp 46522 2007-06-18 18:37:40Z VS $ -// Copyright: (c) 2000 Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_FILESYSTEM && wxUSE_STREAMS - -#include "wx/fs_mem.h" - -#ifndef WXPRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/hash.h" - #if wxUSE_GUI - #include "wx/bitmap.h" - #include "wx/image.h" - #endif // wxUSE_GUI -#endif - -#include "wx/mstream.h" - -class MemFSHashObj : public wxObject -{ - public: - - MemFSHashObj(const void *data, size_t len, const wxString& mime) - { - m_Data = new char[len]; - memcpy(m_Data, data, len); - m_Len = len; - m_MimeType = mime; - InitTime(); - } - - MemFSHashObj(const wxMemoryOutputStream& stream, const wxString& mime) - { - m_Len = stream.GetSize(); - m_Data = new char[m_Len]; - stream.CopyTo(m_Data, m_Len); - m_MimeType = mime; - InitTime(); - } - - virtual ~MemFSHashObj() - { - delete[] m_Data; - } - - char *m_Data; - size_t m_Len; - wxString m_MimeType; -#if wxUSE_DATETIME - wxDateTime m_Time; -#endif // wxUSE_DATETIME - - DECLARE_NO_COPY_CLASS(MemFSHashObj) - - private: - void InitTime() - { -#if wxUSE_DATETIME - m_Time = wxDateTime::Now(); -#endif // wxUSE_DATETIME - } -}; - -#if wxUSE_BASE - - -//-------------------------------------------------------------------------------- -// wxMemoryFSHandler -//-------------------------------------------------------------------------------- - - -wxHashTable *wxMemoryFSHandlerBase::m_Hash = NULL; - - -wxMemoryFSHandlerBase::wxMemoryFSHandlerBase() : wxFileSystemHandler() -{ -} - - - -wxMemoryFSHandlerBase::~wxMemoryFSHandlerBase() -{ - // as only one copy of FS handler is supposed to exist, we may silently - // delete static data here. (There is no way how to remove FS handler from - // wxFileSystem other than releasing _all_ handlers.) - - if (m_Hash) - { - WX_CLEAR_HASH_TABLE(*m_Hash); - delete m_Hash; - m_Hash = NULL; - } -} - - - -bool wxMemoryFSHandlerBase::CanOpen(const wxString& location) -{ - wxString p = GetProtocol(location); - return (p == wxT("memory")); -} - - - - -wxFSFile* wxMemoryFSHandlerBase::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location) -{ - if (m_Hash) - { - MemFSHashObj *obj = (MemFSHashObj*) m_Hash -> Get(GetRightLocation(location)); - if (obj == NULL) - { - return NULL; - } - else - { - wxString mime = obj->m_MimeType; - if ( mime.empty() ) - mime = GetMimeTypeFromExt(location); - return new wxFSFile - ( - new wxMemoryInputStream(obj -> m_Data, obj -> m_Len), - location, - mime, - GetAnchor(location) -#if wxUSE_DATETIME - , obj -> m_Time -#endif // wxUSE_DATETIME - ); - } - } - else return NULL; -} - - - -wxString wxMemoryFSHandlerBase::FindFirst(const wxString& WXUNUSED(spec), - int WXUNUSED(flags)) -{ - wxFAIL_MSG(wxT("wxMemoryFSHandlerBase::FindFirst not implemented")); - - return wxEmptyString; -} - - - -wxString wxMemoryFSHandlerBase::FindNext() -{ - wxFAIL_MSG(wxT("wxMemoryFSHandlerBase::FindNext not implemented")); - - return wxEmptyString; -} - - -bool wxMemoryFSHandlerBase::CheckHash(const wxString& filename) -{ - if (m_Hash == NULL) - { - m_Hash = new wxHashTable(wxKEY_STRING); - } - - if (m_Hash -> Get(filename) != NULL) - { - wxString s; - s.Printf(_("Memory VFS already contains file '%s'!"), filename.c_str()); - wxLogError(s); - return false; - } - else - return true; -} - - -/*static*/ -void wxMemoryFSHandlerBase::AddFileWithMimeType(const wxString& filename, - const wxString& textdata, - const wxString& mimetype) -{ - AddFileWithMimeType(filename, - (const void*) textdata.mb_str(), textdata.length(), - mimetype); -} - - -/*static*/ -void wxMemoryFSHandlerBase::AddFileWithMimeType(const wxString& filename, - const void *binarydata, size_t size, - const wxString& mimetype) -{ - if (!CheckHash(filename)) return; - m_Hash -> Put(filename, new MemFSHashObj(binarydata, size, mimetype)); -} - -/*static*/ -void wxMemoryFSHandlerBase::AddFile(const wxString& filename, - const wxString& textdata) -{ - AddFileWithMimeType(filename, textdata, wxEmptyString); -} - - -/*static*/ -void wxMemoryFSHandlerBase::AddFile(const wxString& filename, - const void *binarydata, size_t size) -{ - AddFileWithMimeType(filename, binarydata, size, wxEmptyString); -} - - - -/*static*/ void wxMemoryFSHandlerBase::RemoveFile(const wxString& filename) -{ - if (m_Hash == NULL || - m_Hash -> Get(filename) == NULL) - { - wxString s; - s.Printf(_("Trying to remove file '%s' from memory VFS, but it is not loaded!"), filename.c_str()); - wxLogError(s); - } - - else - delete m_Hash -> Delete(filename); -} - -#endif // wxUSE_BASE - -#if wxUSE_GUI - -#if wxUSE_IMAGE -/*static*/ void -wxMemoryFSHandler::AddFile(const wxString& filename, - const wxImage& image, - long type) -{ - if (!CheckHash(filename)) return; - - wxMemoryOutputStream mems; - if (image.Ok() && image.SaveFile(mems, (int)type)) - { - m_Hash->Put - ( - filename, - new MemFSHashObj - ( - mems, - wxImage::FindHandler(type)->GetMimeType() - ) - ); - } - else - { - wxString s; - s.Printf(_("Failed to store image '%s' to memory VFS!"), filename.c_str()); - wxPrintf(wxT("'%s'\n"), s.c_str()); - wxLogError(s); - } -} - -/*static*/ void -wxMemoryFSHandler::AddFile(const wxString& filename, - const wxBitmap& bitmap, - long type) -{ -#if !defined(__WXMSW__) || wxUSE_WXDIB - wxImage img = bitmap.ConvertToImage(); - AddFile(filename, img, type); -#endif -} - -#endif // wxUSE_IMAGE - -#endif // wxUSE_GUI - - -#endif // wxUSE_FILESYSTEM && wxUSE_FS_ZIP +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fs_mem.cpp +// Purpose: in-memory file system +// Author: Vaclav Slavik +// RCS-ID: $Id: fs_mem.cpp 46522 2007-06-18 18:37:40Z VS $ +// Copyright: (c) 2000 Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_FILESYSTEM && wxUSE_STREAMS + +#include "wx/fs_mem.h" + +#ifndef WXPRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/hash.h" + #if wxUSE_GUI + #include "wx/bitmap.h" + #include "wx/image.h" + #endif // wxUSE_GUI +#endif + +#include "wx/mstream.h" + +class MemFSHashObj : public wxObject +{ + public: + + MemFSHashObj(const void *data, size_t len, const wxString& mime) + { + m_Data = new char[len]; + memcpy(m_Data, data, len); + m_Len = len; + m_MimeType = mime; + InitTime(); + } + + MemFSHashObj(const wxMemoryOutputStream& stream, const wxString& mime) + { + m_Len = stream.GetSize(); + m_Data = new char[m_Len]; + stream.CopyTo(m_Data, m_Len); + m_MimeType = mime; + InitTime(); + } + + virtual ~MemFSHashObj() + { + delete[] m_Data; + } + + char *m_Data; + size_t m_Len; + wxString m_MimeType; +#if wxUSE_DATETIME + wxDateTime m_Time; +#endif // wxUSE_DATETIME + + DECLARE_NO_COPY_CLASS(MemFSHashObj) + + private: + void InitTime() + { +#if wxUSE_DATETIME + m_Time = wxDateTime::Now(); +#endif // wxUSE_DATETIME + } +}; + +#if wxUSE_BASE + + +//-------------------------------------------------------------------------------- +// wxMemoryFSHandler +//-------------------------------------------------------------------------------- + + +wxHashTable *wxMemoryFSHandlerBase::m_Hash = NULL; + + +wxMemoryFSHandlerBase::wxMemoryFSHandlerBase() : wxFileSystemHandler() +{ +} + + + +wxMemoryFSHandlerBase::~wxMemoryFSHandlerBase() +{ + // as only one copy of FS handler is supposed to exist, we may silently + // delete static data here. (There is no way how to remove FS handler from + // wxFileSystem other than releasing _all_ handlers.) + + if (m_Hash) + { + WX_CLEAR_HASH_TABLE(*m_Hash); + delete m_Hash; + m_Hash = NULL; + } +} + + + +bool wxMemoryFSHandlerBase::CanOpen(const wxString& location) +{ + wxString p = GetProtocol(location); + return (p == wxT("memory")); +} + + + + +wxFSFile* wxMemoryFSHandlerBase::OpenFile(wxFileSystem& WXUNUSED(fs), const wxString& location) +{ + if (m_Hash) + { + MemFSHashObj *obj = (MemFSHashObj*) m_Hash -> Get(GetRightLocation(location)); + if (obj == NULL) + { + return NULL; + } + else + { + wxString mime = obj->m_MimeType; + if ( mime.empty() ) + mime = GetMimeTypeFromExt(location); + return new wxFSFile + ( + new wxMemoryInputStream(obj -> m_Data, obj -> m_Len), + location, + mime, + GetAnchor(location) +#if wxUSE_DATETIME + , obj -> m_Time +#endif // wxUSE_DATETIME + ); + } + } + else return NULL; +} + + + +wxString wxMemoryFSHandlerBase::FindFirst(const wxString& WXUNUSED(spec), + int WXUNUSED(flags)) +{ + wxFAIL_MSG(wxT("wxMemoryFSHandlerBase::FindFirst not implemented")); + + return wxEmptyString; +} + + + +wxString wxMemoryFSHandlerBase::FindNext() +{ + wxFAIL_MSG(wxT("wxMemoryFSHandlerBase::FindNext not implemented")); + + return wxEmptyString; +} + + +bool wxMemoryFSHandlerBase::CheckHash(const wxString& filename) +{ + if (m_Hash == NULL) + { + m_Hash = new wxHashTable(wxKEY_STRING); + } + + if (m_Hash -> Get(filename) != NULL) + { + wxString s; + s.Printf(_("Memory VFS already contains file '%s'!"), filename.c_str()); + wxLogError(s); + return false; + } + else + return true; +} + + +/*static*/ +void wxMemoryFSHandlerBase::AddFileWithMimeType(const wxString& filename, + const wxString& textdata, + const wxString& mimetype) +{ + AddFileWithMimeType(filename, + (const void*) textdata.mb_str(), textdata.length(), + mimetype); +} + + +/*static*/ +void wxMemoryFSHandlerBase::AddFileWithMimeType(const wxString& filename, + const void *binarydata, size_t size, + const wxString& mimetype) +{ + if (!CheckHash(filename)) return; + m_Hash -> Put(filename, new MemFSHashObj(binarydata, size, mimetype)); +} + +/*static*/ +void wxMemoryFSHandlerBase::AddFile(const wxString& filename, + const wxString& textdata) +{ + AddFileWithMimeType(filename, textdata, wxEmptyString); +} + + +/*static*/ +void wxMemoryFSHandlerBase::AddFile(const wxString& filename, + const void *binarydata, size_t size) +{ + AddFileWithMimeType(filename, binarydata, size, wxEmptyString); +} + + + +/*static*/ void wxMemoryFSHandlerBase::RemoveFile(const wxString& filename) +{ + if (m_Hash == NULL || + m_Hash -> Get(filename) == NULL) + { + wxString s; + s.Printf(_("Trying to remove file '%s' from memory VFS, but it is not loaded!"), filename.c_str()); + wxLogError(s); + } + + else + delete m_Hash -> Delete(filename); +} + +#endif // wxUSE_BASE + +#if wxUSE_GUI + +#if wxUSE_IMAGE +/*static*/ void +wxMemoryFSHandler::AddFile(const wxString& filename, + const wxImage& image, + long type) +{ + if (!CheckHash(filename)) return; + + wxMemoryOutputStream mems; + if (image.Ok() && image.SaveFile(mems, (int)type)) + { + m_Hash->Put + ( + filename, + new MemFSHashObj + ( + mems, + wxImage::FindHandler(type)->GetMimeType() + ) + ); + } + else + { + wxString s; + s.Printf(_("Failed to store image '%s' to memory VFS!"), filename.c_str()); + wxPrintf(wxT("'%s'\n"), s.c_str()); + wxLogError(s); + } +} + +/*static*/ void +wxMemoryFSHandler::AddFile(const wxString& filename, + const wxBitmap& bitmap, + long type) +{ +#if !defined(__WXMSW__) || wxUSE_WXDIB + wxImage img = bitmap.ConvertToImage(); + AddFile(filename, img, type); +#endif +} + +#endif // wxUSE_IMAGE + +#endif // wxUSE_GUI + + +#endif // wxUSE_FILESYSTEM && wxUSE_FS_ZIP diff --git a/Source/3rd Party/wx/src/common/gaugecmn.cpp b/Source/3rd Party/wx/src/common/gaugecmn.cpp index f672bb6a3..d8ab642e6 100644 --- a/Source/3rd Party/wx/src/common/gaugecmn.cpp +++ b/Source/3rd Party/wx/src/common/gaugecmn.cpp @@ -1,156 +1,156 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/gaugecmn.cpp -// Purpose: wxGaugeBase: common to all ports methods of wxGauge -// Author: Vadim Zeitlin -// Modified by: -// Created: 20.02.01 -// RCS-ID: $Id: gaugecmn.cpp 41089 2006-09-09 13:36:54Z RR $ -// Copyright: (c) 2001 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP -#endif //WX_PRECOMP - -#if wxUSE_GAUGE - -#include "wx/gauge.h" - -const wxChar wxGaugeNameStr[] = wxT("gauge"); - -// ============================================================================ -// implementation -// ============================================================================ - -wxGaugeBase::~wxGaugeBase() -{ - // this destructor is required for Darwin -} - -// ---------------------------------------------------------------------------- -// wxGauge creation -// ---------------------------------------------------------------------------- - -bool wxGaugeBase::Create(wxWindow *parent, - wxWindowID id, - int range, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name) -{ - if ( !wxControl::Create(parent, id, pos, size, style, validator, name) ) - return false; - - SetName(name); - -#if wxUSE_VALIDATORS - SetValidator(validator); -#endif // wxUSE_VALIDATORS - - SetRange(range); - SetValue(0); -#if wxGAUGE_EMULATE_INDETERMINATE_MODE - m_nDirection = wxRIGHT; -#endif - - return true; -} - -// ---------------------------------------------------------------------------- -// wxGauge determinate mode range/position -// ---------------------------------------------------------------------------- - -void wxGaugeBase::SetRange(int range) -{ - m_rangeMax = range; -} - -int wxGaugeBase::GetRange() const -{ - return m_rangeMax; -} - -void wxGaugeBase::SetValue(int pos) -{ - m_gaugePos = pos; -} - -int wxGaugeBase::GetValue() const -{ - return m_gaugePos; -} - -// ---------------------------------------------------------------------------- -// wxGauge indeterminate mode -// ---------------------------------------------------------------------------- - -void wxGaugeBase::Pulse() -{ -#if wxGAUGE_EMULATE_INDETERMINATE_MODE - // simulate indeterminate mode - int curr = GetValue(), max = GetRange(); - - if (m_nDirection == wxRIGHT) - { - if (curr < max) - SetValue(curr + 1); - else - { - SetValue(max - 1); - m_nDirection = wxLEFT; - } - } - else - { - if (curr > 0) - SetValue(curr - 1); - else - { - SetValue(1); - m_nDirection = wxRIGHT; - } - } -#endif -} - -// ---------------------------------------------------------------------------- -// wxGauge appearance params -// ---------------------------------------------------------------------------- - -void wxGaugeBase::SetShadowWidth(int WXUNUSED(w)) -{ -} - -int wxGaugeBase::GetShadowWidth() const -{ - return 0; -} - - -void wxGaugeBase::SetBezelFace(int WXUNUSED(w)) -{ -} - -int wxGaugeBase::GetBezelFace() const -{ - return 0; -} - -#endif // wxUSE_GAUGE +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/gaugecmn.cpp +// Purpose: wxGaugeBase: common to all ports methods of wxGauge +// Author: Vadim Zeitlin +// Modified by: +// Created: 20.02.01 +// RCS-ID: $Id: gaugecmn.cpp 41089 2006-09-09 13:36:54Z RR $ +// Copyright: (c) 2001 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#endif //WX_PRECOMP + +#if wxUSE_GAUGE + +#include "wx/gauge.h" + +const wxChar wxGaugeNameStr[] = wxT("gauge"); + +// ============================================================================ +// implementation +// ============================================================================ + +wxGaugeBase::~wxGaugeBase() +{ + // this destructor is required for Darwin +} + +// ---------------------------------------------------------------------------- +// wxGauge creation +// ---------------------------------------------------------------------------- + +bool wxGaugeBase::Create(wxWindow *parent, + wxWindowID id, + int range, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + if ( !wxControl::Create(parent, id, pos, size, style, validator, name) ) + return false; + + SetName(name); + +#if wxUSE_VALIDATORS + SetValidator(validator); +#endif // wxUSE_VALIDATORS + + SetRange(range); + SetValue(0); +#if wxGAUGE_EMULATE_INDETERMINATE_MODE + m_nDirection = wxRIGHT; +#endif + + return true; +} + +// ---------------------------------------------------------------------------- +// wxGauge determinate mode range/position +// ---------------------------------------------------------------------------- + +void wxGaugeBase::SetRange(int range) +{ + m_rangeMax = range; +} + +int wxGaugeBase::GetRange() const +{ + return m_rangeMax; +} + +void wxGaugeBase::SetValue(int pos) +{ + m_gaugePos = pos; +} + +int wxGaugeBase::GetValue() const +{ + return m_gaugePos; +} + +// ---------------------------------------------------------------------------- +// wxGauge indeterminate mode +// ---------------------------------------------------------------------------- + +void wxGaugeBase::Pulse() +{ +#if wxGAUGE_EMULATE_INDETERMINATE_MODE + // simulate indeterminate mode + int curr = GetValue(), max = GetRange(); + + if (m_nDirection == wxRIGHT) + { + if (curr < max) + SetValue(curr + 1); + else + { + SetValue(max - 1); + m_nDirection = wxLEFT; + } + } + else + { + if (curr > 0) + SetValue(curr - 1); + else + { + SetValue(1); + m_nDirection = wxRIGHT; + } + } +#endif +} + +// ---------------------------------------------------------------------------- +// wxGauge appearance params +// ---------------------------------------------------------------------------- + +void wxGaugeBase::SetShadowWidth(int WXUNUSED(w)) +{ +} + +int wxGaugeBase::GetShadowWidth() const +{ + return 0; +} + + +void wxGaugeBase::SetBezelFace(int WXUNUSED(w)) +{ +} + +int wxGaugeBase::GetBezelFace() const +{ + return 0; +} + +#endif // wxUSE_GAUGE diff --git a/Source/3rd Party/wx/src/common/gbsizer.cpp b/Source/3rd Party/wx/src/common/gbsizer.cpp index 4ddb9e2cd..c81e80c2b 100644 --- a/Source/3rd Party/wx/src/common/gbsizer.cpp +++ b/Source/3rd Party/wx/src/common/gbsizer.cpp @@ -1,784 +1,784 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: gbsizer.cpp -// Purpose: wxGridBagSizer: A sizer that can lay out items in a grid, -// with items at specified cells, and with the option of row -// and/or column spanning -// -// Author: Robin Dunn -// Created: 03-Nov-2003 -// RCS-ID: $Id: gbsizer.cpp 54568 2008-07-10 01:32:23Z RD $ -// Copyright: (c) Robin Dunn -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/gbsizer.h" - -//--------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGBSizerItem, wxSizerItem) -IMPLEMENT_CLASS(wxGridBagSizer, wxFlexGridSizer) - -const wxGBSpan wxDefaultSpan; - -//--------------------------------------------------------------------------- -// wxGBSizerItem -//--------------------------------------------------------------------------- - -wxGBSizerItem::wxGBSizerItem( int width, - int height, - const wxGBPosition& pos, - const wxGBSpan& span, - int flag, - int border, - wxObject* userData) - : wxSizerItem(width, height, 0, flag, border, userData), - m_pos(pos), - m_span(span), - m_gbsizer(NULL) -{ -} - - -wxGBSizerItem::wxGBSizerItem( wxWindow *window, - const wxGBPosition& pos, - const wxGBSpan& span, - int flag, - int border, - wxObject* userData ) - : wxSizerItem(window, 0, flag, border, userData), - m_pos(pos), - m_span(span), - m_gbsizer(NULL) -{ -} - - -wxGBSizerItem::wxGBSizerItem( wxSizer *sizer, - const wxGBPosition& pos, - const wxGBSpan& span, - int flag, - int border, - wxObject* userData ) - : wxSizerItem(sizer, 0, flag, border, userData), - m_pos(pos), - m_span(span), - m_gbsizer(NULL) -{ -} - -wxGBSizerItem::wxGBSizerItem() - : wxSizerItem(), - m_pos(-1,-1), - m_span(-1,-1), - m_gbsizer(NULL) -{ -} - -//--------------------------------------------------------------------------- - - -void wxGBSizerItem::GetPos(int& row, int& col) const -{ - row = m_pos.GetRow(); - col = m_pos.GetCol(); -} - -void wxGBSizerItem::GetSpan(int& rowspan, int& colspan) const -{ - rowspan = m_span.GetRowspan(); - colspan = m_span.GetColspan(); -} - - -bool wxGBSizerItem::SetPos( const wxGBPosition& pos ) -{ - if (m_gbsizer) - { - wxCHECK_MSG( !m_gbsizer->CheckForIntersection(pos, m_span, this), false, - wxT("An item is already at that position") ); - } - m_pos = pos; - return true; -} - -bool wxGBSizerItem::SetSpan( const wxGBSpan& span ) -{ - if (m_gbsizer) - { - wxCHECK_MSG( !m_gbsizer->CheckForIntersection(m_pos, span, this), false, - wxT("An item is already at that position") ); - } - m_span = span; - return true; -} - - -inline bool InRange(int val, int min, int max) -{ - return (val >= min && val <= max); -} - -bool wxGBSizerItem::Intersects(const wxGBSizerItem& other) -{ - return Intersects(other.GetPos(), other.GetSpan()); -} - -bool wxGBSizerItem::Intersects(const wxGBPosition& pos, const wxGBSpan& span) -{ - - int row, col, endrow, endcol; - int otherrow, othercol, otherendrow, otherendcol; - - GetPos(row, col); - GetEndPos(endrow, endcol); - - otherrow = pos.GetRow(); - othercol = pos.GetCol(); - otherendrow = otherrow + span.GetRowspan() - 1; - otherendcol = othercol + span.GetColspan() - 1; - - // is the other item's start or end in the range of this one? - if (( InRange(otherrow, row, endrow) && InRange(othercol, col, endcol) ) || - ( InRange(otherendrow, row, endrow) && InRange(otherendcol, col, endcol) )) - return true; - - // is this item's start or end in the range of the other one? - if (( InRange(row, otherrow, otherendrow) && InRange(col, othercol, otherendcol) ) || - ( InRange(endrow, otherrow, otherendrow) && InRange(endcol, othercol, otherendcol) )) - return true; - - return false; -} - - -void wxGBSizerItem::GetEndPos(int& row, int& col) -{ - row = m_pos.GetRow() + m_span.GetRowspan() - 1; - col = m_pos.GetCol() + m_span.GetColspan() - 1; -} - - -//--------------------------------------------------------------------------- -// wxGridBagSizer -//--------------------------------------------------------------------------- - -wxGridBagSizer::wxGridBagSizer(int vgap, int hgap ) - : wxFlexGridSizer(1, vgap, hgap), - m_emptyCellSize(10,20) - -{ -} - - -wxSizerItem* wxGridBagSizer::Add( wxWindow *window, - const wxGBPosition& pos, const wxGBSpan& span, - int flag, int border, wxObject* userData ) -{ - wxGBSizerItem* item = new wxGBSizerItem(window, pos, span, flag, border, userData); - if ( Add(item) ) - return item; - else - { - delete item; - return (wxSizerItem*)NULL; - } -} - -wxSizerItem* wxGridBagSizer::Add( wxSizer *sizer, - const wxGBPosition& pos, const wxGBSpan& span, - int flag, int border, wxObject* userData ) -{ - wxGBSizerItem* item = new wxGBSizerItem(sizer, pos, span, flag, border, userData); - if ( Add(item) ) - return item; - else - { - delete item; - return (wxSizerItem*)NULL; - } -} - -wxSizerItem* wxGridBagSizer::Add( int width, int height, - const wxGBPosition& pos, const wxGBSpan& span, - int flag, int border, wxObject* userData ) -{ - wxGBSizerItem* item = new wxGBSizerItem(width, height, pos, span, flag, border, userData); - if ( Add(item) ) - return item; - else - { - delete item; - return (wxSizerItem*)NULL; - } -} - -wxSizerItem* wxGridBagSizer::Add( wxGBSizerItem *item ) -{ - wxCHECK_MSG( !CheckForIntersection(item), NULL, - wxT("An item is already at that position") ); - m_children.Append(item); - item->SetGBSizer(this); - if ( item->GetWindow() ) - item->GetWindow()->SetContainingSizer( this ); - - return item; -} - - - -//--------------------------------------------------------------------------- - -wxSize wxGridBagSizer::GetCellSize(int row, int col) const -{ - wxCHECK_MSG( (row < m_rows) && (col < m_cols), - wxDefaultSize, - wxT("Invalid cell.")); - return wxSize( m_colWidths[col], m_rowHeights[row] ); -} - - -wxGBPosition wxGridBagSizer::GetItemPosition(wxWindow *window) -{ - wxGBPosition badpos(-1,-1); - wxGBSizerItem* item = FindItem(window); - wxCHECK_MSG(item, badpos, wxT("Failed to find item.")); - return item->GetPos(); -} - - -wxGBPosition wxGridBagSizer::GetItemPosition(wxSizer *sizer) -{ - wxGBPosition badpos(-1,-1); - wxGBSizerItem* item = FindItem(sizer); - wxCHECK_MSG(item, badpos, wxT("Failed to find item.")); - return item->GetPos(); -} - - -wxGBPosition wxGridBagSizer::GetItemPosition(size_t index) -{ - wxGBPosition badpos(-1,-1); - wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - wxCHECK_MSG( node, badpos, _T("Failed to find item.") ); - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - return item->GetPos(); -} - - - -bool wxGridBagSizer::SetItemPosition(wxWindow *window, const wxGBPosition& pos) -{ - wxGBSizerItem* item = FindItem(window); - wxCHECK_MSG(item, false, wxT("Failed to find item.")); - return item->SetPos(pos); -} - - -bool wxGridBagSizer::SetItemPosition(wxSizer *sizer, const wxGBPosition& pos) -{ - wxGBSizerItem* item = FindItem(sizer); - wxCHECK_MSG(item, false, wxT("Failed to find item.")); - return item->SetPos(pos); -} - - -bool wxGridBagSizer::SetItemPosition(size_t index, const wxGBPosition& pos) -{ - wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - wxCHECK_MSG( node, false, _T("Failed to find item.") ); - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - return item->SetPos(pos); -} - - - -wxGBSpan wxGridBagSizer::GetItemSpan(wxWindow *window) -{ - wxGBSpan badspan(-1,-1); - wxGBSizerItem* item = FindItem(window); - wxCHECK_MSG( item, badspan, _T("Failed to find item.") ); - return item->GetSpan(); -} - - -wxGBSpan wxGridBagSizer::GetItemSpan(wxSizer *sizer) -{ - wxGBSpan badspan(-1,-1); - wxGBSizerItem* item = FindItem(sizer); - wxCHECK_MSG( item, badspan, _T("Failed to find item.") ); - return item->GetSpan(); -} - - -wxGBSpan wxGridBagSizer::GetItemSpan(size_t index) -{ - wxGBSpan badspan(-1,-1); - wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - wxCHECK_MSG( node, badspan, _T("Failed to find item.") ); - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - return item->GetSpan(); -} - - - -bool wxGridBagSizer::SetItemSpan(wxWindow *window, const wxGBSpan& span) -{ - wxGBSizerItem* item = FindItem(window); - wxCHECK_MSG(item, false, wxT("Failed to find item.")); - return item->SetSpan(span); -} - - -bool wxGridBagSizer::SetItemSpan(wxSizer *sizer, const wxGBSpan& span) -{ - wxGBSizerItem* item = FindItem(sizer); - wxCHECK_MSG(item, false, wxT("Failed to find item.")); - return item->SetSpan(span); -} - - -bool wxGridBagSizer::SetItemSpan(size_t index, const wxGBSpan& span) -{ - wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - wxCHECK_MSG( node, false, _T("Failed to find item.") ); - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - return item->SetSpan(span); -} - - - - -wxGBSizerItem* wxGridBagSizer::FindItem(wxWindow* window) -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - if ( item->GetWindow() == window ) - return item; - node = node->GetNext(); - } - return NULL; -} - - -wxGBSizerItem* wxGridBagSizer::FindItem(wxSizer* sizer) -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - if ( item->GetSizer() == sizer ) - return item; - node = node->GetNext(); - } - return NULL; -} - - - - -wxGBSizerItem* wxGridBagSizer::FindItemAtPosition(const wxGBPosition& pos) -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - if ( item->Intersects(pos, wxDefaultSpan) ) - return item; - node = node->GetNext(); - } - return NULL; -} - - - - -wxGBSizerItem* wxGridBagSizer::FindItemAtPoint(const wxPoint& pt) -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - wxRect rect(item->GetPosition(), item->GetSize()); - rect.Inflate(m_hgap, m_vgap); - if ( rect.Contains(pt) ) - return item; - node = node->GetNext(); - } - return NULL; -} - - - - -wxGBSizerItem* wxGridBagSizer::FindItemWithData(const wxObject* userData) -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - if ( item->GetUserData() == userData ) - return item; - node = node->GetNext(); - } - return NULL; -} - - - - -//--------------------------------------------------------------------------- - -// Figure out what all the min row heights and col widths are, and calculate -// min size from that. -wxSize wxGridBagSizer::CalcMin() -{ - int idx; - - if (m_children.GetCount() == 0) - return m_emptyCellSize; - - m_rowHeights.Empty(); - m_colWidths.Empty(); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - if ( item->ShouldAccountFor() ) - { - int row, col, endrow, endcol; - - item->GetPos(row, col); - item->GetEndPos(endrow, endcol); - - // fill heights and widths upto this item if needed - while ( m_rowHeights.GetCount() <= (size_t)endrow ) - m_rowHeights.Add(m_emptyCellSize.GetHeight()); - while ( m_colWidths.GetCount() <= (size_t)endcol ) - m_colWidths.Add(m_emptyCellSize.GetWidth()); - - // See if this item increases the size of its row(s) or col(s) - wxSize size(item->CalcMin()); - for (idx=row; idx <= endrow; idx++) - m_rowHeights[idx] = wxMax(m_rowHeights[idx], size.GetHeight() / (endrow-row+1)); - for (idx=col; idx <= endcol; idx++) - m_colWidths[idx] = wxMax(m_colWidths[idx], size.GetWidth() / (endcol-col+1)); - } - node = node->GetNext(); - } - - AdjustForOverflow(); - AdjustForFlexDirection(); - - // Now traverse the heights and widths arrays calcing the totals, including gaps - int width = 0; - m_cols = m_colWidths.GetCount(); - for (idx=0; idx < m_cols; idx++) - width += m_colWidths[idx] + ( idx == m_cols-1 ? 0 : m_hgap ); - - int height = 0; - m_rows = m_rowHeights.GetCount(); - for (idx=0; idx < m_rows; idx++) - height += m_rowHeights[idx] + ( idx == m_rows-1 ? 0 : m_vgap ); - - m_calculatedMinSize = wxSize(width, height); - return m_calculatedMinSize; -} - - - -void wxGridBagSizer::RecalcSizes() -{ - if (m_children.GetCount() == 0) - return; - - wxPoint pt( GetPosition() ); - wxSize sz( GetSize() ); - - m_rows = m_rowHeights.GetCount(); - m_cols = m_colWidths.GetCount(); - int idx, width, height; - - AdjustForGrowables(sz, m_calculatedMinSize, m_rows, m_cols); - - // Find the start positions on the window of the rows and columns - wxArrayInt rowpos; - rowpos.Add(0, m_rows); - int y = pt.y; - for (idx=0; idx < m_rows; idx++) - { - height = m_rowHeights[idx] + m_vgap; - rowpos[idx] = y; - y += height; - } - - wxArrayInt colpos; - colpos.Add(0, m_cols); - int x = pt.x; - for (idx=0; idx < m_cols; idx++) - { - width = m_colWidths[idx] + m_hgap; - colpos[idx] = x; - x += width; - } - - - // Now iterate the children, setting each child's dimensions - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - int row, col, endrow, endcol; - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - - if ( item->ShouldAccountFor() ) - { - item->GetPos(row, col); - item->GetEndPos(endrow, endcol); - - height = 0; - for(idx=row; idx <= endrow; idx++) - height += m_rowHeights[idx]; - height += (endrow - row) * m_vgap; // add a vgap for every row spanned - - width = 0; - for (idx=col; idx <= endcol; idx++) - width += m_colWidths[idx]; - width += (endcol - col) * m_hgap; // add a hgap for every col spanned - - SetItemBounds(item, colpos[col], rowpos[row], width, height); - } - - node = node->GetNext(); - } -} - - -// Sometimes CalcMin can result in some rows or cols having too much space in -// them because as it traverses the items it makes some assumptions when -// items span to other cells. But those assumptions can become invalid later -// on when other items are fitted into the same rows or columns that the -// spanning item occupies. This method tries to find those situations and -// fixes them. -void wxGridBagSizer::AdjustForOverflow() -{ - int row, col; - - for (row=0; row<(int)m_rowHeights.GetCount(); row++) - { - int rowExtra=INT_MAX; - int rowHeight = m_rowHeights[row]; - for (col=0; col<(int)m_colWidths.GetCount(); col++) - { - wxGBPosition pos(row,col); - wxGBSizerItem* item = FindItemAtPosition(pos); - if ( !item || !item->ShouldAccountFor() ) - continue; - - int endrow, endcol; - item->GetEndPos(endrow, endcol); - - // If the item starts in this position and doesn't span rows, then - // just look at the whole item height - if ( item->GetPos() == pos && endrow == row ) - { - int itemHeight = item->CalcMin().GetHeight(); - rowExtra = wxMin(rowExtra, rowHeight - itemHeight); - continue; - } - - // Otherwise, only look at spanning items if they end on this row - if ( endrow == row ) - { - // first deduct the portions of the item that are on prior rows - int itemHeight = item->CalcMin().GetHeight(); - for (int r=item->GetPos().GetRow(); rShouldAccountFor() ) - continue; - - int endrow, endcol; - item->GetEndPos(endrow, endcol); - - if ( item->GetPos() == pos && endcol == col ) - { - int itemWidth = item->CalcMin().GetWidth(); - colExtra = wxMin(colExtra, colWidth - itemWidth); - continue; - } - - if ( endcol == col ) - { - int itemWidth = item->CalcMin().GetWidth(); - for (int c=item->GetPos().GetCol(); cGetPos(), item->GetSpan(), excludeItem); -} - -bool wxGridBagSizer::CheckForIntersection(const wxGBPosition& pos, const wxGBSpan& span, wxGBSizerItem* excludeItem) -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); - node = node->GetNext(); - - if ( excludeItem && item == excludeItem ) - continue; - - if ( item->Intersects(pos, span) ) - return true; - - } - return false; -} - - -// Assumes a 10x10 grid, and returns the first empty cell found. This is -// really stupid but it is only used by the Add methods that match the base -// class virtuals, which should normally not be used anyway... -wxGBPosition wxGridBagSizer::FindEmptyCell() -{ - int row, col; - - for (row=0; row<10; row++) - for (col=0; col<10; col++) - { - wxGBPosition pos(row, col); - if ( !CheckForIntersection(pos, wxDefaultSpan) ) - return pos; - } - return wxGBPosition(-1, -1); -} - - -//--------------------------------------------------------------------------- - -// The Add base class virtuals should not be used with this class, but -// we'll try to make them automatically select a location for the item -// anyway. - -wxSizerItem* wxGridBagSizer::Add( wxWindow *window, int, int flag, int border, wxObject* userData ) -{ - return Add(window, FindEmptyCell(), wxDefaultSpan, flag, border, userData); -} - -wxSizerItem* wxGridBagSizer::Add( wxSizer *sizer, int, int flag, int border, wxObject* userData ) -{ - return Add(sizer, FindEmptyCell(), wxDefaultSpan, flag, border, userData); -} - -wxSizerItem* wxGridBagSizer::Add( int width, int height, int, int flag, int border, wxObject* userData ) -{ - return Add(width, height, FindEmptyCell(), wxDefaultSpan, flag, border, userData); -} - - - -// The Insert nad Prepend base class virtuals that are not appropriate for -// this class and should not be used. Their implementation in this class -// simply fails. - -wxSizerItem* wxGridBagSizer::Add( wxSizerItem * ) -{ - wxFAIL_MSG(wxT("Invalid Add form called.")); - return (wxSizerItem*)NULL; -} - -wxSizerItem* wxGridBagSizer::Prepend( wxWindow *, int, int, int, wxObject* ) -{ - wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - -wxSizerItem* wxGridBagSizer::Prepend( wxSizer *, int, int, int, wxObject* ) -{ - wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - -wxSizerItem* wxGridBagSizer::Prepend( int, int, int, int, int, wxObject* ) -{ - wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - -wxSizerItem* wxGridBagSizer::Prepend( wxSizerItem * ) -{ - wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - - -wxSizerItem* wxGridBagSizer::Insert( size_t, wxWindow *, int, int, int, wxObject* ) -{ - wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - -wxSizerItem* wxGridBagSizer::Insert( size_t, wxSizer *, int, int, int, wxObject* ) -{ - wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - -wxSizerItem* wxGridBagSizer::Insert( size_t, int, int, int, int, int, wxObject* ) -{ - wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - -wxSizerItem* wxGridBagSizer::Insert( size_t, wxSizerItem * ) -{ - wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); - return (wxSizerItem*)NULL; -} - - -//--------------------------------------------------------------------------- -//--------------------------------------------------------------------------- +///////////////////////////////////////////////////////////////////////////// +// Name: gbsizer.cpp +// Purpose: wxGridBagSizer: A sizer that can lay out items in a grid, +// with items at specified cells, and with the option of row +// and/or column spanning +// +// Author: Robin Dunn +// Created: 03-Nov-2003 +// RCS-ID: $Id: gbsizer.cpp 54568 2008-07-10 01:32:23Z RD $ +// Copyright: (c) Robin Dunn +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/gbsizer.h" + +//--------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGBSizerItem, wxSizerItem) +IMPLEMENT_CLASS(wxGridBagSizer, wxFlexGridSizer) + +const wxGBSpan wxDefaultSpan; + +//--------------------------------------------------------------------------- +// wxGBSizerItem +//--------------------------------------------------------------------------- + +wxGBSizerItem::wxGBSizerItem( int width, + int height, + const wxGBPosition& pos, + const wxGBSpan& span, + int flag, + int border, + wxObject* userData) + : wxSizerItem(width, height, 0, flag, border, userData), + m_pos(pos), + m_span(span), + m_gbsizer(NULL) +{ +} + + +wxGBSizerItem::wxGBSizerItem( wxWindow *window, + const wxGBPosition& pos, + const wxGBSpan& span, + int flag, + int border, + wxObject* userData ) + : wxSizerItem(window, 0, flag, border, userData), + m_pos(pos), + m_span(span), + m_gbsizer(NULL) +{ +} + + +wxGBSizerItem::wxGBSizerItem( wxSizer *sizer, + const wxGBPosition& pos, + const wxGBSpan& span, + int flag, + int border, + wxObject* userData ) + : wxSizerItem(sizer, 0, flag, border, userData), + m_pos(pos), + m_span(span), + m_gbsizer(NULL) +{ +} + +wxGBSizerItem::wxGBSizerItem() + : wxSizerItem(), + m_pos(-1,-1), + m_span(-1,-1), + m_gbsizer(NULL) +{ +} + +//--------------------------------------------------------------------------- + + +void wxGBSizerItem::GetPos(int& row, int& col) const +{ + row = m_pos.GetRow(); + col = m_pos.GetCol(); +} + +void wxGBSizerItem::GetSpan(int& rowspan, int& colspan) const +{ + rowspan = m_span.GetRowspan(); + colspan = m_span.GetColspan(); +} + + +bool wxGBSizerItem::SetPos( const wxGBPosition& pos ) +{ + if (m_gbsizer) + { + wxCHECK_MSG( !m_gbsizer->CheckForIntersection(pos, m_span, this), false, + wxT("An item is already at that position") ); + } + m_pos = pos; + return true; +} + +bool wxGBSizerItem::SetSpan( const wxGBSpan& span ) +{ + if (m_gbsizer) + { + wxCHECK_MSG( !m_gbsizer->CheckForIntersection(m_pos, span, this), false, + wxT("An item is already at that position") ); + } + m_span = span; + return true; +} + + +inline bool InRange(int val, int min, int max) +{ + return (val >= min && val <= max); +} + +bool wxGBSizerItem::Intersects(const wxGBSizerItem& other) +{ + return Intersects(other.GetPos(), other.GetSpan()); +} + +bool wxGBSizerItem::Intersects(const wxGBPosition& pos, const wxGBSpan& span) +{ + + int row, col, endrow, endcol; + int otherrow, othercol, otherendrow, otherendcol; + + GetPos(row, col); + GetEndPos(endrow, endcol); + + otherrow = pos.GetRow(); + othercol = pos.GetCol(); + otherendrow = otherrow + span.GetRowspan() - 1; + otherendcol = othercol + span.GetColspan() - 1; + + // is the other item's start or end in the range of this one? + if (( InRange(otherrow, row, endrow) && InRange(othercol, col, endcol) ) || + ( InRange(otherendrow, row, endrow) && InRange(otherendcol, col, endcol) )) + return true; + + // is this item's start or end in the range of the other one? + if (( InRange(row, otherrow, otherendrow) && InRange(col, othercol, otherendcol) ) || + ( InRange(endrow, otherrow, otherendrow) && InRange(endcol, othercol, otherendcol) )) + return true; + + return false; +} + + +void wxGBSizerItem::GetEndPos(int& row, int& col) +{ + row = m_pos.GetRow() + m_span.GetRowspan() - 1; + col = m_pos.GetCol() + m_span.GetColspan() - 1; +} + + +//--------------------------------------------------------------------------- +// wxGridBagSizer +//--------------------------------------------------------------------------- + +wxGridBagSizer::wxGridBagSizer(int vgap, int hgap ) + : wxFlexGridSizer(1, vgap, hgap), + m_emptyCellSize(10,20) + +{ +} + + +wxSizerItem* wxGridBagSizer::Add( wxWindow *window, + const wxGBPosition& pos, const wxGBSpan& span, + int flag, int border, wxObject* userData ) +{ + wxGBSizerItem* item = new wxGBSizerItem(window, pos, span, flag, border, userData); + if ( Add(item) ) + return item; + else + { + delete item; + return (wxSizerItem*)NULL; + } +} + +wxSizerItem* wxGridBagSizer::Add( wxSizer *sizer, + const wxGBPosition& pos, const wxGBSpan& span, + int flag, int border, wxObject* userData ) +{ + wxGBSizerItem* item = new wxGBSizerItem(sizer, pos, span, flag, border, userData); + if ( Add(item) ) + return item; + else + { + delete item; + return (wxSizerItem*)NULL; + } +} + +wxSizerItem* wxGridBagSizer::Add( int width, int height, + const wxGBPosition& pos, const wxGBSpan& span, + int flag, int border, wxObject* userData ) +{ + wxGBSizerItem* item = new wxGBSizerItem(width, height, pos, span, flag, border, userData); + if ( Add(item) ) + return item; + else + { + delete item; + return (wxSizerItem*)NULL; + } +} + +wxSizerItem* wxGridBagSizer::Add( wxGBSizerItem *item ) +{ + wxCHECK_MSG( !CheckForIntersection(item), NULL, + wxT("An item is already at that position") ); + m_children.Append(item); + item->SetGBSizer(this); + if ( item->GetWindow() ) + item->GetWindow()->SetContainingSizer( this ); + + return item; +} + + + +//--------------------------------------------------------------------------- + +wxSize wxGridBagSizer::GetCellSize(int row, int col) const +{ + wxCHECK_MSG( (row < m_rows) && (col < m_cols), + wxDefaultSize, + wxT("Invalid cell.")); + return wxSize( m_colWidths[col], m_rowHeights[row] ); +} + + +wxGBPosition wxGridBagSizer::GetItemPosition(wxWindow *window) +{ + wxGBPosition badpos(-1,-1); + wxGBSizerItem* item = FindItem(window); + wxCHECK_MSG(item, badpos, wxT("Failed to find item.")); + return item->GetPos(); +} + + +wxGBPosition wxGridBagSizer::GetItemPosition(wxSizer *sizer) +{ + wxGBPosition badpos(-1,-1); + wxGBSizerItem* item = FindItem(sizer); + wxCHECK_MSG(item, badpos, wxT("Failed to find item.")); + return item->GetPos(); +} + + +wxGBPosition wxGridBagSizer::GetItemPosition(size_t index) +{ + wxGBPosition badpos(-1,-1); + wxSizerItemList::compatibility_iterator node = m_children.Item( index ); + wxCHECK_MSG( node, badpos, _T("Failed to find item.") ); + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + return item->GetPos(); +} + + + +bool wxGridBagSizer::SetItemPosition(wxWindow *window, const wxGBPosition& pos) +{ + wxGBSizerItem* item = FindItem(window); + wxCHECK_MSG(item, false, wxT("Failed to find item.")); + return item->SetPos(pos); +} + + +bool wxGridBagSizer::SetItemPosition(wxSizer *sizer, const wxGBPosition& pos) +{ + wxGBSizerItem* item = FindItem(sizer); + wxCHECK_MSG(item, false, wxT("Failed to find item.")); + return item->SetPos(pos); +} + + +bool wxGridBagSizer::SetItemPosition(size_t index, const wxGBPosition& pos) +{ + wxSizerItemList::compatibility_iterator node = m_children.Item( index ); + wxCHECK_MSG( node, false, _T("Failed to find item.") ); + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + return item->SetPos(pos); +} + + + +wxGBSpan wxGridBagSizer::GetItemSpan(wxWindow *window) +{ + wxGBSpan badspan(-1,-1); + wxGBSizerItem* item = FindItem(window); + wxCHECK_MSG( item, badspan, _T("Failed to find item.") ); + return item->GetSpan(); +} + + +wxGBSpan wxGridBagSizer::GetItemSpan(wxSizer *sizer) +{ + wxGBSpan badspan(-1,-1); + wxGBSizerItem* item = FindItem(sizer); + wxCHECK_MSG( item, badspan, _T("Failed to find item.") ); + return item->GetSpan(); +} + + +wxGBSpan wxGridBagSizer::GetItemSpan(size_t index) +{ + wxGBSpan badspan(-1,-1); + wxSizerItemList::compatibility_iterator node = m_children.Item( index ); + wxCHECK_MSG( node, badspan, _T("Failed to find item.") ); + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + return item->GetSpan(); +} + + + +bool wxGridBagSizer::SetItemSpan(wxWindow *window, const wxGBSpan& span) +{ + wxGBSizerItem* item = FindItem(window); + wxCHECK_MSG(item, false, wxT("Failed to find item.")); + return item->SetSpan(span); +} + + +bool wxGridBagSizer::SetItemSpan(wxSizer *sizer, const wxGBSpan& span) +{ + wxGBSizerItem* item = FindItem(sizer); + wxCHECK_MSG(item, false, wxT("Failed to find item.")); + return item->SetSpan(span); +} + + +bool wxGridBagSizer::SetItemSpan(size_t index, const wxGBSpan& span) +{ + wxSizerItemList::compatibility_iterator node = m_children.Item( index ); + wxCHECK_MSG( node, false, _T("Failed to find item.") ); + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + return item->SetSpan(span); +} + + + + +wxGBSizerItem* wxGridBagSizer::FindItem(wxWindow* window) +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + if ( item->GetWindow() == window ) + return item; + node = node->GetNext(); + } + return NULL; +} + + +wxGBSizerItem* wxGridBagSizer::FindItem(wxSizer* sizer) +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + if ( item->GetSizer() == sizer ) + return item; + node = node->GetNext(); + } + return NULL; +} + + + + +wxGBSizerItem* wxGridBagSizer::FindItemAtPosition(const wxGBPosition& pos) +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + if ( item->Intersects(pos, wxDefaultSpan) ) + return item; + node = node->GetNext(); + } + return NULL; +} + + + + +wxGBSizerItem* wxGridBagSizer::FindItemAtPoint(const wxPoint& pt) +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + wxRect rect(item->GetPosition(), item->GetSize()); + rect.Inflate(m_hgap, m_vgap); + if ( rect.Contains(pt) ) + return item; + node = node->GetNext(); + } + return NULL; +} + + + + +wxGBSizerItem* wxGridBagSizer::FindItemWithData(const wxObject* userData) +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + if ( item->GetUserData() == userData ) + return item; + node = node->GetNext(); + } + return NULL; +} + + + + +//--------------------------------------------------------------------------- + +// Figure out what all the min row heights and col widths are, and calculate +// min size from that. +wxSize wxGridBagSizer::CalcMin() +{ + int idx; + + if (m_children.GetCount() == 0) + return m_emptyCellSize; + + m_rowHeights.Empty(); + m_colWidths.Empty(); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + if ( item->ShouldAccountFor() ) + { + int row, col, endrow, endcol; + + item->GetPos(row, col); + item->GetEndPos(endrow, endcol); + + // fill heights and widths upto this item if needed + while ( m_rowHeights.GetCount() <= (size_t)endrow ) + m_rowHeights.Add(m_emptyCellSize.GetHeight()); + while ( m_colWidths.GetCount() <= (size_t)endcol ) + m_colWidths.Add(m_emptyCellSize.GetWidth()); + + // See if this item increases the size of its row(s) or col(s) + wxSize size(item->CalcMin()); + for (idx=row; idx <= endrow; idx++) + m_rowHeights[idx] = wxMax(m_rowHeights[idx], size.GetHeight() / (endrow-row+1)); + for (idx=col; idx <= endcol; idx++) + m_colWidths[idx] = wxMax(m_colWidths[idx], size.GetWidth() / (endcol-col+1)); + } + node = node->GetNext(); + } + + AdjustForOverflow(); + AdjustForFlexDirection(); + + // Now traverse the heights and widths arrays calcing the totals, including gaps + int width = 0; + m_cols = m_colWidths.GetCount(); + for (idx=0; idx < m_cols; idx++) + width += m_colWidths[idx] + ( idx == m_cols-1 ? 0 : m_hgap ); + + int height = 0; + m_rows = m_rowHeights.GetCount(); + for (idx=0; idx < m_rows; idx++) + height += m_rowHeights[idx] + ( idx == m_rows-1 ? 0 : m_vgap ); + + m_calculatedMinSize = wxSize(width, height); + return m_calculatedMinSize; +} + + + +void wxGridBagSizer::RecalcSizes() +{ + if (m_children.GetCount() == 0) + return; + + wxPoint pt( GetPosition() ); + wxSize sz( GetSize() ); + + m_rows = m_rowHeights.GetCount(); + m_cols = m_colWidths.GetCount(); + int idx, width, height; + + AdjustForGrowables(sz, m_calculatedMinSize, m_rows, m_cols); + + // Find the start positions on the window of the rows and columns + wxArrayInt rowpos; + rowpos.Add(0, m_rows); + int y = pt.y; + for (idx=0; idx < m_rows; idx++) + { + height = m_rowHeights[idx] + m_vgap; + rowpos[idx] = y; + y += height; + } + + wxArrayInt colpos; + colpos.Add(0, m_cols); + int x = pt.x; + for (idx=0; idx < m_cols; idx++) + { + width = m_colWidths[idx] + m_hgap; + colpos[idx] = x; + x += width; + } + + + // Now iterate the children, setting each child's dimensions + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + int row, col, endrow, endcol; + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + + if ( item->ShouldAccountFor() ) + { + item->GetPos(row, col); + item->GetEndPos(endrow, endcol); + + height = 0; + for(idx=row; idx <= endrow; idx++) + height += m_rowHeights[idx]; + height += (endrow - row) * m_vgap; // add a vgap for every row spanned + + width = 0; + for (idx=col; idx <= endcol; idx++) + width += m_colWidths[idx]; + width += (endcol - col) * m_hgap; // add a hgap for every col spanned + + SetItemBounds(item, colpos[col], rowpos[row], width, height); + } + + node = node->GetNext(); + } +} + + +// Sometimes CalcMin can result in some rows or cols having too much space in +// them because as it traverses the items it makes some assumptions when +// items span to other cells. But those assumptions can become invalid later +// on when other items are fitted into the same rows or columns that the +// spanning item occupies. This method tries to find those situations and +// fixes them. +void wxGridBagSizer::AdjustForOverflow() +{ + int row, col; + + for (row=0; row<(int)m_rowHeights.GetCount(); row++) + { + int rowExtra=INT_MAX; + int rowHeight = m_rowHeights[row]; + for (col=0; col<(int)m_colWidths.GetCount(); col++) + { + wxGBPosition pos(row,col); + wxGBSizerItem* item = FindItemAtPosition(pos); + if ( !item || !item->ShouldAccountFor() ) + continue; + + int endrow, endcol; + item->GetEndPos(endrow, endcol); + + // If the item starts in this position and doesn't span rows, then + // just look at the whole item height + if ( item->GetPos() == pos && endrow == row ) + { + int itemHeight = item->CalcMin().GetHeight(); + rowExtra = wxMin(rowExtra, rowHeight - itemHeight); + continue; + } + + // Otherwise, only look at spanning items if they end on this row + if ( endrow == row ) + { + // first deduct the portions of the item that are on prior rows + int itemHeight = item->CalcMin().GetHeight(); + for (int r=item->GetPos().GetRow(); rShouldAccountFor() ) + continue; + + int endrow, endcol; + item->GetEndPos(endrow, endcol); + + if ( item->GetPos() == pos && endcol == col ) + { + int itemWidth = item->CalcMin().GetWidth(); + colExtra = wxMin(colExtra, colWidth - itemWidth); + continue; + } + + if ( endcol == col ) + { + int itemWidth = item->CalcMin().GetWidth(); + for (int c=item->GetPos().GetCol(); cGetPos(), item->GetSpan(), excludeItem); +} + +bool wxGridBagSizer::CheckForIntersection(const wxGBPosition& pos, const wxGBSpan& span, wxGBSizerItem* excludeItem) +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxGBSizerItem* item = (wxGBSizerItem*)node->GetData(); + node = node->GetNext(); + + if ( excludeItem && item == excludeItem ) + continue; + + if ( item->Intersects(pos, span) ) + return true; + + } + return false; +} + + +// Assumes a 10x10 grid, and returns the first empty cell found. This is +// really stupid but it is only used by the Add methods that match the base +// class virtuals, which should normally not be used anyway... +wxGBPosition wxGridBagSizer::FindEmptyCell() +{ + int row, col; + + for (row=0; row<10; row++) + for (col=0; col<10; col++) + { + wxGBPosition pos(row, col); + if ( !CheckForIntersection(pos, wxDefaultSpan) ) + return pos; + } + return wxGBPosition(-1, -1); +} + + +//--------------------------------------------------------------------------- + +// The Add base class virtuals should not be used with this class, but +// we'll try to make them automatically select a location for the item +// anyway. + +wxSizerItem* wxGridBagSizer::Add( wxWindow *window, int, int flag, int border, wxObject* userData ) +{ + return Add(window, FindEmptyCell(), wxDefaultSpan, flag, border, userData); +} + +wxSizerItem* wxGridBagSizer::Add( wxSizer *sizer, int, int flag, int border, wxObject* userData ) +{ + return Add(sizer, FindEmptyCell(), wxDefaultSpan, flag, border, userData); +} + +wxSizerItem* wxGridBagSizer::Add( int width, int height, int, int flag, int border, wxObject* userData ) +{ + return Add(width, height, FindEmptyCell(), wxDefaultSpan, flag, border, userData); +} + + + +// The Insert nad Prepend base class virtuals that are not appropriate for +// this class and should not be used. Their implementation in this class +// simply fails. + +wxSizerItem* wxGridBagSizer::Add( wxSizerItem * ) +{ + wxFAIL_MSG(wxT("Invalid Add form called.")); + return (wxSizerItem*)NULL; +} + +wxSizerItem* wxGridBagSizer::Prepend( wxWindow *, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + +wxSizerItem* wxGridBagSizer::Prepend( wxSizer *, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + +wxSizerItem* wxGridBagSizer::Prepend( int, int, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + +wxSizerItem* wxGridBagSizer::Prepend( wxSizerItem * ) +{ + wxFAIL_MSG(wxT("Prepend should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + + +wxSizerItem* wxGridBagSizer::Insert( size_t, wxWindow *, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + +wxSizerItem* wxGridBagSizer::Insert( size_t, wxSizer *, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + +wxSizerItem* wxGridBagSizer::Insert( size_t, int, int, int, int, int, wxObject* ) +{ + wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + +wxSizerItem* wxGridBagSizer::Insert( size_t, wxSizerItem * ) +{ + wxFAIL_MSG(wxT("Insert should not be used with wxGridBagSizer.")); + return (wxSizerItem*)NULL; +} + + +//--------------------------------------------------------------------------- +//--------------------------------------------------------------------------- diff --git a/Source/3rd Party/wx/src/common/gdicmn.cpp b/Source/3rd Party/wx/src/common/gdicmn.cpp index 86411416f..232238853 100644 --- a/Source/3rd Party/wx/src/common/gdicmn.cpp +++ b/Source/3rd Party/wx/src/common/gdicmn.cpp @@ -1,871 +1,871 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/gdicmn.cpp -// Purpose: Common GDI classes -// Author: Julian Smart -// Modified by: -// Created: 01/02/97 -// RCS-ID: $Id: gdicmn.cpp 50022 2007-11-17 14:24:18Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/gdicmn.h" -#include "wx/gdiobj.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/pen.h" - #include "wx/brush.h" - #include "wx/palette.h" - #include "wx/icon.h" - #include "wx/cursor.h" - #include "wx/settings.h" - #include "wx/bitmap.h" - #include "wx/colour.h" - #include "wx/font.h" -#endif - - -IMPLEMENT_DYNAMIC_CLASS(wxGDIObject, wxObject) - - -WXDLLIMPEXP_DATA_CORE(wxBrushList*) wxTheBrushList; -WXDLLIMPEXP_DATA_CORE(wxFontList*) wxTheFontList; -WXDLLIMPEXP_DATA_CORE(wxPenList*) wxThePenList; - -WXDLLIMPEXP_DATA_CORE(wxColourDatabase*) wxTheColourDatabase; - -WXDLLIMPEXP_DATA_CORE(wxBitmap) wxNullBitmap; -WXDLLIMPEXP_DATA_CORE(wxBrush) wxNullBrush; -WXDLLIMPEXP_DATA_CORE(wxColour) wxNullColour; -WXDLLIMPEXP_DATA_CORE(wxCursor) wxNullCursor; -WXDLLIMPEXP_DATA_CORE(wxFont) wxNullFont; -WXDLLIMPEXP_DATA_CORE(wxIcon) wxNullIcon; -WXDLLIMPEXP_DATA_CORE(wxPen) wxNullPen; -#if wxUSE_PALETTE -WXDLLIMPEXP_DATA_CORE(wxPalette) wxNullPalette; -#endif - -const wxSize wxDefaultSize(wxDefaultCoord, wxDefaultCoord); -const wxPoint wxDefaultPosition(wxDefaultCoord, wxDefaultCoord); - -#if wxUSE_EXTENDED_RTTI - -// wxPoint - -template<> void wxStringReadValue(const wxString &s , wxPoint &data ) -{ - wxSscanf(s, wxT("%d,%d"), &data.x , &data.y ) ; -} - -template<> void wxStringWriteValue(wxString &s , const wxPoint &data ) -{ - s = wxString::Format(wxT("%d,%d"), data.x , data.y ) ; -} - -wxCUSTOM_TYPE_INFO(wxPoint, wxToStringConverter , wxFromStringConverter) - -template<> void wxStringReadValue(const wxString &s , wxSize &data ) -{ - wxSscanf(s, wxT("%d,%d"), &data.x , &data.y ) ; -} - -template<> void wxStringWriteValue(wxString &s , const wxSize &data ) -{ - s = wxString::Format(wxT("%d,%d"), data.x , data.y ) ; -} - -wxCUSTOM_TYPE_INFO(wxSize, wxToStringConverter , wxFromStringConverter) - -#endif - -wxRect::wxRect(const wxPoint& point1, const wxPoint& point2) -{ - x = point1.x; - y = point1.y; - width = point2.x - point1.x; - height = point2.y - point1.y; - - if (width < 0) - { - width = -width; - x = point2.x; - } - width++; - - if (height < 0) - { - height = -height; - y = point2.y; - } - height++; -} - -bool wxRect::operator==(const wxRect& rect) const -{ - return ((x == rect.x) && - (y == rect.y) && - (width == rect.width) && - (height == rect.height)); -} - -wxRect wxRect::operator+(const wxRect& rect) const -{ - int x1 = wxMin(this->x, rect.x); - int y1 = wxMin(this->y, rect.y); - int y2 = wxMax(y+height, rect.height+rect.y); - int x2 = wxMax(x+width, rect.width+rect.x); - return wxRect(x1, y1, x2-x1, y2-y1); -} - -wxRect& wxRect::Union(const wxRect& rect) -{ - // ignore empty rectangles: union with an empty rectangle shouldn't extend - // this one to (0, 0) - if ( !width || !height ) - { - *this = rect; - } - else if ( rect.width && rect.height ) - { - int x1 = wxMin(x, rect.x); - int y1 = wxMin(y, rect.y); - int y2 = wxMax(y + height, rect.height + rect.y); - int x2 = wxMax(x + width, rect.width + rect.x); - - x = x1; - y = y1; - width = x2 - x1; - height = y2 - y1; - } - //else: we're not empty and rect is empty - - return *this; -} - -wxRect& wxRect::Inflate(wxCoord dx, wxCoord dy) -{ - if (-2*dx>width) - { - // Don't allow deflate to eat more width than we have, - // a well-defined rectangle cannot have negative width. - x+=width/2; - width=0; - } - else - { - // The inflate is valid. - x-=dx; - width+=2*dx; - } - - if (-2*dy>height) - { - // Don't allow deflate to eat more height than we have, - // a well-defined rectangle cannot have negative height. - y+=height/2; - height=0; - } - else - { - // The inflate is valid. - y-=dy; - height+=2*dy; - } - - return *this; -} - -bool wxRect::Contains(int cx, int cy) const -{ - return ( (cx >= x) && (cy >= y) - && ((cy - y) < height) - && ((cx - x) < width) - ); -} - -bool wxRect::Contains(const wxRect& rect) const -{ - return Contains(rect.GetTopLeft()) && Contains(rect.GetBottomRight()); -} - -wxRect& wxRect::Intersect(const wxRect& rect) -{ - int x2 = GetRight(), - y2 = GetBottom(); - - if ( x < rect.x ) - x = rect.x; - if ( y < rect.y ) - y = rect.y; - if ( x2 > rect.GetRight() ) - x2 = rect.GetRight(); - if ( y2 > rect.GetBottom() ) - y2 = rect.GetBottom(); - - width = x2 - x + 1; - height = y2 - y + 1; - - if ( width <= 0 || height <= 0 ) - { - width = - height = 0; - } - - return *this; -} - -bool wxRect::Intersects(const wxRect& rect) const -{ - wxRect r = Intersect(rect); - - // if there is no intersection, both width and height are 0 - return r.width != 0; -} - -// ============================================================================ -// wxColourDatabase -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxColourDatabase ctor/dtor -// ---------------------------------------------------------------------------- - -wxColourDatabase::wxColourDatabase () -{ - // will be created on demand in Initialize() - m_map = NULL; -} - -wxColourDatabase::~wxColourDatabase () -{ - if ( m_map ) - { - WX_CLEAR_HASH_MAP(wxStringToColourHashMap, *m_map); - - delete m_map; - } - -#ifdef __WXPM__ - delete [] m_palTable; -#endif -} - -// Colour database stuff -void wxColourDatabase::Initialize() -{ - if ( m_map ) - { - // already initialized - return; - } - - m_map = new wxStringToColourHashMap; - - static const struct wxColourDesc - { - const wxChar *name; - unsigned char r,g,b; - } - wxColourTable[] = - { - {wxT("AQUAMARINE"),112, 219, 147}, - {wxT("BLACK"),0, 0, 0}, - {wxT("BLUE"), 0, 0, 255}, - {wxT("BLUE VIOLET"), 159, 95, 159}, - {wxT("BROWN"), 165, 42, 42}, - {wxT("CADET BLUE"), 95, 159, 159}, - {wxT("CORAL"), 255, 127, 0}, - {wxT("CORNFLOWER BLUE"), 66, 66, 111}, - {wxT("CYAN"), 0, 255, 255}, - {wxT("DARK GREY"), 47, 47, 47}, // ? - - {wxT("DARK GREEN"), 47, 79, 47}, - {wxT("DARK OLIVE GREEN"), 79, 79, 47}, - {wxT("DARK ORCHID"), 153, 50, 204}, - {wxT("DARK SLATE BLUE"), 107, 35, 142}, - {wxT("DARK SLATE GREY"), 47, 79, 79}, - {wxT("DARK TURQUOISE"), 112, 147, 219}, - {wxT("DIM GREY"), 84, 84, 84}, - {wxT("FIREBRICK"), 142, 35, 35}, - {wxT("FOREST GREEN"), 35, 142, 35}, - {wxT("GOLD"), 204, 127, 50}, - {wxT("GOLDENROD"), 219, 219, 112}, - {wxT("GREY"), 128, 128, 128}, - {wxT("GREEN"), 0, 255, 0}, - {wxT("GREEN YELLOW"), 147, 219, 112}, - {wxT("INDIAN RED"), 79, 47, 47}, - {wxT("KHAKI"), 159, 159, 95}, - {wxT("LIGHT BLUE"), 191, 216, 216}, - {wxT("LIGHT GREY"), 192, 192, 192}, - {wxT("LIGHT STEEL BLUE"), 143, 143, 188}, - {wxT("LIME GREEN"), 50, 204, 50}, - {wxT("LIGHT MAGENTA"), 255, 0, 255}, - {wxT("MAGENTA"), 255, 0, 255}, - {wxT("MAROON"), 142, 35, 107}, - {wxT("MEDIUM AQUAMARINE"), 50, 204, 153}, - {wxT("MEDIUM GREY"), 100, 100, 100}, - {wxT("MEDIUM BLUE"), 50, 50, 204}, - {wxT("MEDIUM FOREST GREEN"), 107, 142, 35}, - {wxT("MEDIUM GOLDENROD"), 234, 234, 173}, - {wxT("MEDIUM ORCHID"), 147, 112, 219}, - {wxT("MEDIUM SEA GREEN"), 66, 111, 66}, - {wxT("MEDIUM SLATE BLUE"), 127, 0, 255}, - {wxT("MEDIUM SPRING GREEN"), 127, 255, 0}, - {wxT("MEDIUM TURQUOISE"), 112, 219, 219}, - {wxT("MEDIUM VIOLET RED"), 219, 112, 147}, - {wxT("MIDNIGHT BLUE"), 47, 47, 79}, - {wxT("NAVY"), 35, 35, 142}, - {wxT("ORANGE"), 204, 50, 50}, - {wxT("ORANGE RED"), 255, 0, 127}, - {wxT("ORCHID"), 219, 112, 219}, - {wxT("PALE GREEN"), 143, 188, 143}, - {wxT("PINK"), 255, 192, 203}, - {wxT("PLUM"), 234, 173, 234}, - {wxT("PURPLE"), 176, 0, 255}, - {wxT("RED"), 255, 0, 0}, - {wxT("SALMON"), 111, 66, 66}, - {wxT("SEA GREEN"), 35, 142, 107}, - {wxT("SIENNA"), 142, 107, 35}, - {wxT("SKY BLUE"), 50, 153, 204}, - {wxT("SLATE BLUE"), 0, 127, 255}, - {wxT("SPRING GREEN"), 0, 255, 127}, - {wxT("STEEL BLUE"), 35, 107, 142}, - {wxT("TAN"), 219, 147, 112}, - {wxT("THISTLE"), 216, 191, 216}, - {wxT("TURQUOISE"), 173, 234, 234}, - {wxT("VIOLET"), 79, 47, 79}, - {wxT("VIOLET RED"), 204, 50, 153}, - {wxT("WHEAT"), 216, 216, 191}, - {wxT("WHITE"), 255, 255, 255}, - {wxT("YELLOW"), 255, 255, 0}, - {wxT("YELLOW GREEN"), 153, 204, 50} - }; - - size_t n; - - for ( n = 0; n < WXSIZEOF(wxColourTable); n++ ) - { - const wxColourDesc& cc = wxColourTable[n]; - (*m_map)[cc.name] = new wxColour(cc.r, cc.g, cc.b); - } - -#ifdef __WXPM__ - m_palTable = new long[n]; - for ( n = 0; n < WXSIZEOF(wxColourTable); n++ ) - { - const wxColourDesc& cc = wxColourTable[n]; - m_palTable[n] = OS2RGB(cc.r,cc.g,cc.b); - } - m_nSize = n; -#endif -} - -// ---------------------------------------------------------------------------- -// wxColourDatabase operations -// ---------------------------------------------------------------------------- - -void wxColourDatabase::AddColour(const wxString& name, const wxColour& colour) -{ - Initialize(); - - // canonicalize the colour names before using them as keys: they should be - // in upper case - wxString colName = name; - colName.MakeUpper(); - - // ... and we also allow both grey/gray - wxString colNameAlt = colName; - if ( !colNameAlt.Replace(_T("GRAY"), _T("GREY")) ) - { - // but in this case it is not necessary so avoid extra search below - colNameAlt.clear(); - } - - wxStringToColourHashMap::iterator it = m_map->find(colName); - if ( it == m_map->end() && !colNameAlt.empty() ) - it = m_map->find(colNameAlt); - if ( it != m_map->end() ) - { - *(it->second) = colour; - } - else // new colour - { - (*m_map)[colName] = new wxColour(colour); - } -} - -wxColour wxColourDatabase::Find(const wxString& colour) const -{ - wxColourDatabase * const self = wxConstCast(this, wxColourDatabase); - self->Initialize(); - - // make the comparaison case insensitive and also match both grey and gray - wxString colName = colour; - colName.MakeUpper(); - wxString colNameAlt = colName; - if ( !colNameAlt.Replace(_T("GRAY"), _T("GREY")) ) - colNameAlt.clear(); - - wxStringToColourHashMap::iterator it = m_map->find(colName); - if ( it == m_map->end() && !colNameAlt.empty() ) - it = m_map->find(colNameAlt); - if ( it != m_map->end() ) - return *(it->second); - - // we did not find any result in existing colours: - // we won't use wxString -> wxColour conversion because the - // wxColour::Set(const wxString &) function which does that conversion - // internally uses this function (wxColourDatabase::Find) and we want - // to avoid infinite recursion ! - return wxNullColour; -} - -wxString wxColourDatabase::FindName(const wxColour& colour) const -{ - wxColourDatabase * const self = wxConstCast(this, wxColourDatabase); - self->Initialize(); - - typedef wxStringToColourHashMap::iterator iterator; - - for ( iterator it = m_map->begin(), en = m_map->end(); it != en; ++it ) - { - if ( *(it->second) == colour ) - return it->first; - } - - return wxEmptyString; -} - -// ---------------------------------------------------------------------------- -// deprecated wxColourDatabase methods -// ---------------------------------------------------------------------------- - -#if WXWIN_COMPATIBILITY_2_6 -wxColour *wxColourDatabase::FindColour(const wxString& name) -{ - // This function is deprecated, use Find() instead. - // Formerly this function sometimes would return a deletable pointer and - // sometimes a non-deletable one (when returning a colour from the database). - // Trying to delete the latter anyway results in problems, so probably - // nobody ever freed the pointers. Currently it always returns a new - // instance, which means there will be memory leaks. - wxLogDebug(wxT("wxColourDataBase::FindColour():") - wxT(" Please use wxColourDataBase::Find() instead")); - - // using a static variable here is not the most elegant solution but unless - // we want to make wxStringToColourHashMap public (i.e. move it to the - // header) so that we could have a member function returning - // wxStringToColourHashMap::iterator, there is really no good way to do it - // otherwise - // - // and knowing that this function is going to disappear in the next release - // anyhow I don't want to waste time on this - - static wxColour s_col; - - s_col = Find(name); - if ( !s_col.Ok() ) - return NULL; - - return new wxColour(s_col); -} -#endif // WXWIN_COMPATIBILITY_2_6 - -// ============================================================================ -// stock objects -// ============================================================================ - -static wxStockGDI gs_wxStockGDI_instance; -wxStockGDI* wxStockGDI::ms_instance = &gs_wxStockGDI_instance; -wxObject* wxStockGDI::ms_stockObject[ITEMCOUNT]; - -wxStockGDI::wxStockGDI() -{ -} - -wxStockGDI::~wxStockGDI() -{ -} - -void wxStockGDI::DeleteAll() -{ - for (unsigned i = 0; i < ITEMCOUNT; i++) - { - delete ms_stockObject[i]; - ms_stockObject[i] = NULL; - } -} - -const wxBrush* wxStockGDI::GetBrush(Item item) -{ - wxBrush* brush = wx_static_cast(wxBrush*, ms_stockObject[item]); - if (brush == NULL) - { - switch (item) - { - case BRUSH_BLACK: - brush = new wxBrush(*GetColour(COLOUR_BLACK), wxSOLID); - break; - case BRUSH_BLUE: - brush = new wxBrush(*GetColour(COLOUR_BLUE), wxSOLID); - break; - case BRUSH_CYAN: - brush = new wxBrush(*GetColour(COLOUR_CYAN), wxSOLID); - break; - case BRUSH_GREEN: - brush = new wxBrush(*GetColour(COLOUR_GREEN), wxSOLID); - break; - case BRUSH_GREY: - brush = new wxBrush(wxColour(wxT("GREY")), wxSOLID); - break; - case BRUSH_LIGHTGREY: - brush = new wxBrush(*GetColour(COLOUR_LIGHTGREY), wxSOLID); - break; - case BRUSH_MEDIUMGREY: - brush = new wxBrush(wxColour(wxT("MEDIUM GREY")), wxSOLID); - break; - case BRUSH_RED: - brush = new wxBrush(*GetColour(COLOUR_RED), wxSOLID); - break; - case BRUSH_TRANSPARENT: - brush = new wxBrush(*GetColour(COLOUR_BLACK), wxTRANSPARENT); - break; - case BRUSH_WHITE: - brush = new wxBrush(*GetColour(COLOUR_WHITE), wxSOLID); - break; - default: - wxFAIL; - } - ms_stockObject[item] = brush; - } - return brush; -} - -const wxColour* wxStockGDI::GetColour(Item item) -{ - wxColour* colour = wx_static_cast(wxColour*, ms_stockObject[item]); - if (colour == NULL) - { - switch (item) - { - case COLOUR_BLACK: - colour = new wxColour(0, 0, 0); - break; - case COLOUR_BLUE: - colour = new wxColour(0, 0, 255); - break; - case COLOUR_CYAN: - colour = new wxColour(wxT("CYAN")); - break; - case COLOUR_GREEN: - colour = new wxColour(0, 255, 0); - break; - case COLOUR_LIGHTGREY: - colour = new wxColour(wxT("LIGHT GREY")); - break; - case COLOUR_RED: - colour = new wxColour(255, 0, 0); - break; - case COLOUR_WHITE: - colour = new wxColour(255, 255, 255); - break; - default: - wxFAIL; - } - ms_stockObject[item] = colour; - } - return colour; -} - -const wxCursor* wxStockGDI::GetCursor(Item item) -{ - wxCursor* cursor = wx_static_cast(wxCursor*, ms_stockObject[item]); - if (cursor == NULL) - { - switch (item) - { - case CURSOR_CROSS: - cursor = new wxCursor(wxCURSOR_CROSS); - break; - case CURSOR_HOURGLASS: - cursor = new wxCursor(wxCURSOR_WAIT); - break; - case CURSOR_STANDARD: - cursor = new wxCursor(wxCURSOR_ARROW); - break; - default: - wxFAIL; - } - ms_stockObject[item] = cursor; - } - return cursor; -} - -const wxFont* wxStockGDI::GetFont(Item item) -{ - wxFont* font = wx_static_cast(wxFont*, ms_stockObject[item]); - if (font == NULL) - { - switch (item) - { - case FONT_ITALIC: - font = new wxFont(GetFont(FONT_NORMAL)->GetPointSize(), wxROMAN, wxITALIC, wxNORMAL); - break; - case FONT_NORMAL: - font = new wxFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - break; - case FONT_SMALL: - font = new wxFont(GetFont(FONT_NORMAL)->GetPointSize() - 2, wxSWISS, wxNORMAL, wxNORMAL); - break; - case FONT_SWISS: - font = new wxFont(GetFont(FONT_NORMAL)->GetPointSize(), wxSWISS, wxNORMAL, wxNORMAL); - break; - default: - wxFAIL; - } - ms_stockObject[item] = font; - } - return font; -} - -const wxPen* wxStockGDI::GetPen(Item item) -{ - wxPen* pen = wx_static_cast(wxPen*, ms_stockObject[item]); - if (pen == NULL) - { - switch (item) - { - case PEN_BLACK: - pen = new wxPen(*GetColour(COLOUR_BLACK), 1, wxSOLID); - break; - case PEN_BLACKDASHED: - pen = new wxPen(*GetColour(COLOUR_BLACK), 1, wxSHORT_DASH); - break; - case PEN_CYAN: - pen = new wxPen(*GetColour(COLOUR_CYAN), 1, wxSOLID); - break; - case PEN_GREEN: - pen = new wxPen(*GetColour(COLOUR_GREEN), 1, wxSOLID); - break; - case PEN_GREY: - pen = new wxPen(wxColour(wxT("GREY")), 1, wxSOLID); - break; - case PEN_LIGHTGREY: - pen = new wxPen(*GetColour(COLOUR_LIGHTGREY), 1, wxSOLID); - break; - case PEN_MEDIUMGREY: - pen = new wxPen(wxColour(wxT("MEDIUM GREY")), 1, wxSOLID); - break; - case PEN_RED: - pen = new wxPen(*GetColour(COLOUR_RED), 1, wxSOLID); - break; - case PEN_TRANSPARENT: - pen = new wxPen(*GetColour(COLOUR_BLACK), 1, wxTRANSPARENT); - break; - case PEN_WHITE: - pen = new wxPen(*GetColour(COLOUR_WHITE), 1, wxSOLID); - break; - default: - wxFAIL; - } - ms_stockObject[item] = pen; - } - return pen; -} - -void wxInitializeStockLists() -{ - wxTheColourDatabase = new wxColourDatabase; - - wxTheBrushList = new wxBrushList; - wxThePenList = new wxPenList; - wxTheFontList = new wxFontList; -} - -void wxDeleteStockLists() -{ - wxDELETE(wxTheBrushList); - wxDELETE(wxThePenList); - wxDELETE(wxTheFontList); -} - -// ============================================================================ -// wxTheXXXList stuff (semi-obsolete) -// ============================================================================ - -wxGDIObjListBase::wxGDIObjListBase() -{ -} - -wxGDIObjListBase::~wxGDIObjListBase() -{ - for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext()) - { - delete wx_static_cast(wxObject*, node->GetData()); - } -} - -wxPen *wxPenList::FindOrCreatePen (const wxColour& colour, int width, int style) -{ - for ( wxList::compatibility_iterator node = list.GetFirst(); - node; - node = node->GetNext() ) - { - wxPen * const pen = (wxPen *) node->GetData(); - if ( pen->GetWidth () == width && - pen->GetStyle () == style && - pen->GetColour() == colour ) - return pen; - } - - wxPen* pen = NULL; - wxPen penTmp(colour, width, style); - if (penTmp.Ok()) - { - pen = new wxPen(penTmp); - list.Append(pen); - } - - return pen; -} - -wxBrush *wxBrushList::FindOrCreateBrush (const wxColour& colour, int style) -{ - for ( wxList::compatibility_iterator node = list.GetFirst(); - node; - node = node->GetNext() ) - { - wxBrush * const brush = (wxBrush *) node->GetData (); - if ( brush->GetStyle () == style && brush->GetColour() == colour ) - return brush; - } - - wxBrush* brush = NULL; - wxBrush brushTmp(colour, style); - if (brushTmp.Ok()) - { - brush = new wxBrush(brushTmp); - list.Append(brush); - } - - return brush; -} - -wxFont *wxFontList::FindOrCreateFont(int pointSize, - int family, - int style, - int weight, - bool underline, - const wxString& facename, - wxFontEncoding encoding) -{ - wxFont *font; - wxList::compatibility_iterator node; - for (node = list.GetFirst(); node; node = node->GetNext()) - { - font = (wxFont *)node->GetData(); - if ( - font->GetPointSize () == pointSize && - font->GetStyle () == style && - font->GetWeight () == weight && - font->GetUnderlined () == underline ) - { - int fontFamily = font->GetFamily(); - -#if defined(__WXGTK__) - // under GTK the default family is wxSWISS, so looking for a font - // with wxDEFAULT family should return a wxSWISS one instead of - // creating a new one - bool same = (fontFamily == family) || - (fontFamily == wxSWISS && family == wxDEFAULT); -#else // !GTK - // VZ: but why elsewhere do we require an exact match? mystery... - bool same = fontFamily == family; -#endif // GTK/!GTK - - // empty facename matches anything at all: this is bad because - // depending on which fonts are already created, we might get back - // a different font if we create it with empty facename, but it is - // still better than never matching anything in the cache at all - // in this case - if ( same && !facename.empty() ) - { - const wxString& fontFace = font->GetFaceName(); - - // empty facename matches everything - same = !fontFace || fontFace == facename; - } - - if ( same && (encoding != wxFONTENCODING_DEFAULT) ) - { - // have to match the encoding too - same = font->GetEncoding() == encoding; - } - - if ( same ) - { - return font; - } - } - } - - // font not found, create the new one - font = NULL; - wxFont fontTmp(pointSize, family, style, weight, underline, facename, encoding); - if (fontTmp.Ok()) - { - font = new wxFont(fontTmp); - list.Append(font); - } - - return font; -} - -#if WXWIN_COMPATIBILITY_2_6 -void wxBrushList::AddBrush(wxBrush*) { } -void wxBrushList::RemoveBrush(wxBrush*) { } -void wxFontList::AddFont(wxFont*) { } -void wxFontList::RemoveFont(wxFont*) { } -void wxPenList::AddPen(wxPen*) { } -void wxPenList::RemovePen(wxPen*) { } -#endif - -wxSize wxGetDisplaySize() -{ - int x, y; - wxDisplaySize(& x, & y); - return wxSize(x, y); -} - -wxRect wxGetClientDisplayRect() -{ - int x, y, width, height; - wxClientDisplayRect(&x, &y, &width, &height); // call plat-specific version - return wxRect(x, y, width, height); -} - -wxSize wxGetDisplaySizeMM() -{ - int x, y; - wxDisplaySizeMM(& x, & y); - return wxSize(x, y); -} - -wxResourceCache::~wxResourceCache () -{ - wxList::compatibility_iterator node = GetFirst (); - while (node) { - wxObject *item = (wxObject *)node->GetData(); - delete item; - - node = node->GetNext (); - } -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/gdicmn.cpp +// Purpose: Common GDI classes +// Author: Julian Smart +// Modified by: +// Created: 01/02/97 +// RCS-ID: $Id: gdicmn.cpp 50022 2007-11-17 14:24:18Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/gdicmn.h" +#include "wx/gdiobj.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/pen.h" + #include "wx/brush.h" + #include "wx/palette.h" + #include "wx/icon.h" + #include "wx/cursor.h" + #include "wx/settings.h" + #include "wx/bitmap.h" + #include "wx/colour.h" + #include "wx/font.h" +#endif + + +IMPLEMENT_DYNAMIC_CLASS(wxGDIObject, wxObject) + + +WXDLLIMPEXP_DATA_CORE(wxBrushList*) wxTheBrushList; +WXDLLIMPEXP_DATA_CORE(wxFontList*) wxTheFontList; +WXDLLIMPEXP_DATA_CORE(wxPenList*) wxThePenList; + +WXDLLIMPEXP_DATA_CORE(wxColourDatabase*) wxTheColourDatabase; + +WXDLLIMPEXP_DATA_CORE(wxBitmap) wxNullBitmap; +WXDLLIMPEXP_DATA_CORE(wxBrush) wxNullBrush; +WXDLLIMPEXP_DATA_CORE(wxColour) wxNullColour; +WXDLLIMPEXP_DATA_CORE(wxCursor) wxNullCursor; +WXDLLIMPEXP_DATA_CORE(wxFont) wxNullFont; +WXDLLIMPEXP_DATA_CORE(wxIcon) wxNullIcon; +WXDLLIMPEXP_DATA_CORE(wxPen) wxNullPen; +#if wxUSE_PALETTE +WXDLLIMPEXP_DATA_CORE(wxPalette) wxNullPalette; +#endif + +const wxSize wxDefaultSize(wxDefaultCoord, wxDefaultCoord); +const wxPoint wxDefaultPosition(wxDefaultCoord, wxDefaultCoord); + +#if wxUSE_EXTENDED_RTTI + +// wxPoint + +template<> void wxStringReadValue(const wxString &s , wxPoint &data ) +{ + wxSscanf(s, wxT("%d,%d"), &data.x , &data.y ) ; +} + +template<> void wxStringWriteValue(wxString &s , const wxPoint &data ) +{ + s = wxString::Format(wxT("%d,%d"), data.x , data.y ) ; +} + +wxCUSTOM_TYPE_INFO(wxPoint, wxToStringConverter , wxFromStringConverter) + +template<> void wxStringReadValue(const wxString &s , wxSize &data ) +{ + wxSscanf(s, wxT("%d,%d"), &data.x , &data.y ) ; +} + +template<> void wxStringWriteValue(wxString &s , const wxSize &data ) +{ + s = wxString::Format(wxT("%d,%d"), data.x , data.y ) ; +} + +wxCUSTOM_TYPE_INFO(wxSize, wxToStringConverter , wxFromStringConverter) + +#endif + +wxRect::wxRect(const wxPoint& point1, const wxPoint& point2) +{ + x = point1.x; + y = point1.y; + width = point2.x - point1.x; + height = point2.y - point1.y; + + if (width < 0) + { + width = -width; + x = point2.x; + } + width++; + + if (height < 0) + { + height = -height; + y = point2.y; + } + height++; +} + +bool wxRect::operator==(const wxRect& rect) const +{ + return ((x == rect.x) && + (y == rect.y) && + (width == rect.width) && + (height == rect.height)); +} + +wxRect wxRect::operator+(const wxRect& rect) const +{ + int x1 = wxMin(this->x, rect.x); + int y1 = wxMin(this->y, rect.y); + int y2 = wxMax(y+height, rect.height+rect.y); + int x2 = wxMax(x+width, rect.width+rect.x); + return wxRect(x1, y1, x2-x1, y2-y1); +} + +wxRect& wxRect::Union(const wxRect& rect) +{ + // ignore empty rectangles: union with an empty rectangle shouldn't extend + // this one to (0, 0) + if ( !width || !height ) + { + *this = rect; + } + else if ( rect.width && rect.height ) + { + int x1 = wxMin(x, rect.x); + int y1 = wxMin(y, rect.y); + int y2 = wxMax(y + height, rect.height + rect.y); + int x2 = wxMax(x + width, rect.width + rect.x); + + x = x1; + y = y1; + width = x2 - x1; + height = y2 - y1; + } + //else: we're not empty and rect is empty + + return *this; +} + +wxRect& wxRect::Inflate(wxCoord dx, wxCoord dy) +{ + if (-2*dx>width) + { + // Don't allow deflate to eat more width than we have, + // a well-defined rectangle cannot have negative width. + x+=width/2; + width=0; + } + else + { + // The inflate is valid. + x-=dx; + width+=2*dx; + } + + if (-2*dy>height) + { + // Don't allow deflate to eat more height than we have, + // a well-defined rectangle cannot have negative height. + y+=height/2; + height=0; + } + else + { + // The inflate is valid. + y-=dy; + height+=2*dy; + } + + return *this; +} + +bool wxRect::Contains(int cx, int cy) const +{ + return ( (cx >= x) && (cy >= y) + && ((cy - y) < height) + && ((cx - x) < width) + ); +} + +bool wxRect::Contains(const wxRect& rect) const +{ + return Contains(rect.GetTopLeft()) && Contains(rect.GetBottomRight()); +} + +wxRect& wxRect::Intersect(const wxRect& rect) +{ + int x2 = GetRight(), + y2 = GetBottom(); + + if ( x < rect.x ) + x = rect.x; + if ( y < rect.y ) + y = rect.y; + if ( x2 > rect.GetRight() ) + x2 = rect.GetRight(); + if ( y2 > rect.GetBottom() ) + y2 = rect.GetBottom(); + + width = x2 - x + 1; + height = y2 - y + 1; + + if ( width <= 0 || height <= 0 ) + { + width = + height = 0; + } + + return *this; +} + +bool wxRect::Intersects(const wxRect& rect) const +{ + wxRect r = Intersect(rect); + + // if there is no intersection, both width and height are 0 + return r.width != 0; +} + +// ============================================================================ +// wxColourDatabase +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxColourDatabase ctor/dtor +// ---------------------------------------------------------------------------- + +wxColourDatabase::wxColourDatabase () +{ + // will be created on demand in Initialize() + m_map = NULL; +} + +wxColourDatabase::~wxColourDatabase () +{ + if ( m_map ) + { + WX_CLEAR_HASH_MAP(wxStringToColourHashMap, *m_map); + + delete m_map; + } + +#ifdef __WXPM__ + delete [] m_palTable; +#endif +} + +// Colour database stuff +void wxColourDatabase::Initialize() +{ + if ( m_map ) + { + // already initialized + return; + } + + m_map = new wxStringToColourHashMap; + + static const struct wxColourDesc + { + const wxChar *name; + unsigned char r,g,b; + } + wxColourTable[] = + { + {wxT("AQUAMARINE"),112, 219, 147}, + {wxT("BLACK"),0, 0, 0}, + {wxT("BLUE"), 0, 0, 255}, + {wxT("BLUE VIOLET"), 159, 95, 159}, + {wxT("BROWN"), 165, 42, 42}, + {wxT("CADET BLUE"), 95, 159, 159}, + {wxT("CORAL"), 255, 127, 0}, + {wxT("CORNFLOWER BLUE"), 66, 66, 111}, + {wxT("CYAN"), 0, 255, 255}, + {wxT("DARK GREY"), 47, 47, 47}, // ? + + {wxT("DARK GREEN"), 47, 79, 47}, + {wxT("DARK OLIVE GREEN"), 79, 79, 47}, + {wxT("DARK ORCHID"), 153, 50, 204}, + {wxT("DARK SLATE BLUE"), 107, 35, 142}, + {wxT("DARK SLATE GREY"), 47, 79, 79}, + {wxT("DARK TURQUOISE"), 112, 147, 219}, + {wxT("DIM GREY"), 84, 84, 84}, + {wxT("FIREBRICK"), 142, 35, 35}, + {wxT("FOREST GREEN"), 35, 142, 35}, + {wxT("GOLD"), 204, 127, 50}, + {wxT("GOLDENROD"), 219, 219, 112}, + {wxT("GREY"), 128, 128, 128}, + {wxT("GREEN"), 0, 255, 0}, + {wxT("GREEN YELLOW"), 147, 219, 112}, + {wxT("INDIAN RED"), 79, 47, 47}, + {wxT("KHAKI"), 159, 159, 95}, + {wxT("LIGHT BLUE"), 191, 216, 216}, + {wxT("LIGHT GREY"), 192, 192, 192}, + {wxT("LIGHT STEEL BLUE"), 143, 143, 188}, + {wxT("LIME GREEN"), 50, 204, 50}, + {wxT("LIGHT MAGENTA"), 255, 0, 255}, + {wxT("MAGENTA"), 255, 0, 255}, + {wxT("MAROON"), 142, 35, 107}, + {wxT("MEDIUM AQUAMARINE"), 50, 204, 153}, + {wxT("MEDIUM GREY"), 100, 100, 100}, + {wxT("MEDIUM BLUE"), 50, 50, 204}, + {wxT("MEDIUM FOREST GREEN"), 107, 142, 35}, + {wxT("MEDIUM GOLDENROD"), 234, 234, 173}, + {wxT("MEDIUM ORCHID"), 147, 112, 219}, + {wxT("MEDIUM SEA GREEN"), 66, 111, 66}, + {wxT("MEDIUM SLATE BLUE"), 127, 0, 255}, + {wxT("MEDIUM SPRING GREEN"), 127, 255, 0}, + {wxT("MEDIUM TURQUOISE"), 112, 219, 219}, + {wxT("MEDIUM VIOLET RED"), 219, 112, 147}, + {wxT("MIDNIGHT BLUE"), 47, 47, 79}, + {wxT("NAVY"), 35, 35, 142}, + {wxT("ORANGE"), 204, 50, 50}, + {wxT("ORANGE RED"), 255, 0, 127}, + {wxT("ORCHID"), 219, 112, 219}, + {wxT("PALE GREEN"), 143, 188, 143}, + {wxT("PINK"), 255, 192, 203}, + {wxT("PLUM"), 234, 173, 234}, + {wxT("PURPLE"), 176, 0, 255}, + {wxT("RED"), 255, 0, 0}, + {wxT("SALMON"), 111, 66, 66}, + {wxT("SEA GREEN"), 35, 142, 107}, + {wxT("SIENNA"), 142, 107, 35}, + {wxT("SKY BLUE"), 50, 153, 204}, + {wxT("SLATE BLUE"), 0, 127, 255}, + {wxT("SPRING GREEN"), 0, 255, 127}, + {wxT("STEEL BLUE"), 35, 107, 142}, + {wxT("TAN"), 219, 147, 112}, + {wxT("THISTLE"), 216, 191, 216}, + {wxT("TURQUOISE"), 173, 234, 234}, + {wxT("VIOLET"), 79, 47, 79}, + {wxT("VIOLET RED"), 204, 50, 153}, + {wxT("WHEAT"), 216, 216, 191}, + {wxT("WHITE"), 255, 255, 255}, + {wxT("YELLOW"), 255, 255, 0}, + {wxT("YELLOW GREEN"), 153, 204, 50} + }; + + size_t n; + + for ( n = 0; n < WXSIZEOF(wxColourTable); n++ ) + { + const wxColourDesc& cc = wxColourTable[n]; + (*m_map)[cc.name] = new wxColour(cc.r, cc.g, cc.b); + } + +#ifdef __WXPM__ + m_palTable = new long[n]; + for ( n = 0; n < WXSIZEOF(wxColourTable); n++ ) + { + const wxColourDesc& cc = wxColourTable[n]; + m_palTable[n] = OS2RGB(cc.r,cc.g,cc.b); + } + m_nSize = n; +#endif +} + +// ---------------------------------------------------------------------------- +// wxColourDatabase operations +// ---------------------------------------------------------------------------- + +void wxColourDatabase::AddColour(const wxString& name, const wxColour& colour) +{ + Initialize(); + + // canonicalize the colour names before using them as keys: they should be + // in upper case + wxString colName = name; + colName.MakeUpper(); + + // ... and we also allow both grey/gray + wxString colNameAlt = colName; + if ( !colNameAlt.Replace(_T("GRAY"), _T("GREY")) ) + { + // but in this case it is not necessary so avoid extra search below + colNameAlt.clear(); + } + + wxStringToColourHashMap::iterator it = m_map->find(colName); + if ( it == m_map->end() && !colNameAlt.empty() ) + it = m_map->find(colNameAlt); + if ( it != m_map->end() ) + { + *(it->second) = colour; + } + else // new colour + { + (*m_map)[colName] = new wxColour(colour); + } +} + +wxColour wxColourDatabase::Find(const wxString& colour) const +{ + wxColourDatabase * const self = wxConstCast(this, wxColourDatabase); + self->Initialize(); + + // make the comparaison case insensitive and also match both grey and gray + wxString colName = colour; + colName.MakeUpper(); + wxString colNameAlt = colName; + if ( !colNameAlt.Replace(_T("GRAY"), _T("GREY")) ) + colNameAlt.clear(); + + wxStringToColourHashMap::iterator it = m_map->find(colName); + if ( it == m_map->end() && !colNameAlt.empty() ) + it = m_map->find(colNameAlt); + if ( it != m_map->end() ) + return *(it->second); + + // we did not find any result in existing colours: + // we won't use wxString -> wxColour conversion because the + // wxColour::Set(const wxString &) function which does that conversion + // internally uses this function (wxColourDatabase::Find) and we want + // to avoid infinite recursion ! + return wxNullColour; +} + +wxString wxColourDatabase::FindName(const wxColour& colour) const +{ + wxColourDatabase * const self = wxConstCast(this, wxColourDatabase); + self->Initialize(); + + typedef wxStringToColourHashMap::iterator iterator; + + for ( iterator it = m_map->begin(), en = m_map->end(); it != en; ++it ) + { + if ( *(it->second) == colour ) + return it->first; + } + + return wxEmptyString; +} + +// ---------------------------------------------------------------------------- +// deprecated wxColourDatabase methods +// ---------------------------------------------------------------------------- + +#if WXWIN_COMPATIBILITY_2_6 +wxColour *wxColourDatabase::FindColour(const wxString& name) +{ + // This function is deprecated, use Find() instead. + // Formerly this function sometimes would return a deletable pointer and + // sometimes a non-deletable one (when returning a colour from the database). + // Trying to delete the latter anyway results in problems, so probably + // nobody ever freed the pointers. Currently it always returns a new + // instance, which means there will be memory leaks. + wxLogDebug(wxT("wxColourDataBase::FindColour():") + wxT(" Please use wxColourDataBase::Find() instead")); + + // using a static variable here is not the most elegant solution but unless + // we want to make wxStringToColourHashMap public (i.e. move it to the + // header) so that we could have a member function returning + // wxStringToColourHashMap::iterator, there is really no good way to do it + // otherwise + // + // and knowing that this function is going to disappear in the next release + // anyhow I don't want to waste time on this + + static wxColour s_col; + + s_col = Find(name); + if ( !s_col.Ok() ) + return NULL; + + return new wxColour(s_col); +} +#endif // WXWIN_COMPATIBILITY_2_6 + +// ============================================================================ +// stock objects +// ============================================================================ + +static wxStockGDI gs_wxStockGDI_instance; +wxStockGDI* wxStockGDI::ms_instance = &gs_wxStockGDI_instance; +wxObject* wxStockGDI::ms_stockObject[ITEMCOUNT]; + +wxStockGDI::wxStockGDI() +{ +} + +wxStockGDI::~wxStockGDI() +{ +} + +void wxStockGDI::DeleteAll() +{ + for (unsigned i = 0; i < ITEMCOUNT; i++) + { + delete ms_stockObject[i]; + ms_stockObject[i] = NULL; + } +} + +const wxBrush* wxStockGDI::GetBrush(Item item) +{ + wxBrush* brush = wx_static_cast(wxBrush*, ms_stockObject[item]); + if (brush == NULL) + { + switch (item) + { + case BRUSH_BLACK: + brush = new wxBrush(*GetColour(COLOUR_BLACK), wxSOLID); + break; + case BRUSH_BLUE: + brush = new wxBrush(*GetColour(COLOUR_BLUE), wxSOLID); + break; + case BRUSH_CYAN: + brush = new wxBrush(*GetColour(COLOUR_CYAN), wxSOLID); + break; + case BRUSH_GREEN: + brush = new wxBrush(*GetColour(COLOUR_GREEN), wxSOLID); + break; + case BRUSH_GREY: + brush = new wxBrush(wxColour(wxT("GREY")), wxSOLID); + break; + case BRUSH_LIGHTGREY: + brush = new wxBrush(*GetColour(COLOUR_LIGHTGREY), wxSOLID); + break; + case BRUSH_MEDIUMGREY: + brush = new wxBrush(wxColour(wxT("MEDIUM GREY")), wxSOLID); + break; + case BRUSH_RED: + brush = new wxBrush(*GetColour(COLOUR_RED), wxSOLID); + break; + case BRUSH_TRANSPARENT: + brush = new wxBrush(*GetColour(COLOUR_BLACK), wxTRANSPARENT); + break; + case BRUSH_WHITE: + brush = new wxBrush(*GetColour(COLOUR_WHITE), wxSOLID); + break; + default: + wxFAIL; + } + ms_stockObject[item] = brush; + } + return brush; +} + +const wxColour* wxStockGDI::GetColour(Item item) +{ + wxColour* colour = wx_static_cast(wxColour*, ms_stockObject[item]); + if (colour == NULL) + { + switch (item) + { + case COLOUR_BLACK: + colour = new wxColour(0, 0, 0); + break; + case COLOUR_BLUE: + colour = new wxColour(0, 0, 255); + break; + case COLOUR_CYAN: + colour = new wxColour(wxT("CYAN")); + break; + case COLOUR_GREEN: + colour = new wxColour(0, 255, 0); + break; + case COLOUR_LIGHTGREY: + colour = new wxColour(wxT("LIGHT GREY")); + break; + case COLOUR_RED: + colour = new wxColour(255, 0, 0); + break; + case COLOUR_WHITE: + colour = new wxColour(255, 255, 255); + break; + default: + wxFAIL; + } + ms_stockObject[item] = colour; + } + return colour; +} + +const wxCursor* wxStockGDI::GetCursor(Item item) +{ + wxCursor* cursor = wx_static_cast(wxCursor*, ms_stockObject[item]); + if (cursor == NULL) + { + switch (item) + { + case CURSOR_CROSS: + cursor = new wxCursor(wxCURSOR_CROSS); + break; + case CURSOR_HOURGLASS: + cursor = new wxCursor(wxCURSOR_WAIT); + break; + case CURSOR_STANDARD: + cursor = new wxCursor(wxCURSOR_ARROW); + break; + default: + wxFAIL; + } + ms_stockObject[item] = cursor; + } + return cursor; +} + +const wxFont* wxStockGDI::GetFont(Item item) +{ + wxFont* font = wx_static_cast(wxFont*, ms_stockObject[item]); + if (font == NULL) + { + switch (item) + { + case FONT_ITALIC: + font = new wxFont(GetFont(FONT_NORMAL)->GetPointSize(), wxROMAN, wxITALIC, wxNORMAL); + break; + case FONT_NORMAL: + font = new wxFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + break; + case FONT_SMALL: + font = new wxFont(GetFont(FONT_NORMAL)->GetPointSize() - 2, wxSWISS, wxNORMAL, wxNORMAL); + break; + case FONT_SWISS: + font = new wxFont(GetFont(FONT_NORMAL)->GetPointSize(), wxSWISS, wxNORMAL, wxNORMAL); + break; + default: + wxFAIL; + } + ms_stockObject[item] = font; + } + return font; +} + +const wxPen* wxStockGDI::GetPen(Item item) +{ + wxPen* pen = wx_static_cast(wxPen*, ms_stockObject[item]); + if (pen == NULL) + { + switch (item) + { + case PEN_BLACK: + pen = new wxPen(*GetColour(COLOUR_BLACK), 1, wxSOLID); + break; + case PEN_BLACKDASHED: + pen = new wxPen(*GetColour(COLOUR_BLACK), 1, wxSHORT_DASH); + break; + case PEN_CYAN: + pen = new wxPen(*GetColour(COLOUR_CYAN), 1, wxSOLID); + break; + case PEN_GREEN: + pen = new wxPen(*GetColour(COLOUR_GREEN), 1, wxSOLID); + break; + case PEN_GREY: + pen = new wxPen(wxColour(wxT("GREY")), 1, wxSOLID); + break; + case PEN_LIGHTGREY: + pen = new wxPen(*GetColour(COLOUR_LIGHTGREY), 1, wxSOLID); + break; + case PEN_MEDIUMGREY: + pen = new wxPen(wxColour(wxT("MEDIUM GREY")), 1, wxSOLID); + break; + case PEN_RED: + pen = new wxPen(*GetColour(COLOUR_RED), 1, wxSOLID); + break; + case PEN_TRANSPARENT: + pen = new wxPen(*GetColour(COLOUR_BLACK), 1, wxTRANSPARENT); + break; + case PEN_WHITE: + pen = new wxPen(*GetColour(COLOUR_WHITE), 1, wxSOLID); + break; + default: + wxFAIL; + } + ms_stockObject[item] = pen; + } + return pen; +} + +void wxInitializeStockLists() +{ + wxTheColourDatabase = new wxColourDatabase; + + wxTheBrushList = new wxBrushList; + wxThePenList = new wxPenList; + wxTheFontList = new wxFontList; +} + +void wxDeleteStockLists() +{ + wxDELETE(wxTheBrushList); + wxDELETE(wxThePenList); + wxDELETE(wxTheFontList); +} + +// ============================================================================ +// wxTheXXXList stuff (semi-obsolete) +// ============================================================================ + +wxGDIObjListBase::wxGDIObjListBase() +{ +} + +wxGDIObjListBase::~wxGDIObjListBase() +{ + for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext()) + { + delete wx_static_cast(wxObject*, node->GetData()); + } +} + +wxPen *wxPenList::FindOrCreatePen (const wxColour& colour, int width, int style) +{ + for ( wxList::compatibility_iterator node = list.GetFirst(); + node; + node = node->GetNext() ) + { + wxPen * const pen = (wxPen *) node->GetData(); + if ( pen->GetWidth () == width && + pen->GetStyle () == style && + pen->GetColour() == colour ) + return pen; + } + + wxPen* pen = NULL; + wxPen penTmp(colour, width, style); + if (penTmp.Ok()) + { + pen = new wxPen(penTmp); + list.Append(pen); + } + + return pen; +} + +wxBrush *wxBrushList::FindOrCreateBrush (const wxColour& colour, int style) +{ + for ( wxList::compatibility_iterator node = list.GetFirst(); + node; + node = node->GetNext() ) + { + wxBrush * const brush = (wxBrush *) node->GetData (); + if ( brush->GetStyle () == style && brush->GetColour() == colour ) + return brush; + } + + wxBrush* brush = NULL; + wxBrush brushTmp(colour, style); + if (brushTmp.Ok()) + { + brush = new wxBrush(brushTmp); + list.Append(brush); + } + + return brush; +} + +wxFont *wxFontList::FindOrCreateFont(int pointSize, + int family, + int style, + int weight, + bool underline, + const wxString& facename, + wxFontEncoding encoding) +{ + wxFont *font; + wxList::compatibility_iterator node; + for (node = list.GetFirst(); node; node = node->GetNext()) + { + font = (wxFont *)node->GetData(); + if ( + font->GetPointSize () == pointSize && + font->GetStyle () == style && + font->GetWeight () == weight && + font->GetUnderlined () == underline ) + { + int fontFamily = font->GetFamily(); + +#if defined(__WXGTK__) + // under GTK the default family is wxSWISS, so looking for a font + // with wxDEFAULT family should return a wxSWISS one instead of + // creating a new one + bool same = (fontFamily == family) || + (fontFamily == wxSWISS && family == wxDEFAULT); +#else // !GTK + // VZ: but why elsewhere do we require an exact match? mystery... + bool same = fontFamily == family; +#endif // GTK/!GTK + + // empty facename matches anything at all: this is bad because + // depending on which fonts are already created, we might get back + // a different font if we create it with empty facename, but it is + // still better than never matching anything in the cache at all + // in this case + if ( same && !facename.empty() ) + { + const wxString& fontFace = font->GetFaceName(); + + // empty facename matches everything + same = !fontFace || fontFace == facename; + } + + if ( same && (encoding != wxFONTENCODING_DEFAULT) ) + { + // have to match the encoding too + same = font->GetEncoding() == encoding; + } + + if ( same ) + { + return font; + } + } + } + + // font not found, create the new one + font = NULL; + wxFont fontTmp(pointSize, family, style, weight, underline, facename, encoding); + if (fontTmp.Ok()) + { + font = new wxFont(fontTmp); + list.Append(font); + } + + return font; +} + +#if WXWIN_COMPATIBILITY_2_6 +void wxBrushList::AddBrush(wxBrush*) { } +void wxBrushList::RemoveBrush(wxBrush*) { } +void wxFontList::AddFont(wxFont*) { } +void wxFontList::RemoveFont(wxFont*) { } +void wxPenList::AddPen(wxPen*) { } +void wxPenList::RemovePen(wxPen*) { } +#endif + +wxSize wxGetDisplaySize() +{ + int x, y; + wxDisplaySize(& x, & y); + return wxSize(x, y); +} + +wxRect wxGetClientDisplayRect() +{ + int x, y, width, height; + wxClientDisplayRect(&x, &y, &width, &height); // call plat-specific version + return wxRect(x, y, width, height); +} + +wxSize wxGetDisplaySizeMM() +{ + int x, y; + wxDisplaySizeMM(& x, & y); + return wxSize(x, y); +} + +wxResourceCache::~wxResourceCache () +{ + wxList::compatibility_iterator node = GetFirst (); + while (node) { + wxObject *item = (wxObject *)node->GetData(); + delete item; + + node = node->GetNext (); + } +} diff --git a/Source/3rd Party/wx/src/common/geometry.cpp b/Source/3rd Party/wx/src/common/geometry.cpp index 66726d13e..362b1aee5 100644 --- a/Source/3rd Party/wx/src/common/geometry.cpp +++ b/Source/3rd Party/wx/src/common/geometry.cpp @@ -1,364 +1,364 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/geometry.cpp -// Purpose: Common Geometry Classes -// Author: Stefan Csomor -// Modified by: -// Created: 08/05/99 -// RCS-ID: -// Copyright: (c) 1999 Stefan Csomor -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_GEOMETRY - -#include "wx/geometry.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" -#endif - -#include - -#include "wx/datstrm.h" - -// -// wxPoint2D -// - -// -// wxRect2D -// - -// wxDouble version - -// for the following calculations always remember -// that the right and bottom edges are not part of a rect - -bool wxRect2DDouble::Intersects( const wxRect2DDouble &rect ) const -{ - wxDouble left,right,bottom,top; - left = wxMax ( m_x , rect.m_x ); - right = wxMin ( m_x+m_width, rect.m_x + rect.m_width ); - top = wxMax ( m_y , rect.m_y ); - bottom = wxMin ( m_y+m_height, rect.m_y + rect.m_height ); - - if ( left < right && top < bottom ) - { - return true; - } - return false; -} - -void wxRect2DDouble::Intersect( const wxRect2DDouble &src1 , const wxRect2DDouble &src2 , wxRect2DDouble *dest ) -{ - wxDouble left,right,bottom,top; - left = wxMax ( src1.m_x , src2.m_x ); - right = wxMin ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); - top = wxMax ( src1.m_y , src2.m_y ); - bottom = wxMin ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); - - if ( left < right && top < bottom ) - { - dest->m_x = left; - dest->m_y = top; - dest->m_width = right - left; - dest->m_height = bottom - top; - } - else - { - dest->m_width = dest->m_height = 0; - } -} - -void wxRect2DDouble::Union( const wxRect2DDouble &src1 , const wxRect2DDouble &src2 , wxRect2DDouble *dest ) -{ - wxDouble left,right,bottom,top; - - left = wxMin ( src1.m_x , src2.m_x ); - right = wxMax ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); - top = wxMin ( src1.m_y , src2.m_y ); - bottom = wxMax ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); - - dest->m_x = left; - dest->m_y = top; - dest->m_width = right - left; - dest->m_height = bottom - top; -} - -void wxRect2DDouble::Union( const wxPoint2DDouble &pt ) -{ - wxDouble x = pt.m_x; - wxDouble y = pt.m_y; - - if ( x < m_x ) - { - SetLeft( x ); - } - else if ( x < m_x + m_width ) - { - // contained - } - else - { - SetRight( x ); - } - - if ( y < m_y ) - { - SetTop( y ); - } - else if ( y < m_y + m_height ) - { - // contained - } - else - { - SetBottom( y ); - } -} - -void wxRect2DDouble::ConstrainTo( const wxRect2DDouble &rect ) -{ - if ( GetLeft() < rect.GetLeft() ) - SetLeft( rect.GetLeft() ); - - if ( GetRight() > rect.GetRight() ) - SetRight( rect.GetRight() ); - - if ( GetBottom() > rect.GetBottom() ) - SetBottom( rect.GetBottom() ); - - if ( GetTop() < rect.GetTop() ) - SetTop( rect.GetTop() ); -} - -wxRect2DDouble& wxRect2DDouble::operator=( const wxRect2DDouble &r ) -{ - m_x = r.m_x; - m_y = r.m_y; - m_width = r.m_width; - m_height = r.m_height; - return *this; -} - -// integer version - -// for the following calculations always remember -// that the right and bottom edges are not part of a rect - -// wxPoint2D - -#if wxUSE_STREAMS -void wxPoint2DInt::WriteTo( wxDataOutputStream &stream ) const -{ - stream.Write32( m_x ); - stream.Write32( m_y ); -} - -void wxPoint2DInt::ReadFrom( wxDataInputStream &stream ) -{ - m_x = stream.Read32(); - m_y = stream.Read32(); -} -#endif // wxUSE_STREAMS - -wxDouble wxPoint2DInt::GetVectorAngle() const -{ - if ( m_x == 0 ) - { - if ( m_y >= 0 ) - return 90; - else - return 270; - } - if ( m_y == 0 ) - { - if ( m_x >= 0 ) - return 0; - else - return 180; - } - - // casts needed for MIPSpro compiler under SGI - wxDouble deg = atan2( (double)m_y , (double)m_x ) * 180 / M_PI; - if ( deg < 0 ) - { - deg += 360; - } - return deg; -} - - -void wxPoint2DInt::SetVectorAngle( wxDouble degrees ) -{ - wxDouble length = GetVectorLength(); - m_x = (int)(length * cos( degrees / 180 * M_PI )); - m_y = (int)(length * sin( degrees / 180 * M_PI )); -} - -wxDouble wxPoint2DDouble::GetVectorAngle() const -{ - if ( wxIsNullDouble(m_x) ) - { - if ( m_y >= 0 ) - return 90; - else - return 270; - } - if ( wxIsNullDouble(m_y) ) - { - if ( m_x >= 0 ) - return 0; - else - return 180; - } - wxDouble deg = atan2( m_y , m_x ) * 180 / M_PI; - if ( deg < 0 ) - { - deg += 360; - } - return deg; -} - -void wxPoint2DDouble::SetVectorAngle( wxDouble degrees ) -{ - wxDouble length = GetVectorLength(); - m_x = length * cos( degrees / 180 * M_PI ); - m_y = length * sin( degrees / 180 * M_PI ); -} - -// wxRect2D - -bool wxRect2DInt::Intersects( const wxRect2DInt &rect ) const -{ - wxInt32 left,right,bottom,top; - left = wxMax ( m_x , rect.m_x ); - right = wxMin ( m_x+m_width, rect.m_x + rect.m_width ); - top = wxMax ( m_y , rect.m_y ); - bottom = wxMin ( m_y+m_height, rect.m_y + rect.m_height ); - - if ( left < right && top < bottom ) - { - return true; - } - return false; -} - -void wxRect2DInt::Intersect( const wxRect2DInt &src1 , const wxRect2DInt &src2 , wxRect2DInt *dest ) -{ - wxInt32 left,right,bottom,top; - left = wxMax ( src1.m_x , src2.m_x ); - right = wxMin ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); - top = wxMax ( src1.m_y , src2.m_y ); - bottom = wxMin ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); - - if ( left < right && top < bottom ) - { - dest->m_x = left; - dest->m_y = top; - dest->m_width = right - left; - dest->m_height = bottom - top; - } - else - { - dest->m_width = dest->m_height = 0; - } -} - -void wxRect2DInt::Union( const wxRect2DInt &src1 , const wxRect2DInt &src2 , wxRect2DInt *dest ) -{ - wxInt32 left,right,bottom,top; - - left = wxMin ( src1.m_x , src2.m_x ); - right = wxMax ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); - top = wxMin ( src1.m_y , src2.m_y ); - bottom = wxMax ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); - - dest->m_x = left; - dest->m_y = top; - dest->m_width = right - left; - dest->m_height = bottom - top; -} - -void wxRect2DInt::Union( const wxPoint2DInt &pt ) -{ - wxInt32 x = pt.m_x; - wxInt32 y = pt.m_y; - - if ( x < m_x ) - { - SetLeft( x ); - } - else if ( x < m_x + m_width ) - { - // contained - } - else - { - SetRight( x ); - } - - if ( y < m_y ) - { - SetTop( y ); - } - else if ( y < m_y + m_height ) - { - // contained - } - else - { - SetBottom( y ); - } -} - -void wxRect2DInt::ConstrainTo( const wxRect2DInt &rect ) -{ - if ( GetLeft() < rect.GetLeft() ) - SetLeft( rect.GetLeft() ); - - if ( GetRight() > rect.GetRight() ) - SetRight( rect.GetRight() ); - - if ( GetBottom() > rect.GetBottom() ) - SetBottom( rect.GetBottom() ); - - if ( GetTop() < rect.GetTop() ) - SetTop( rect.GetTop() ); -} - -wxRect2DInt& wxRect2DInt::operator=( const wxRect2DInt &r ) -{ - m_x = r.m_x; - m_y = r.m_y; - m_width = r.m_width; - m_height = r.m_height; - return *this; -} - -#if wxUSE_STREAMS -void wxRect2DInt::WriteTo( wxDataOutputStream &stream ) const -{ - stream.Write32( m_x ); - stream.Write32( m_y ); - stream.Write32( m_width ); - stream.Write32( m_height ); -} - -void wxRect2DInt::ReadFrom( wxDataInputStream &stream ) -{ - m_x = stream.Read32(); - m_y = stream.Read32(); - m_width = stream.Read32(); - m_height = stream.Read32(); -} -#endif // wxUSE_STREAMS - -#endif // wxUSE_GEOMETRY +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/geometry.cpp +// Purpose: Common Geometry Classes +// Author: Stefan Csomor +// Modified by: +// Created: 08/05/99 +// RCS-ID: +// Copyright: (c) 1999 Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_GEOMETRY + +#include "wx/geometry.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" +#endif + +#include + +#include "wx/datstrm.h" + +// +// wxPoint2D +// + +// +// wxRect2D +// + +// wxDouble version + +// for the following calculations always remember +// that the right and bottom edges are not part of a rect + +bool wxRect2DDouble::Intersects( const wxRect2DDouble &rect ) const +{ + wxDouble left,right,bottom,top; + left = wxMax ( m_x , rect.m_x ); + right = wxMin ( m_x+m_width, rect.m_x + rect.m_width ); + top = wxMax ( m_y , rect.m_y ); + bottom = wxMin ( m_y+m_height, rect.m_y + rect.m_height ); + + if ( left < right && top < bottom ) + { + return true; + } + return false; +} + +void wxRect2DDouble::Intersect( const wxRect2DDouble &src1 , const wxRect2DDouble &src2 , wxRect2DDouble *dest ) +{ + wxDouble left,right,bottom,top; + left = wxMax ( src1.m_x , src2.m_x ); + right = wxMin ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); + top = wxMax ( src1.m_y , src2.m_y ); + bottom = wxMin ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); + + if ( left < right && top < bottom ) + { + dest->m_x = left; + dest->m_y = top; + dest->m_width = right - left; + dest->m_height = bottom - top; + } + else + { + dest->m_width = dest->m_height = 0; + } +} + +void wxRect2DDouble::Union( const wxRect2DDouble &src1 , const wxRect2DDouble &src2 , wxRect2DDouble *dest ) +{ + wxDouble left,right,bottom,top; + + left = wxMin ( src1.m_x , src2.m_x ); + right = wxMax ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); + top = wxMin ( src1.m_y , src2.m_y ); + bottom = wxMax ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); + + dest->m_x = left; + dest->m_y = top; + dest->m_width = right - left; + dest->m_height = bottom - top; +} + +void wxRect2DDouble::Union( const wxPoint2DDouble &pt ) +{ + wxDouble x = pt.m_x; + wxDouble y = pt.m_y; + + if ( x < m_x ) + { + SetLeft( x ); + } + else if ( x < m_x + m_width ) + { + // contained + } + else + { + SetRight( x ); + } + + if ( y < m_y ) + { + SetTop( y ); + } + else if ( y < m_y + m_height ) + { + // contained + } + else + { + SetBottom( y ); + } +} + +void wxRect2DDouble::ConstrainTo( const wxRect2DDouble &rect ) +{ + if ( GetLeft() < rect.GetLeft() ) + SetLeft( rect.GetLeft() ); + + if ( GetRight() > rect.GetRight() ) + SetRight( rect.GetRight() ); + + if ( GetBottom() > rect.GetBottom() ) + SetBottom( rect.GetBottom() ); + + if ( GetTop() < rect.GetTop() ) + SetTop( rect.GetTop() ); +} + +wxRect2DDouble& wxRect2DDouble::operator=( const wxRect2DDouble &r ) +{ + m_x = r.m_x; + m_y = r.m_y; + m_width = r.m_width; + m_height = r.m_height; + return *this; +} + +// integer version + +// for the following calculations always remember +// that the right and bottom edges are not part of a rect + +// wxPoint2D + +#if wxUSE_STREAMS +void wxPoint2DInt::WriteTo( wxDataOutputStream &stream ) const +{ + stream.Write32( m_x ); + stream.Write32( m_y ); +} + +void wxPoint2DInt::ReadFrom( wxDataInputStream &stream ) +{ + m_x = stream.Read32(); + m_y = stream.Read32(); +} +#endif // wxUSE_STREAMS + +wxDouble wxPoint2DInt::GetVectorAngle() const +{ + if ( m_x == 0 ) + { + if ( m_y >= 0 ) + return 90; + else + return 270; + } + if ( m_y == 0 ) + { + if ( m_x >= 0 ) + return 0; + else + return 180; + } + + // casts needed for MIPSpro compiler under SGI + wxDouble deg = atan2( (double)m_y , (double)m_x ) * 180 / M_PI; + if ( deg < 0 ) + { + deg += 360; + } + return deg; +} + + +void wxPoint2DInt::SetVectorAngle( wxDouble degrees ) +{ + wxDouble length = GetVectorLength(); + m_x = (int)(length * cos( degrees / 180 * M_PI )); + m_y = (int)(length * sin( degrees / 180 * M_PI )); +} + +wxDouble wxPoint2DDouble::GetVectorAngle() const +{ + if ( wxIsNullDouble(m_x) ) + { + if ( m_y >= 0 ) + return 90; + else + return 270; + } + if ( wxIsNullDouble(m_y) ) + { + if ( m_x >= 0 ) + return 0; + else + return 180; + } + wxDouble deg = atan2( m_y , m_x ) * 180 / M_PI; + if ( deg < 0 ) + { + deg += 360; + } + return deg; +} + +void wxPoint2DDouble::SetVectorAngle( wxDouble degrees ) +{ + wxDouble length = GetVectorLength(); + m_x = length * cos( degrees / 180 * M_PI ); + m_y = length * sin( degrees / 180 * M_PI ); +} + +// wxRect2D + +bool wxRect2DInt::Intersects( const wxRect2DInt &rect ) const +{ + wxInt32 left,right,bottom,top; + left = wxMax ( m_x , rect.m_x ); + right = wxMin ( m_x+m_width, rect.m_x + rect.m_width ); + top = wxMax ( m_y , rect.m_y ); + bottom = wxMin ( m_y+m_height, rect.m_y + rect.m_height ); + + if ( left < right && top < bottom ) + { + return true; + } + return false; +} + +void wxRect2DInt::Intersect( const wxRect2DInt &src1 , const wxRect2DInt &src2 , wxRect2DInt *dest ) +{ + wxInt32 left,right,bottom,top; + left = wxMax ( src1.m_x , src2.m_x ); + right = wxMin ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); + top = wxMax ( src1.m_y , src2.m_y ); + bottom = wxMin ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); + + if ( left < right && top < bottom ) + { + dest->m_x = left; + dest->m_y = top; + dest->m_width = right - left; + dest->m_height = bottom - top; + } + else + { + dest->m_width = dest->m_height = 0; + } +} + +void wxRect2DInt::Union( const wxRect2DInt &src1 , const wxRect2DInt &src2 , wxRect2DInt *dest ) +{ + wxInt32 left,right,bottom,top; + + left = wxMin ( src1.m_x , src2.m_x ); + right = wxMax ( src1.m_x+src1.m_width, src2.m_x + src2.m_width ); + top = wxMin ( src1.m_y , src2.m_y ); + bottom = wxMax ( src1.m_y+src1.m_height, src2.m_y + src2.m_height ); + + dest->m_x = left; + dest->m_y = top; + dest->m_width = right - left; + dest->m_height = bottom - top; +} + +void wxRect2DInt::Union( const wxPoint2DInt &pt ) +{ + wxInt32 x = pt.m_x; + wxInt32 y = pt.m_y; + + if ( x < m_x ) + { + SetLeft( x ); + } + else if ( x < m_x + m_width ) + { + // contained + } + else + { + SetRight( x ); + } + + if ( y < m_y ) + { + SetTop( y ); + } + else if ( y < m_y + m_height ) + { + // contained + } + else + { + SetBottom( y ); + } +} + +void wxRect2DInt::ConstrainTo( const wxRect2DInt &rect ) +{ + if ( GetLeft() < rect.GetLeft() ) + SetLeft( rect.GetLeft() ); + + if ( GetRight() > rect.GetRight() ) + SetRight( rect.GetRight() ); + + if ( GetBottom() > rect.GetBottom() ) + SetBottom( rect.GetBottom() ); + + if ( GetTop() < rect.GetTop() ) + SetTop( rect.GetTop() ); +} + +wxRect2DInt& wxRect2DInt::operator=( const wxRect2DInt &r ) +{ + m_x = r.m_x; + m_y = r.m_y; + m_width = r.m_width; + m_height = r.m_height; + return *this; +} + +#if wxUSE_STREAMS +void wxRect2DInt::WriteTo( wxDataOutputStream &stream ) const +{ + stream.Write32( m_x ); + stream.Write32( m_y ); + stream.Write32( m_width ); + stream.Write32( m_height ); +} + +void wxRect2DInt::ReadFrom( wxDataInputStream &stream ) +{ + m_x = stream.Read32(); + m_y = stream.Read32(); + m_width = stream.Read32(); + m_height = stream.Read32(); +} +#endif // wxUSE_STREAMS + +#endif // wxUSE_GEOMETRY diff --git a/Source/3rd Party/wx/src/common/gifdecod.cpp b/Source/3rd Party/wx/src/common/gifdecod.cpp index ce3eaad61..1f3c869d5 100644 --- a/Source/3rd Party/wx/src/common/gifdecod.cpp +++ b/Source/3rd Party/wx/src/common/gifdecod.cpp @@ -1,933 +1,933 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/gifdecod.cpp -// Purpose: wxGIFDecoder, GIF reader for wxImage and wxAnimation -// Author: Guillermo Rodriguez Garcia -// Version: 3.04 -// RCS-ID: $Id: gifdecod.cpp 62183 2009-09-28 09:40:20Z JS $ -// Copyright: (c) Guillermo Rodriguez Garcia -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS && wxUSE_GIF - -#ifndef WX_PRECOMP - #include "wx/palette.h" - #include "wx/log.h" - #include "wx/intl.h" -#endif - -#include -#include -#include "wx/gifdecod.h" - - - -//--------------------------------------------------------------------------- -// GIFImage -//--------------------------------------------------------------------------- - -// internal class for storing GIF image data -class GIFImage -{ -public: - // def ctor - GIFImage(); - - unsigned int w; // width - unsigned int h; // height - unsigned int left; // x coord (in logical screen) - unsigned int top; // y coord (in logical screen) - int transparent; // transparent color index (-1 = none) - wxAnimationDisposal disposal; // disposal method - long delay; // delay in ms (-1 = unused) - unsigned char *p; // bitmap - unsigned char *pal; // palette - unsigned int ncolours; // number of colours - - DECLARE_NO_COPY_CLASS(GIFImage) -}; - - - -//--------------------------------------------------------------------------- -// GIFImage constructor -//--------------------------------------------------------------------------- -GIFImage::GIFImage() -{ - w = 0; - h = 0; - left = 0; - top = 0; - transparent = 0; - disposal = wxANIM_DONOTREMOVE; - delay = -1; - p = (unsigned char *) NULL; - pal = (unsigned char *) NULL; - ncolours = 0; -} - -//--------------------------------------------------------------------------- -// wxGIFDecoder constructor and destructor -//--------------------------------------------------------------------------- - -wxGIFDecoder::wxGIFDecoder() -{ -} - -wxGIFDecoder::~wxGIFDecoder() -{ - Destroy(); -} - -void wxGIFDecoder::Destroy() -{ - wxASSERT(m_nFrames==m_frames.GetCount()); - for (unsigned int i=0; ip); - free(f->pal); - delete f; - } - - m_frames.Clear(); - m_nFrames = 0; -} - - -//--------------------------------------------------------------------------- -// Convert this image to a wxImage object -//--------------------------------------------------------------------------- - -// This function was designed by Vaclav Slavik - -bool wxGIFDecoder::ConvertToImage(unsigned int frame, wxImage *image) const -{ - unsigned char *src, *dst, *pal; - unsigned long i; - int transparent; - - // just in case... - image->Destroy(); - - // create the image - wxSize sz = GetFrameSize(frame); - image->Create(sz.GetWidth(), sz.GetHeight()); - - if (!image->Ok()) - return false; - - pal = GetPalette(frame); - src = GetData(frame); - dst = image->GetData(); - transparent = GetTransparentColourIndex(frame); - - // set transparent colour mask - if (transparent != -1) - { - for (i = 0; i < GetNcolours(frame); i++) - { - if ((pal[3 * i + 0] == 255) && - (pal[3 * i + 1] == 0) && - (pal[3 * i + 2] == 255)) - { - pal[3 * i + 2] = 254; - } - } - - pal[3 * transparent + 0] = 255, - pal[3 * transparent + 1] = 0, - pal[3 * transparent + 2] = 255; - - image->SetMaskColour(255, 0, 255); - } - else - image->SetMask(false); - -#if wxUSE_PALETTE - unsigned char r[256]; - unsigned char g[256]; - unsigned char b[256]; - - for (i = 0; i < 256; i++) - { - r[i] = pal[3*i + 0]; - g[i] = pal[3*i + 1]; - b[i] = pal[3*i + 2]; - } - - image->SetPalette(wxPalette(GetNcolours(frame), r, g, b)); -#endif // wxUSE_PALETTE - - // copy image data - unsigned long npixel = sz.GetWidth() * sz.GetHeight(); - for (i = 0; i < npixel; i++, src++) - { - *(dst++) = pal[3 * (*src) + 0]; - *(dst++) = pal[3 * (*src) + 1]; - *(dst++) = pal[3 * (*src) + 2]; - } - - return true; -} - - -//--------------------------------------------------------------------------- -// Data accessors -//--------------------------------------------------------------------------- - -#define GetFrame(n) ((GIFImage*)m_frames[n]) - - -// Get data for current frame - -wxSize wxGIFDecoder::GetFrameSize(unsigned int frame) const -{ - return wxSize(GetFrame(frame)->w, GetFrame(frame)->h); -} - -wxPoint wxGIFDecoder::GetFramePosition(unsigned int frame) const -{ - return wxPoint(GetFrame(frame)->left, GetFrame(frame)->top); -} - -wxAnimationDisposal wxGIFDecoder::GetDisposalMethod(unsigned int frame) const -{ - return GetFrame(frame)->disposal; -} - -long wxGIFDecoder::GetDelay(unsigned int frame) const -{ - return GetFrame(frame)->delay; -} - -wxColour wxGIFDecoder::GetTransparentColour(unsigned int frame) const -{ - unsigned char *pal = GetFrame(frame)->pal; - int n = GetFrame(frame)->transparent; - if (n == -1) - return wxNullColour; - - return wxColour(pal[n*3 + 0], - pal[n*3 + 1], - pal[n*3 + 2]); -} - -unsigned char* wxGIFDecoder::GetData(unsigned int frame) const { return (GetFrame(frame)->p); } -unsigned char* wxGIFDecoder::GetPalette(unsigned int frame) const { return (GetFrame(frame)->pal); } -unsigned int wxGIFDecoder::GetNcolours(unsigned int frame) const { return (GetFrame(frame)->ncolours); } -int wxGIFDecoder::GetTransparentColourIndex(unsigned int frame) const { return (GetFrame(frame)->transparent); } - - - -//--------------------------------------------------------------------------- -// GIF reading and decoding -//--------------------------------------------------------------------------- - -// getcode: -// Reads the next code from the file stream, with size 'bits' -// -int wxGIFDecoder::getcode(wxInputStream& stream, int bits, int ab_fin) -{ - unsigned int mask; // bit mask - unsigned int code; // code (result) - - // get remaining bits from last byte read - mask = (1 << bits) - 1; - code = (m_lastbyte >> (8 - m_restbits)) & mask; - - // keep reading new bytes while needed - while (bits > m_restbits) - { - // if no bytes left in this block, read the next block - if (m_restbyte == 0) - { - m_restbyte = (unsigned char)stream.GetC(); - - /* Some encoders are a bit broken: instead of issuing - * an end-of-image symbol (ab_fin) they come up with - * a zero-length subblock!! We catch this here so - * that the decoder sees an ab_fin code. - */ - if (m_restbyte == 0) - { - code = ab_fin; - break; - } - - // prefetch data - stream.Read((void *) m_buffer, m_restbyte); - if (stream.LastRead() != m_restbyte) - { - code = ab_fin; - return code; - } - m_bufp = m_buffer; - } - - // read next byte and isolate the bits we need - m_lastbyte = (unsigned char) (*m_bufp++); - mask = (1 << (bits - m_restbits)) - 1; - code = code + ((m_lastbyte & mask) << m_restbits); - m_restbyte--; - - // adjust total number of bits extracted from the buffer - m_restbits = m_restbits + 8; - } - - // find number of bits remaining for next code - m_restbits = (m_restbits - bits); - - return code; -} - - -// dgif: -// GIF decoding function. The initial code size (aka root size) -// is 'bits'. Supports interlaced images (interl == 1). -// Returns wxGIF_OK (== 0) on success, or an error code if something -// fails (see header file for details) -wxGIFErrorCode -wxGIFDecoder::dgif(wxInputStream& stream, GIFImage *img, int interl, int bits) -{ - static const int allocSize = 4096 + 1; - int *ab_prefix = new int[allocSize]; // alphabet (prefixes) - if (ab_prefix == NULL) - { - return wxGIF_MEMERR; - } - - int *ab_tail = new int[allocSize]; // alphabet (tails) - if (ab_tail == NULL) - { - delete[] ab_prefix; - return wxGIF_MEMERR; - } - - int *stack = new int[allocSize]; // decompression stack - if (stack == NULL) - { - delete[] ab_prefix; - delete[] ab_tail; - return wxGIF_MEMERR; - } - - int ab_clr; // clear code - int ab_fin; // end of info code - int ab_bits; // actual symbol width, in bits - int ab_free; // first free position in alphabet - int ab_max; // last possible character in alphabet - int pass; // pass number in interlaced images - int pos; // index into decompresion stack - unsigned int x, y; // position in image buffer - - int code, readcode, lastcode, abcabca; - - // these won't change - ab_clr = (1 << bits); - ab_fin = (1 << bits) + 1; - - // these will change through the decompression proccess - ab_bits = bits + 1; - ab_free = (1 << bits) + 2; - ab_max = (1 << ab_bits) - 1; - lastcode = -1; - abcabca = -1; - pass = 1; - pos = x = y = 0; - - // reset decoder vars - m_restbits = 0; - m_restbyte = 0; - m_lastbyte = 0; - - do - { - // get next code - readcode = code = getcode(stream, ab_bits, ab_fin); - - // end of image? - if (code == ab_fin) break; - - // reset alphabet? - if (code == ab_clr) - { - // reset main variables - ab_bits = bits + 1; - ab_free = (1 << bits) + 2; - ab_max = (1 << ab_bits) - 1; - lastcode = -1; - abcabca = -1; - - // skip to next code - continue; - } - - // unknown code: special case (like in ABCABCA) - if (code >= ab_free) - { - code = lastcode; // take last string - stack[pos++] = abcabca; // add first character - } - - // build the string for this code in the stack - while (code > ab_clr) - { - stack[pos++] = ab_tail[code]; - code = ab_prefix[code]; - - // Don't overflow. This shouldn't happen with normal - // GIF files, the allocSize of 4096+1 is enough. This - // will only happen with badly formed GIFs. - if (pos >= allocSize) - { - delete[] ab_prefix; - delete[] ab_tail; - delete[] stack; - return wxGIF_INVFORMAT; - } - } - - if (pos >= allocSize) - { - delete[] ab_prefix; - delete[] ab_tail; - delete[] stack; - return wxGIF_INVFORMAT; - } - - stack[pos] = code; // push last code into the stack - abcabca = code; // save for special case - - // make new entry in alphabet (only if NOT just cleared) - if (lastcode != -1) - { - // Normally, after the alphabet is full and can't grow any - // further (ab_free == 4096), encoder should (must?) emit CLEAR - // to reset it. This checks whether we really got it, otherwise - // the GIF is damaged. - if (ab_free > ab_max) - { - delete[] ab_prefix; - delete[] ab_tail; - delete[] stack; - return wxGIF_INVFORMAT; - } - - // This assert seems unnecessary since the condition above - // eliminates the only case in which it went false. But I really - // don't like being forced to ask "Who in .text could have - // written there?!" And I wouldn't have been forced to ask if - // this line had already been here. - wxASSERT(ab_free < allocSize); - - ab_prefix[ab_free] = lastcode; - ab_tail[ab_free] = code; - ab_free++; - - if ((ab_free > ab_max) && (ab_bits < 12)) - { - ab_bits++; - ab_max = (1 << ab_bits) - 1; - } - } - - // dump stack data to the image buffer - while (pos >= 0) - { - (img->p)[x + (y * (img->w))] = (char) stack[pos]; - pos--; - - if (++x >= (img->w)) - { - x = 0; - - if (interl) - { - // support for interlaced images - switch (pass) - { - case 1: y += 8; break; - case 2: y += 8; break; - case 3: y += 4; break; - case 4: y += 2; break; - } - - /* loop until a valid y coordinate has been - found, Or if the maximum number of passes has - been reached, exit the loop, and stop image - decoding (At this point the image is successfully - decoded). - If we don't loop, but merely set y to some other - value, that new value might still be invalid depending - on the height of the image. This would cause out of - bounds writing. - */ - while (y >= (img->h)) - { - switch (++pass) - { - case 2: y = 4; break; - case 3: y = 2; break; - case 4: y = 1; break; - - default: - /* - It's possible we arrive here. For example this - happens when the image is interlaced, and the - height is 1. Looking at the above cases, the - lowest possible y is 1. While the only valid - one would be 0 for an image of height 1. So - 'eventually' the loop will arrive here. - This case makes sure this while loop is - exited, as well as the 2 other ones. - */ - - // Set y to a valid coordinate so the local - // while loop will be exited. (y = 0 always - // is >= img->h since if img->h == 0 the - // image is never decoded) - y = 0; - - // This will exit the other outer while loop - pos = -1; - - // This will halt image decoding. - code = ab_fin; - - break; - } - } - } - else - { - // non-interlaced - y++; -/* -Normally image decoding is finished when an End of Information code is -encountered (code == ab_fin) however some broken encoders write wrong -"block byte counts" (The first byte value after the "code size" byte), -being one value too high. It might very well be possible other variants -of this problem occur as well. The only sensible solution seems to -be to check for clipping. -Example of wrong encoding: -(1 * 1 B/W image, raster data stream follows in hex bytes) - -02 << B/W images have a code size of 2 -02 << Block byte count -44 << LZW packed -00 << Zero byte count (terminates data stream) - -Because the block byte count is 2, the zero byte count is used in the -decoding process, and decoding is continued after this byte. (While it -should signal an end of image) - -It should be: -02 -02 -44 -01 << When decoded this correctly includes the End of Information code -00 - -Or (Worse solution): -02 -01 -44 -00 -(The 44 doesn't include an End of Information code, but at least the -decoder correctly skips to 00 now after decoding, and signals this -as an End of Information itself) -*/ - if (y >= img->h) - { - code = ab_fin; - break; - } - } - } - } - - pos = 0; - lastcode = readcode; - } - while (code != ab_fin); - - delete [] ab_prefix ; - delete [] ab_tail ; - delete [] stack ; - - return wxGIF_OK; -} - - -// CanRead: -// Returns true if the file looks like a valid GIF, false otherwise. -// -bool wxGIFDecoder::CanRead(wxInputStream &stream) const -{ - unsigned char buf[3]; - - if ( !stream.Read(buf, WXSIZEOF(buf)) ) - return false; - - stream.SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent); - - return memcmp(buf, "GIF", WXSIZEOF(buf)) == 0; -} - - -// LoadGIF: -// Reads and decodes one or more GIF images, depending on whether -// animated GIF support is enabled. Can read GIFs with any bit -// size (color depth), but the output images are always expanded -// to 8 bits per pixel. Also, the image palettes always contain -// 256 colors, although some of them may be unused. Returns wxGIF_OK -// (== 0) on success, or an error code if something fails (see -// header file for details) -// -wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) -{ - unsigned int global_ncolors = 0; - int bits, interl, i; - wxAnimationDisposal disposal; - long size; - long delay; - unsigned char type = 0; - unsigned char pal[768]; - unsigned char buf[16]; - bool anim = true; - - // check GIF signature - if (!CanRead(stream)) - return wxGIF_INVFORMAT; - - // check for animated GIF support (ver. >= 89a) - - static const unsigned int headerSize = (3 + 3); - stream.Read(buf, headerSize); - if (stream.LastRead() != headerSize) - { - return wxGIF_INVFORMAT; - } - - if (memcmp(buf + 3, "89a", 3) < 0) - { - anim = false; - } - - // read logical screen descriptor block (LSDB) - static const unsigned int lsdbSize = (2 + 2 + 1 + 1 + 1); - stream.Read(buf, lsdbSize); - if (stream.LastRead() != lsdbSize) - { - return wxGIF_INVFORMAT; - } - - m_szAnimation.SetWidth( buf[0] + 256 * buf[1] ); - m_szAnimation.SetHeight( buf[2] + 256 * buf[3] ); - - if (anim && ((m_szAnimation.GetWidth() == 0) || (m_szAnimation.GetHeight() == 0))) - { - return wxGIF_INVFORMAT; - } - - // load global color map if available - if ((buf[4] & 0x80) == 0x80) - { - int backgroundColIndex = buf[5]; - - global_ncolors = 2 << (buf[4] & 0x07); - unsigned int numBytes = 3 * global_ncolors; - stream.Read(pal, numBytes); - if (stream.LastRead() != numBytes) - { - return wxGIF_INVFORMAT; - } - - m_background.Set(pal[backgroundColIndex*3 + 0], - pal[backgroundColIndex*3 + 1], - pal[backgroundColIndex*3 + 2]); - } - - // transparent colour, disposal method and delay default to unused - int transparent = -1; - disposal = wxANIM_UNSPECIFIED; - delay = -1; - - bool done = false; - while (!done) - { - type = (unsigned char)stream.GetC(); - - /* - If the end of file has been reached (or an error) and a ";" - (0x3B) hasn't been encountered yet, exit the loop. (Without this - check the while loop would loop endlessly.) Later on, in the next while - loop, the file will be treated as being truncated (But still - be decoded as far as possible). returning wxGIF_TRUNCATED is not - possible here since some init code is done after this loop. - */ - if (stream.Eof())// || !stream.IsOk()) - { - /* - type is set to some bogus value, so there's no - need to continue evaluating it. - */ - break; // Alternative : "return wxGIF_INVFORMAT;" - } - - // end of data? - if (type == 0x3B) - { - done = true; - } - else - // extension block? - if (type == 0x21) - { - if (((unsigned char)stream.GetC()) == 0xF9) - // graphics control extension, parse it - { - static const unsigned int gceSize = 6; - stream.Read(buf, gceSize); - if (stream.LastRead() != gceSize) - { - Destroy(); - return wxGIF_INVFORMAT; - } - - // read delay and convert from 1/100 of a second to ms - delay = 10 * (buf[2] + 256 * buf[3]); - - // read transparent colour index, if used - transparent = buf[1] & 0x01 ? buf[4] : -1; - - // read disposal method - disposal = (wxAnimationDisposal)(((buf[1] & 0x1C) >> 2) - 1); - } - else - // other extension, skip - { - while ((i = (unsigned char)stream.GetC()) != 0) - { - if (stream.Eof() || (stream.LastRead() == 0)) - { - done = true; - break; - } - stream.SeekI(i, wxFromCurrent); - } - } - } - else - // image descriptor block? - if (type == 0x2C) - { - // allocate memory for IMAGEN struct - GIFImage *pimg = new GIFImage(); - - if (pimg == NULL) - { - Destroy(); - return wxGIF_MEMERR; - } - - // fill in the data - static const unsigned int idbSize = (2 + 2 + 2 + 2 + 1); - stream.Read(buf, idbSize); - if (stream.LastRead() != idbSize) - { - Destroy(); - return wxGIF_INVFORMAT; - } - - pimg->left = buf[0] + 256 * buf[1]; - pimg->top = buf[2] + 256 * buf[3]; -/* - pimg->left = buf[4] + 256 * buf[5]; - pimg->top = buf[4] + 256 * buf[5]; -*/ - pimg->w = buf[4] + 256 * buf[5]; - pimg->h = buf[6] + 256 * buf[7]; - -#if 0 - if (anim && ((pimg->w == 0) || (pimg->w > (unsigned int)m_szAnimation.GetWidth()) || - (pimg->h == 0) || (pimg->h > (unsigned int)m_szAnimation.GetHeight()))) - { - Destroy(); - return wxGIF_INVFORMAT; - } -#endif - if ( anim ) - { - // some GIF images specify incorrect animation size but we can - // still open them if we fix up the animation size, see #9465 - if ( m_nFrames == 0 ) - { - if ( pimg->w > (unsigned)m_szAnimation.x ) - m_szAnimation.x = pimg->w; - if ( pimg->h > (unsigned)m_szAnimation.y ) - m_szAnimation.y = pimg->h; - } - else // subsequent frames - { - // check that we have valid size - if ( (!pimg->w || pimg->w > (unsigned)m_szAnimation.x) || - (!pimg->h || pimg->h > (unsigned)m_szAnimation.y) ) - { - wxLogError(_("Incorrect GIF frame size (%u, %d) for the frame #%u"), - pimg->w, pimg->h, m_nFrames); - Destroy(); - return wxGIF_INVFORMAT; - } - } - } - - interl = ((buf[8] & 0x40)? 1 : 0); - size = pimg->w * pimg->h; - - pimg->transparent = transparent; - pimg->disposal = disposal; - pimg->delay = delay; - - // allocate memory for image and palette - pimg->p = (unsigned char *) malloc((unsigned int)size); - pimg->pal = (unsigned char *) malloc(768); - - if ((!pimg->p) || (!pimg->pal)) - { - Destroy(); - return wxGIF_MEMERR; - } - - // load local color map if available, else use global map - if ((buf[8] & 0x80) == 0x80) - { - unsigned int local_ncolors = 2 << (buf[8] & 0x07); - unsigned int numBytes = 3 * local_ncolors; - stream.Read(pimg->pal, numBytes); - pimg->ncolours = local_ncolors; - if (stream.LastRead() != numBytes) - { - Destroy(); - return wxGIF_INVFORMAT; - } - } - else - { - memcpy(pimg->pal, pal, 768); - pimg->ncolours = global_ncolors; - } - - // get initial code size from first byte in raster data - bits = (unsigned char)stream.GetC(); - if (bits == 0) - { - Destroy(); - return wxGIF_INVFORMAT; - } - - // decode image - wxGIFErrorCode result = dgif(stream, pimg, interl, bits); - if (result != wxGIF_OK) - { - Destroy(); - return result; - } - - // add the image to our frame array - m_frames.Add((void*)pimg); - m_nFrames++; - - // if this is not an animated GIF, exit after first image - if (!anim) - done = true; - } - } - - if (m_nFrames <= 0) - { - Destroy(); - return wxGIF_INVFORMAT; - } - - // try to read to the end of the stream - while (type != 0x3B) - { - if (!stream.IsOk()) - return wxGIF_TRUNCATED; - - type = (unsigned char)stream.GetC(); - - if (type == 0x21) - { - // extension type - (void) stream.GetC(); - - // skip all data - while ((i = (unsigned char)stream.GetC()) != 0) - { - if (stream.Eof() || (stream.LastRead() == 0)) - { - Destroy(); - return wxGIF_INVFORMAT; - } - stream.SeekI(i, wxFromCurrent); - } - } - else if (type == 0x2C) - { - // image descriptor block - static const unsigned int idbSize = (2 + 2 + 2 + 2 + 1); - stream.Read(buf, idbSize); - if (stream.LastRead() != idbSize) - { - Destroy(); - return wxGIF_INVFORMAT; - } - - // local color map - if ((buf[8] & 0x80) == 0x80) - { - unsigned int local_ncolors = 2 << (buf[8] & 0x07); - wxFileOffset numBytes = 3 * local_ncolors; - stream.SeekI(numBytes, wxFromCurrent); - } - - // initial code size - (void) stream.GetC(); - if (stream.Eof() || (stream.LastRead() == 0)) - { - Destroy(); - return wxGIF_INVFORMAT; - } - - // skip all data - while ((i = (unsigned char)stream.GetC()) != 0) - { - if (stream.Eof() || (stream.LastRead() == 0)) - { - Destroy(); - return wxGIF_INVFORMAT; - } - stream.SeekI(i, wxFromCurrent); - } - } - else if ((type != 0x3B) && (type != 00)) // testing - { - // images are OK, but couldn't read to the end of the stream - return wxGIF_TRUNCATED; - } - } - - return wxGIF_OK; -} - -#endif // wxUSE_STREAMS && wxUSE_GIF +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/gifdecod.cpp +// Purpose: wxGIFDecoder, GIF reader for wxImage and wxAnimation +// Author: Guillermo Rodriguez Garcia +// Version: 3.04 +// RCS-ID: $Id: gifdecod.cpp 62183 2009-09-28 09:40:20Z JS $ +// Copyright: (c) Guillermo Rodriguez Garcia +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS && wxUSE_GIF + +#ifndef WX_PRECOMP + #include "wx/palette.h" + #include "wx/log.h" + #include "wx/intl.h" +#endif + +#include +#include +#include "wx/gifdecod.h" + + + +//--------------------------------------------------------------------------- +// GIFImage +//--------------------------------------------------------------------------- + +// internal class for storing GIF image data +class GIFImage +{ +public: + // def ctor + GIFImage(); + + unsigned int w; // width + unsigned int h; // height + unsigned int left; // x coord (in logical screen) + unsigned int top; // y coord (in logical screen) + int transparent; // transparent color index (-1 = none) + wxAnimationDisposal disposal; // disposal method + long delay; // delay in ms (-1 = unused) + unsigned char *p; // bitmap + unsigned char *pal; // palette + unsigned int ncolours; // number of colours + + DECLARE_NO_COPY_CLASS(GIFImage) +}; + + + +//--------------------------------------------------------------------------- +// GIFImage constructor +//--------------------------------------------------------------------------- +GIFImage::GIFImage() +{ + w = 0; + h = 0; + left = 0; + top = 0; + transparent = 0; + disposal = wxANIM_DONOTREMOVE; + delay = -1; + p = (unsigned char *) NULL; + pal = (unsigned char *) NULL; + ncolours = 0; +} + +//--------------------------------------------------------------------------- +// wxGIFDecoder constructor and destructor +//--------------------------------------------------------------------------- + +wxGIFDecoder::wxGIFDecoder() +{ +} + +wxGIFDecoder::~wxGIFDecoder() +{ + Destroy(); +} + +void wxGIFDecoder::Destroy() +{ + wxASSERT(m_nFrames==m_frames.GetCount()); + for (unsigned int i=0; ip); + free(f->pal); + delete f; + } + + m_frames.Clear(); + m_nFrames = 0; +} + + +//--------------------------------------------------------------------------- +// Convert this image to a wxImage object +//--------------------------------------------------------------------------- + +// This function was designed by Vaclav Slavik + +bool wxGIFDecoder::ConvertToImage(unsigned int frame, wxImage *image) const +{ + unsigned char *src, *dst, *pal; + unsigned long i; + int transparent; + + // just in case... + image->Destroy(); + + // create the image + wxSize sz = GetFrameSize(frame); + image->Create(sz.GetWidth(), sz.GetHeight()); + + if (!image->Ok()) + return false; + + pal = GetPalette(frame); + src = GetData(frame); + dst = image->GetData(); + transparent = GetTransparentColourIndex(frame); + + // set transparent colour mask + if (transparent != -1) + { + for (i = 0; i < GetNcolours(frame); i++) + { + if ((pal[3 * i + 0] == 255) && + (pal[3 * i + 1] == 0) && + (pal[3 * i + 2] == 255)) + { + pal[3 * i + 2] = 254; + } + } + + pal[3 * transparent + 0] = 255, + pal[3 * transparent + 1] = 0, + pal[3 * transparent + 2] = 255; + + image->SetMaskColour(255, 0, 255); + } + else + image->SetMask(false); + +#if wxUSE_PALETTE + unsigned char r[256]; + unsigned char g[256]; + unsigned char b[256]; + + for (i = 0; i < 256; i++) + { + r[i] = pal[3*i + 0]; + g[i] = pal[3*i + 1]; + b[i] = pal[3*i + 2]; + } + + image->SetPalette(wxPalette(GetNcolours(frame), r, g, b)); +#endif // wxUSE_PALETTE + + // copy image data + unsigned long npixel = sz.GetWidth() * sz.GetHeight(); + for (i = 0; i < npixel; i++, src++) + { + *(dst++) = pal[3 * (*src) + 0]; + *(dst++) = pal[3 * (*src) + 1]; + *(dst++) = pal[3 * (*src) + 2]; + } + + return true; +} + + +//--------------------------------------------------------------------------- +// Data accessors +//--------------------------------------------------------------------------- + +#define GetFrame(n) ((GIFImage*)m_frames[n]) + + +// Get data for current frame + +wxSize wxGIFDecoder::GetFrameSize(unsigned int frame) const +{ + return wxSize(GetFrame(frame)->w, GetFrame(frame)->h); +} + +wxPoint wxGIFDecoder::GetFramePosition(unsigned int frame) const +{ + return wxPoint(GetFrame(frame)->left, GetFrame(frame)->top); +} + +wxAnimationDisposal wxGIFDecoder::GetDisposalMethod(unsigned int frame) const +{ + return GetFrame(frame)->disposal; +} + +long wxGIFDecoder::GetDelay(unsigned int frame) const +{ + return GetFrame(frame)->delay; +} + +wxColour wxGIFDecoder::GetTransparentColour(unsigned int frame) const +{ + unsigned char *pal = GetFrame(frame)->pal; + int n = GetFrame(frame)->transparent; + if (n == -1) + return wxNullColour; + + return wxColour(pal[n*3 + 0], + pal[n*3 + 1], + pal[n*3 + 2]); +} + +unsigned char* wxGIFDecoder::GetData(unsigned int frame) const { return (GetFrame(frame)->p); } +unsigned char* wxGIFDecoder::GetPalette(unsigned int frame) const { return (GetFrame(frame)->pal); } +unsigned int wxGIFDecoder::GetNcolours(unsigned int frame) const { return (GetFrame(frame)->ncolours); } +int wxGIFDecoder::GetTransparentColourIndex(unsigned int frame) const { return (GetFrame(frame)->transparent); } + + + +//--------------------------------------------------------------------------- +// GIF reading and decoding +//--------------------------------------------------------------------------- + +// getcode: +// Reads the next code from the file stream, with size 'bits' +// +int wxGIFDecoder::getcode(wxInputStream& stream, int bits, int ab_fin) +{ + unsigned int mask; // bit mask + unsigned int code; // code (result) + + // get remaining bits from last byte read + mask = (1 << bits) - 1; + code = (m_lastbyte >> (8 - m_restbits)) & mask; + + // keep reading new bytes while needed + while (bits > m_restbits) + { + // if no bytes left in this block, read the next block + if (m_restbyte == 0) + { + m_restbyte = (unsigned char)stream.GetC(); + + /* Some encoders are a bit broken: instead of issuing + * an end-of-image symbol (ab_fin) they come up with + * a zero-length subblock!! We catch this here so + * that the decoder sees an ab_fin code. + */ + if (m_restbyte == 0) + { + code = ab_fin; + break; + } + + // prefetch data + stream.Read((void *) m_buffer, m_restbyte); + if (stream.LastRead() != m_restbyte) + { + code = ab_fin; + return code; + } + m_bufp = m_buffer; + } + + // read next byte and isolate the bits we need + m_lastbyte = (unsigned char) (*m_bufp++); + mask = (1 << (bits - m_restbits)) - 1; + code = code + ((m_lastbyte & mask) << m_restbits); + m_restbyte--; + + // adjust total number of bits extracted from the buffer + m_restbits = m_restbits + 8; + } + + // find number of bits remaining for next code + m_restbits = (m_restbits - bits); + + return code; +} + + +// dgif: +// GIF decoding function. The initial code size (aka root size) +// is 'bits'. Supports interlaced images (interl == 1). +// Returns wxGIF_OK (== 0) on success, or an error code if something +// fails (see header file for details) +wxGIFErrorCode +wxGIFDecoder::dgif(wxInputStream& stream, GIFImage *img, int interl, int bits) +{ + static const int allocSize = 4096 + 1; + int *ab_prefix = new int[allocSize]; // alphabet (prefixes) + if (ab_prefix == NULL) + { + return wxGIF_MEMERR; + } + + int *ab_tail = new int[allocSize]; // alphabet (tails) + if (ab_tail == NULL) + { + delete[] ab_prefix; + return wxGIF_MEMERR; + } + + int *stack = new int[allocSize]; // decompression stack + if (stack == NULL) + { + delete[] ab_prefix; + delete[] ab_tail; + return wxGIF_MEMERR; + } + + int ab_clr; // clear code + int ab_fin; // end of info code + int ab_bits; // actual symbol width, in bits + int ab_free; // first free position in alphabet + int ab_max; // last possible character in alphabet + int pass; // pass number in interlaced images + int pos; // index into decompresion stack + unsigned int x, y; // position in image buffer + + int code, readcode, lastcode, abcabca; + + // these won't change + ab_clr = (1 << bits); + ab_fin = (1 << bits) + 1; + + // these will change through the decompression proccess + ab_bits = bits + 1; + ab_free = (1 << bits) + 2; + ab_max = (1 << ab_bits) - 1; + lastcode = -1; + abcabca = -1; + pass = 1; + pos = x = y = 0; + + // reset decoder vars + m_restbits = 0; + m_restbyte = 0; + m_lastbyte = 0; + + do + { + // get next code + readcode = code = getcode(stream, ab_bits, ab_fin); + + // end of image? + if (code == ab_fin) break; + + // reset alphabet? + if (code == ab_clr) + { + // reset main variables + ab_bits = bits + 1; + ab_free = (1 << bits) + 2; + ab_max = (1 << ab_bits) - 1; + lastcode = -1; + abcabca = -1; + + // skip to next code + continue; + } + + // unknown code: special case (like in ABCABCA) + if (code >= ab_free) + { + code = lastcode; // take last string + stack[pos++] = abcabca; // add first character + } + + // build the string for this code in the stack + while (code > ab_clr) + { + stack[pos++] = ab_tail[code]; + code = ab_prefix[code]; + + // Don't overflow. This shouldn't happen with normal + // GIF files, the allocSize of 4096+1 is enough. This + // will only happen with badly formed GIFs. + if (pos >= allocSize) + { + delete[] ab_prefix; + delete[] ab_tail; + delete[] stack; + return wxGIF_INVFORMAT; + } + } + + if (pos >= allocSize) + { + delete[] ab_prefix; + delete[] ab_tail; + delete[] stack; + return wxGIF_INVFORMAT; + } + + stack[pos] = code; // push last code into the stack + abcabca = code; // save for special case + + // make new entry in alphabet (only if NOT just cleared) + if (lastcode != -1) + { + // Normally, after the alphabet is full and can't grow any + // further (ab_free == 4096), encoder should (must?) emit CLEAR + // to reset it. This checks whether we really got it, otherwise + // the GIF is damaged. + if (ab_free > ab_max) + { + delete[] ab_prefix; + delete[] ab_tail; + delete[] stack; + return wxGIF_INVFORMAT; + } + + // This assert seems unnecessary since the condition above + // eliminates the only case in which it went false. But I really + // don't like being forced to ask "Who in .text could have + // written there?!" And I wouldn't have been forced to ask if + // this line had already been here. + wxASSERT(ab_free < allocSize); + + ab_prefix[ab_free] = lastcode; + ab_tail[ab_free] = code; + ab_free++; + + if ((ab_free > ab_max) && (ab_bits < 12)) + { + ab_bits++; + ab_max = (1 << ab_bits) - 1; + } + } + + // dump stack data to the image buffer + while (pos >= 0) + { + (img->p)[x + (y * (img->w))] = (char) stack[pos]; + pos--; + + if (++x >= (img->w)) + { + x = 0; + + if (interl) + { + // support for interlaced images + switch (pass) + { + case 1: y += 8; break; + case 2: y += 8; break; + case 3: y += 4; break; + case 4: y += 2; break; + } + + /* loop until a valid y coordinate has been + found, Or if the maximum number of passes has + been reached, exit the loop, and stop image + decoding (At this point the image is successfully + decoded). + If we don't loop, but merely set y to some other + value, that new value might still be invalid depending + on the height of the image. This would cause out of + bounds writing. + */ + while (y >= (img->h)) + { + switch (++pass) + { + case 2: y = 4; break; + case 3: y = 2; break; + case 4: y = 1; break; + + default: + /* + It's possible we arrive here. For example this + happens when the image is interlaced, and the + height is 1. Looking at the above cases, the + lowest possible y is 1. While the only valid + one would be 0 for an image of height 1. So + 'eventually' the loop will arrive here. + This case makes sure this while loop is + exited, as well as the 2 other ones. + */ + + // Set y to a valid coordinate so the local + // while loop will be exited. (y = 0 always + // is >= img->h since if img->h == 0 the + // image is never decoded) + y = 0; + + // This will exit the other outer while loop + pos = -1; + + // This will halt image decoding. + code = ab_fin; + + break; + } + } + } + else + { + // non-interlaced + y++; +/* +Normally image decoding is finished when an End of Information code is +encountered (code == ab_fin) however some broken encoders write wrong +"block byte counts" (The first byte value after the "code size" byte), +being one value too high. It might very well be possible other variants +of this problem occur as well. The only sensible solution seems to +be to check for clipping. +Example of wrong encoding: +(1 * 1 B/W image, raster data stream follows in hex bytes) + +02 << B/W images have a code size of 2 +02 << Block byte count +44 << LZW packed +00 << Zero byte count (terminates data stream) + +Because the block byte count is 2, the zero byte count is used in the +decoding process, and decoding is continued after this byte. (While it +should signal an end of image) + +It should be: +02 +02 +44 +01 << When decoded this correctly includes the End of Information code +00 + +Or (Worse solution): +02 +01 +44 +00 +(The 44 doesn't include an End of Information code, but at least the +decoder correctly skips to 00 now after decoding, and signals this +as an End of Information itself) +*/ + if (y >= img->h) + { + code = ab_fin; + break; + } + } + } + } + + pos = 0; + lastcode = readcode; + } + while (code != ab_fin); + + delete [] ab_prefix ; + delete [] ab_tail ; + delete [] stack ; + + return wxGIF_OK; +} + + +// CanRead: +// Returns true if the file looks like a valid GIF, false otherwise. +// +bool wxGIFDecoder::CanRead(wxInputStream &stream) const +{ + unsigned char buf[3]; + + if ( !stream.Read(buf, WXSIZEOF(buf)) ) + return false; + + stream.SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent); + + return memcmp(buf, "GIF", WXSIZEOF(buf)) == 0; +} + + +// LoadGIF: +// Reads and decodes one or more GIF images, depending on whether +// animated GIF support is enabled. Can read GIFs with any bit +// size (color depth), but the output images are always expanded +// to 8 bits per pixel. Also, the image palettes always contain +// 256 colors, although some of them may be unused. Returns wxGIF_OK +// (== 0) on success, or an error code if something fails (see +// header file for details) +// +wxGIFErrorCode wxGIFDecoder::LoadGIF(wxInputStream& stream) +{ + unsigned int global_ncolors = 0; + int bits, interl, i; + wxAnimationDisposal disposal; + long size; + long delay; + unsigned char type = 0; + unsigned char pal[768]; + unsigned char buf[16]; + bool anim = true; + + // check GIF signature + if (!CanRead(stream)) + return wxGIF_INVFORMAT; + + // check for animated GIF support (ver. >= 89a) + + static const unsigned int headerSize = (3 + 3); + stream.Read(buf, headerSize); + if (stream.LastRead() != headerSize) + { + return wxGIF_INVFORMAT; + } + + if (memcmp(buf + 3, "89a", 3) < 0) + { + anim = false; + } + + // read logical screen descriptor block (LSDB) + static const unsigned int lsdbSize = (2 + 2 + 1 + 1 + 1); + stream.Read(buf, lsdbSize); + if (stream.LastRead() != lsdbSize) + { + return wxGIF_INVFORMAT; + } + + m_szAnimation.SetWidth( buf[0] + 256 * buf[1] ); + m_szAnimation.SetHeight( buf[2] + 256 * buf[3] ); + + if (anim && ((m_szAnimation.GetWidth() == 0) || (m_szAnimation.GetHeight() == 0))) + { + return wxGIF_INVFORMAT; + } + + // load global color map if available + if ((buf[4] & 0x80) == 0x80) + { + int backgroundColIndex = buf[5]; + + global_ncolors = 2 << (buf[4] & 0x07); + unsigned int numBytes = 3 * global_ncolors; + stream.Read(pal, numBytes); + if (stream.LastRead() != numBytes) + { + return wxGIF_INVFORMAT; + } + + m_background.Set(pal[backgroundColIndex*3 + 0], + pal[backgroundColIndex*3 + 1], + pal[backgroundColIndex*3 + 2]); + } + + // transparent colour, disposal method and delay default to unused + int transparent = -1; + disposal = wxANIM_UNSPECIFIED; + delay = -1; + + bool done = false; + while (!done) + { + type = (unsigned char)stream.GetC(); + + /* + If the end of file has been reached (or an error) and a ";" + (0x3B) hasn't been encountered yet, exit the loop. (Without this + check the while loop would loop endlessly.) Later on, in the next while + loop, the file will be treated as being truncated (But still + be decoded as far as possible). returning wxGIF_TRUNCATED is not + possible here since some init code is done after this loop. + */ + if (stream.Eof())// || !stream.IsOk()) + { + /* + type is set to some bogus value, so there's no + need to continue evaluating it. + */ + break; // Alternative : "return wxGIF_INVFORMAT;" + } + + // end of data? + if (type == 0x3B) + { + done = true; + } + else + // extension block? + if (type == 0x21) + { + if (((unsigned char)stream.GetC()) == 0xF9) + // graphics control extension, parse it + { + static const unsigned int gceSize = 6; + stream.Read(buf, gceSize); + if (stream.LastRead() != gceSize) + { + Destroy(); + return wxGIF_INVFORMAT; + } + + // read delay and convert from 1/100 of a second to ms + delay = 10 * (buf[2] + 256 * buf[3]); + + // read transparent colour index, if used + transparent = buf[1] & 0x01 ? buf[4] : -1; + + // read disposal method + disposal = (wxAnimationDisposal)(((buf[1] & 0x1C) >> 2) - 1); + } + else + // other extension, skip + { + while ((i = (unsigned char)stream.GetC()) != 0) + { + if (stream.Eof() || (stream.LastRead() == 0)) + { + done = true; + break; + } + stream.SeekI(i, wxFromCurrent); + } + } + } + else + // image descriptor block? + if (type == 0x2C) + { + // allocate memory for IMAGEN struct + GIFImage *pimg = new GIFImage(); + + if (pimg == NULL) + { + Destroy(); + return wxGIF_MEMERR; + } + + // fill in the data + static const unsigned int idbSize = (2 + 2 + 2 + 2 + 1); + stream.Read(buf, idbSize); + if (stream.LastRead() != idbSize) + { + Destroy(); + return wxGIF_INVFORMAT; + } + + pimg->left = buf[0] + 256 * buf[1]; + pimg->top = buf[2] + 256 * buf[3]; +/* + pimg->left = buf[4] + 256 * buf[5]; + pimg->top = buf[4] + 256 * buf[5]; +*/ + pimg->w = buf[4] + 256 * buf[5]; + pimg->h = buf[6] + 256 * buf[7]; + +#if 0 + if (anim && ((pimg->w == 0) || (pimg->w > (unsigned int)m_szAnimation.GetWidth()) || + (pimg->h == 0) || (pimg->h > (unsigned int)m_szAnimation.GetHeight()))) + { + Destroy(); + return wxGIF_INVFORMAT; + } +#endif + if ( anim ) + { + // some GIF images specify incorrect animation size but we can + // still open them if we fix up the animation size, see #9465 + if ( m_nFrames == 0 ) + { + if ( pimg->w > (unsigned)m_szAnimation.x ) + m_szAnimation.x = pimg->w; + if ( pimg->h > (unsigned)m_szAnimation.y ) + m_szAnimation.y = pimg->h; + } + else // subsequent frames + { + // check that we have valid size + if ( (!pimg->w || pimg->w > (unsigned)m_szAnimation.x) || + (!pimg->h || pimg->h > (unsigned)m_szAnimation.y) ) + { + wxLogError(_("Incorrect GIF frame size (%u, %d) for the frame #%u"), + pimg->w, pimg->h, m_nFrames); + Destroy(); + return wxGIF_INVFORMAT; + } + } + } + + interl = ((buf[8] & 0x40)? 1 : 0); + size = pimg->w * pimg->h; + + pimg->transparent = transparent; + pimg->disposal = disposal; + pimg->delay = delay; + + // allocate memory for image and palette + pimg->p = (unsigned char *) malloc((unsigned int)size); + pimg->pal = (unsigned char *) malloc(768); + + if ((!pimg->p) || (!pimg->pal)) + { + Destroy(); + return wxGIF_MEMERR; + } + + // load local color map if available, else use global map + if ((buf[8] & 0x80) == 0x80) + { + unsigned int local_ncolors = 2 << (buf[8] & 0x07); + unsigned int numBytes = 3 * local_ncolors; + stream.Read(pimg->pal, numBytes); + pimg->ncolours = local_ncolors; + if (stream.LastRead() != numBytes) + { + Destroy(); + return wxGIF_INVFORMAT; + } + } + else + { + memcpy(pimg->pal, pal, 768); + pimg->ncolours = global_ncolors; + } + + // get initial code size from first byte in raster data + bits = (unsigned char)stream.GetC(); + if (bits == 0) + { + Destroy(); + return wxGIF_INVFORMAT; + } + + // decode image + wxGIFErrorCode result = dgif(stream, pimg, interl, bits); + if (result != wxGIF_OK) + { + Destroy(); + return result; + } + + // add the image to our frame array + m_frames.Add((void*)pimg); + m_nFrames++; + + // if this is not an animated GIF, exit after first image + if (!anim) + done = true; + } + } + + if (m_nFrames <= 0) + { + Destroy(); + return wxGIF_INVFORMAT; + } + + // try to read to the end of the stream + while (type != 0x3B) + { + if (!stream.IsOk()) + return wxGIF_TRUNCATED; + + type = (unsigned char)stream.GetC(); + + if (type == 0x21) + { + // extension type + (void) stream.GetC(); + + // skip all data + while ((i = (unsigned char)stream.GetC()) != 0) + { + if (stream.Eof() || (stream.LastRead() == 0)) + { + Destroy(); + return wxGIF_INVFORMAT; + } + stream.SeekI(i, wxFromCurrent); + } + } + else if (type == 0x2C) + { + // image descriptor block + static const unsigned int idbSize = (2 + 2 + 2 + 2 + 1); + stream.Read(buf, idbSize); + if (stream.LastRead() != idbSize) + { + Destroy(); + return wxGIF_INVFORMAT; + } + + // local color map + if ((buf[8] & 0x80) == 0x80) + { + unsigned int local_ncolors = 2 << (buf[8] & 0x07); + wxFileOffset numBytes = 3 * local_ncolors; + stream.SeekI(numBytes, wxFromCurrent); + } + + // initial code size + (void) stream.GetC(); + if (stream.Eof() || (stream.LastRead() == 0)) + { + Destroy(); + return wxGIF_INVFORMAT; + } + + // skip all data + while ((i = (unsigned char)stream.GetC()) != 0) + { + if (stream.Eof() || (stream.LastRead() == 0)) + { + Destroy(); + return wxGIF_INVFORMAT; + } + stream.SeekI(i, wxFromCurrent); + } + } + else if ((type != 0x3B) && (type != 00)) // testing + { + // images are OK, but couldn't read to the end of the stream + return wxGIF_TRUNCATED; + } + } + + return wxGIF_OK; +} + +#endif // wxUSE_STREAMS && wxUSE_GIF diff --git a/Source/3rd Party/wx/src/common/graphcmn.cpp b/Source/3rd Party/wx/src/common/graphcmn.cpp index 1ac6d0457..70f1a3416 100644 --- a/Source/3rd Party/wx/src/common/graphcmn.cpp +++ b/Source/3rd Party/wx/src/common/graphcmn.cpp @@ -1,776 +1,776 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/graphcmn.cpp -// Purpose: graphics context methods common to all platforms -// Author: Stefan Csomor -// Modified by: -// Created: -// RCS-ID: $Id: graphcmn.cpp 56801 2008-11-16 23:25:09Z KO $ -// Copyright: (c) Stefan Csomor -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#if wxUSE_GRAPHICS_CONTEXT - -#include "wx/graphics.h" - -#ifndef WX_PRECOMP - #include "wx/icon.h" - #include "wx/bitmap.h" - #include "wx/dcmemory.h" - #include "wx/region.h" - #include "wx/log.h" -#endif - -#if !defined(wxMAC_USE_CORE_GRAPHICS_BLEND_MODES) -#define wxMAC_USE_CORE_GRAPHICS_BLEND_MODES 0 -#endif - -//----------------------------------------------------------------------------- -// constants -//----------------------------------------------------------------------------- - -static const double RAD2DEG = 180.0 / M_PI; - -//----------------------------------------------------------------------------- -// Local functions -//----------------------------------------------------------------------------- - -static inline double DegToRad(double deg) -{ - return (deg * M_PI) / 180.0; -} - -//----------------------------------------------------------------------------- - -//----------------------------------------------------------------------------- -// wxGraphicsObject -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGraphicsObject, wxObject) - -wxGraphicsObjectRefData::wxGraphicsObjectRefData( wxGraphicsRenderer* renderer ) -{ - m_renderer = renderer; -} -wxGraphicsObjectRefData::wxGraphicsObjectRefData( const wxGraphicsObjectRefData* data ) -{ - m_renderer = data->m_renderer; -} -wxGraphicsRenderer* wxGraphicsObjectRefData::GetRenderer() const -{ - return m_renderer ; -} - -wxGraphicsObjectRefData* wxGraphicsObjectRefData::Clone() const -{ - return new wxGraphicsObjectRefData(this); -} - -wxGraphicsObject::wxGraphicsObject() -{ -} - -wxGraphicsObject::wxGraphicsObject( wxGraphicsRenderer* renderer ) -{ - SetRefData( new wxGraphicsObjectRefData(renderer)); -} - -wxGraphicsObject::~wxGraphicsObject() -{ -} - -bool wxGraphicsObject::IsNull() const -{ - return m_refData == NULL; -} - -wxGraphicsRenderer* wxGraphicsObject::GetRenderer() const -{ - return ( IsNull() ? NULL : GetGraphicsData()->GetRenderer() ); -} - -wxGraphicsObjectRefData* wxGraphicsObject::GetGraphicsData() const -{ - return (wxGraphicsObjectRefData*) m_refData; -} - -wxObjectRefData* wxGraphicsObject::CreateRefData() const -{ - wxLogDebug(wxT("A Null Object cannot be changed")); - return NULL; -} - -wxObjectRefData* wxGraphicsObject::CloneRefData(const wxObjectRefData* data) const -{ - const wxGraphicsObjectRefData* ptr = (const wxGraphicsObjectRefData*) data; - return ptr->Clone(); -} - -//----------------------------------------------------------------------------- -// pens etc. -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGraphicsPen, wxGraphicsObject) -IMPLEMENT_DYNAMIC_CLASS(wxGraphicsBrush, wxGraphicsObject) -IMPLEMENT_DYNAMIC_CLASS(wxGraphicsFont, wxGraphicsObject) -IMPLEMENT_DYNAMIC_CLASS(wxGraphicsBitmap, wxGraphicsObject) - -WXDLLIMPEXP_DATA_CORE(wxGraphicsPen) wxNullGraphicsPen; -WXDLLIMPEXP_DATA_CORE(wxGraphicsBrush) wxNullGraphicsBrush; -WXDLLIMPEXP_DATA_CORE(wxGraphicsFont) wxNullGraphicsFont; -WXDLLIMPEXP_DATA_CORE(wxGraphicsBitmap) wxNullGraphicsBitmap; - -//----------------------------------------------------------------------------- -// matrix -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGraphicsMatrix, wxGraphicsObject) -WXDLLIMPEXP_DATA_CORE(wxGraphicsMatrix) wxNullGraphicsMatrix; - -// concatenates the matrix -void wxGraphicsMatrix::Concat( const wxGraphicsMatrix *t ) -{ - AllocExclusive(); - GetMatrixData()->Concat(t->GetMatrixData()); -} - -// sets the matrix to the respective values -void wxGraphicsMatrix::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d, - wxDouble tx, wxDouble ty) -{ - AllocExclusive(); - GetMatrixData()->Set(a,b,c,d,tx,ty); -} - -// gets the component valuess of the matrix -void wxGraphicsMatrix::Get(wxDouble* a, wxDouble* b, wxDouble* c, - wxDouble* d, wxDouble* tx, wxDouble* ty) const -{ - GetMatrixData()->Get(a, b, c, d, tx, ty); -} - -// makes this the inverse matrix -void wxGraphicsMatrix::Invert() -{ - AllocExclusive(); - GetMatrixData()->Invert(); -} - -// returns true if the elements of the transformation matrix are equal ? -bool wxGraphicsMatrix::IsEqual( const wxGraphicsMatrix* t) const -{ - return GetMatrixData()->IsEqual(t->GetMatrixData()); -} - -// return true if this is the identity matrix -bool wxGraphicsMatrix::IsIdentity() const -{ - return GetMatrixData()->IsIdentity(); -} - -// add the translation to this matrix -void wxGraphicsMatrix::Translate( wxDouble dx , wxDouble dy ) -{ - AllocExclusive(); - GetMatrixData()->Translate(dx,dy); -} - -// add the scale to this matrix -void wxGraphicsMatrix::Scale( wxDouble xScale , wxDouble yScale ) -{ - AllocExclusive(); - GetMatrixData()->Scale(xScale,yScale); -} - -// add the rotation to this matrix (radians) -void wxGraphicsMatrix::Rotate( wxDouble angle ) -{ - AllocExclusive(); - GetMatrixData()->Rotate(angle); -} - -// -// apply the transforms -// - -// applies that matrix to the point -void wxGraphicsMatrix::TransformPoint( wxDouble *x, wxDouble *y ) const -{ - GetMatrixData()->TransformPoint(x,y); -} - -// applies the matrix except for translations -void wxGraphicsMatrix::TransformDistance( wxDouble *dx, wxDouble *dy ) const -{ - GetMatrixData()->TransformDistance(dx,dy); -} - -// returns the native representation -void * wxGraphicsMatrix::GetNativeMatrix() const -{ - return GetMatrixData()->GetNativeMatrix(); -} - -//----------------------------------------------------------------------------- -// path -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxGraphicsPath, wxGraphicsObject) -WXDLLIMPEXP_DATA_CORE(wxGraphicsPath) wxNullGraphicsPath; - -// convenience functions, for using wxPoint2DDouble etc - -wxPoint2DDouble wxGraphicsPath::GetCurrentPoint() const -{ - wxDouble x,y; - GetCurrentPoint(&x,&y); - return wxPoint2DDouble(x,y); -} - -void wxGraphicsPath::MoveToPoint( const wxPoint2DDouble& p) -{ - MoveToPoint( p.m_x , p.m_y); -} - -void wxGraphicsPath::AddLineToPoint( const wxPoint2DDouble& p) -{ - AddLineToPoint( p.m_x , p.m_y); -} - -void wxGraphicsPath::AddCurveToPoint( const wxPoint2DDouble& c1, const wxPoint2DDouble& c2, const wxPoint2DDouble& e) -{ - AddCurveToPoint(c1.m_x, c1.m_y, c2.m_x, c2.m_y, e.m_x, e.m_y); -} - -void wxGraphicsPath::AddArc( const wxPoint2DDouble& c, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise) -{ - AddArc(c.m_x, c.m_y, r, startAngle, endAngle, clockwise); -} - -wxRect2DDouble wxGraphicsPath::GetBox() const -{ - wxDouble x,y,w,h; - GetBox(&x,&y,&w,&h); - return wxRect2DDouble( x,y,w,h ); -} - -bool wxGraphicsPath::Contains( const wxPoint2DDouble& c, int fillStyle ) const -{ - return Contains( c.m_x, c.m_y, fillStyle); -} - -// true redirections - -// begins a new subpath at (x,y) -void wxGraphicsPath::MoveToPoint( wxDouble x, wxDouble y ) -{ - AllocExclusive(); - GetPathData()->MoveToPoint(x,y); -} - -// adds a straight line from the current point to (x,y) -void wxGraphicsPath::AddLineToPoint( wxDouble x, wxDouble y ) -{ - AllocExclusive(); - GetPathData()->AddLineToPoint(x,y); -} - -// adds a cubic Bezier curve from the current point, using two control points and an end point -void wxGraphicsPath::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y ) -{ - AllocExclusive(); - GetPathData()->AddCurveToPoint(cx1,cy1,cx2,cy2,x,y); -} - -// adds another path -void wxGraphicsPath::AddPath( const wxGraphicsPath& path ) -{ - AllocExclusive(); - GetPathData()->AddPath(path.GetPathData()); -} - -// closes the current sub-path -void wxGraphicsPath::CloseSubpath() -{ - AllocExclusive(); - GetPathData()->CloseSubpath(); -} - -// gets the last point of the current path, (0,0) if not yet set -void wxGraphicsPath::GetCurrentPoint( wxDouble* x, wxDouble* y) const -{ - GetPathData()->GetCurrentPoint(x,y); -} - -// adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle -void wxGraphicsPath::AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise ) -{ - AllocExclusive(); - GetPathData()->AddArc(x,y,r,startAngle,endAngle,clockwise); -} - -// -// These are convenience functions which - if not available natively will be assembled -// using the primitives from above -// - -// adds a quadratic Bezier curve from the current point, using a control point and an end point -void wxGraphicsPath::AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y ) -{ - AllocExclusive(); - GetPathData()->AddQuadCurveToPoint(cx,cy,x,y); -} - -// appends a rectangle as a new closed subpath -void wxGraphicsPath::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) -{ - AllocExclusive(); - GetPathData()->AddRectangle(x,y,w,h); -} - -// appends an ellipsis as a new closed subpath fitting the passed rectangle -void wxGraphicsPath::AddCircle( wxDouble x, wxDouble y, wxDouble r ) -{ - AllocExclusive(); - GetPathData()->AddCircle(x,y,r); -} - -// appends a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1) -void wxGraphicsPath::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) -{ - GetPathData()->AddArcToPoint(x1,y1,x2,y2,r); -} - -// appends an ellipse -void wxGraphicsPath::AddEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h) -{ - AllocExclusive(); - GetPathData()->AddEllipse(x,y,w,h); -} - -// appends a rounded rectangle -void wxGraphicsPath::AddRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius) -{ - AllocExclusive(); - GetPathData()->AddRoundedRectangle(x,y,w,h,radius); -} - -// returns the native path -void * wxGraphicsPath::GetNativePath() const -{ - return GetPathData()->GetNativePath(); -} - -// give the native path returned by GetNativePath() back (there might be some deallocations necessary) -void wxGraphicsPath::UnGetNativePath(void *p)const -{ - GetPathData()->UnGetNativePath(p); -} - -// transforms each point of this path by the matrix -void wxGraphicsPath::Transform( const wxGraphicsMatrix& matrix ) -{ - AllocExclusive(); - GetPathData()->Transform(matrix.GetMatrixData()); -} - -// gets the bounding box enclosing all points (possibly including control points) -void wxGraphicsPath::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const -{ - GetPathData()->GetBox(x,y,w,h); -} - -bool wxGraphicsPath::Contains( wxDouble x, wxDouble y, int fillStyle ) const -{ - return GetPathData()->Contains(x,y,fillStyle); -} - -// -// Emulations, these mus be implemented in the ...Data classes in order to allow for proper overrides -// - -void wxGraphicsPathData::AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y ) -{ - // calculate using degree elevation to a cubic bezier - wxPoint2DDouble c1; - wxPoint2DDouble c2; - - wxPoint2DDouble start; - GetCurrentPoint(&start.m_x,&start.m_y); - wxPoint2DDouble end(x,y); - wxPoint2DDouble c(cx,cy); - c1 = wxDouble(1/3.0) * start + wxDouble(2/3.0) * c; - c2 = wxDouble(2/3.0) * c + wxDouble(1/3.0) * end; - AddCurveToPoint(c1.m_x,c1.m_y,c2.m_x,c2.m_y,x,y); -} - -void wxGraphicsPathData::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) -{ - MoveToPoint(x,y); - AddLineToPoint(x,y+h); - AddLineToPoint(x+w,y+h); - AddLineToPoint(x+w,y); - CloseSubpath(); -} - -void wxGraphicsPathData::AddCircle( wxDouble x, wxDouble y, wxDouble r ) -{ - MoveToPoint(x+r,y); - AddArc( x,y,r,0,2*M_PI,false); - CloseSubpath(); -} - -void wxGraphicsPathData::AddEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h) -{ - wxDouble rw = w/2; - wxDouble rh = h/2; - wxDouble xc = x + rw; - wxDouble yc = y + rh; - wxGraphicsMatrix m = GetRenderer()->CreateMatrix(); - m.Translate(xc,yc); - m.Scale(rw/rh,1.0); - wxGraphicsPath p = GetRenderer()->CreatePath(); - p.AddCircle(0,0,rh); - p.Transform(m); - AddPath(p.GetPathData()); -} - -void wxGraphicsPathData::AddRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius) -{ - if ( radius == 0 ) - AddRectangle(x,y,w,h); - else - { - MoveToPoint( x + w, y + h / 2); - AddArcToPoint(x + w, y + h, x + w / 2, y + h, radius); - AddArcToPoint(x, y + h, x, y + h / 2, radius); - AddArcToPoint(x, y , x + w / 2, y, radius); - AddArcToPoint(x + w, y, x + w, y + h / 2, radius); - CloseSubpath(); - } -} - -// draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1) -void wxGraphicsPathData::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) -{ - wxPoint2DDouble current; - GetCurrentPoint(¤t.m_x,¤t.m_y); - wxPoint2DDouble p1(x1,y1); - wxPoint2DDouble p2(x2,y2); - - wxPoint2DDouble v1 = current - p1; - v1.Normalize(); - wxPoint2DDouble v2 = p2 - p1; - v2.Normalize(); - - wxDouble alpha = v1.GetVectorAngle() - v2.GetVectorAngle(); - - if ( alpha < 0 ) - alpha = 360 + alpha; - // TODO obtuse angles - - alpha = DegToRad(alpha); - - wxDouble dist = r / sin(alpha/2) * cos(alpha/2); - // calculate tangential points - wxPoint2DDouble t1 = dist*v1 + p1; - wxPoint2DDouble t2 = dist*v2 + p1; - - wxPoint2DDouble nv1 = v1; - nv1.SetVectorAngle(v1.GetVectorAngle()-90); - wxPoint2DDouble c = t1 + r*nv1; - - wxDouble a1 = v1.GetVectorAngle()+90; - wxDouble a2 = v2.GetVectorAngle()-90; - - AddLineToPoint(t1.m_x,t1.m_y); - AddArc(c.m_x,c.m_y,r,DegToRad(a1),DegToRad(a2),true); - AddLineToPoint(p2.m_x,p2.m_y); -} - -//----------------------------------------------------------------------------- -// wxGraphicsContext Convenience Methods -//----------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxGraphicsContext, wxObject) - - -wxGraphicsContext::wxGraphicsContext(wxGraphicsRenderer* renderer) : wxGraphicsObject(renderer) -{ - m_logicalFunction = wxCOPY; -} - -wxGraphicsContext::~wxGraphicsContext() -{ -} - -// sets the pen -void wxGraphicsContext::SetPen( const wxGraphicsPen& pen ) -{ - m_pen = pen; -} - -void wxGraphicsContext::SetPen( const wxPen& pen ) -{ - if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT ) - SetPen( wxNullGraphicsPen ); - else - SetPen( CreatePen( pen ) ); -} - -// sets the brush for filling -void wxGraphicsContext::SetBrush( const wxGraphicsBrush& brush ) -{ - m_brush = brush; -} - -void wxGraphicsContext::SetBrush( const wxBrush& brush ) -{ - if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT ) - SetBrush( wxNullGraphicsBrush ); - else - SetBrush( CreateBrush( brush ) ); -} - -// sets the brush for filling -void wxGraphicsContext::SetFont( const wxGraphicsFont& font ) -{ - m_font = font; -} - -bool wxGraphicsContext::SetLogicalFunction( int function ) -{ - if ( function == wxCOPY ) - { - m_logicalFunction = function; - return true; - } - return false; -} - -void wxGraphicsContext::SetFont( const wxFont& font, const wxColour& colour ) -{ - if ( font.Ok() ) - SetFont( CreateFont( font, colour ) ); - else - SetFont( wxNullGraphicsFont ); -} - -void wxGraphicsContext::DrawPath( const wxGraphicsPath& path, int fillStyle ) -{ - FillPath( path , fillStyle ); - StrokePath( path ); -} - -void wxGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle ) -{ - Translate(x,y); - Rotate( -angle ); - DrawText( str , 0, 0 ); - Rotate( angle ); - Translate(-x,-y); -} - -void wxGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, const wxGraphicsBrush& backgroundBrush ) -{ - wxGraphicsBrush formerBrush = m_brush; - wxGraphicsPen formerPen = m_pen; - wxDouble width; - wxDouble height; - wxDouble descent; - wxDouble externalLeading; - GetTextExtent( str , &width, &height, &descent, &externalLeading ); - SetBrush( backgroundBrush ); - // to make sure our 'OffsetToPixelBoundaries' doesn't move the fill shape - SetPen( wxNullGraphicsPen ); - - wxGraphicsPath path = CreatePath(); - path.AddRectangle( x , y, width, height ); - FillPath( path ); - - DrawText( str, x ,y); - SetBrush( formerBrush ); - SetPen( formerPen ); -} - -void wxGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle, const wxGraphicsBrush& backgroundBrush ) -{ - wxGraphicsBrush formerBrush = m_brush; - wxGraphicsPen formerPen = m_pen; - - wxDouble width; - wxDouble height; - wxDouble descent; - wxDouble externalLeading; - GetTextExtent( str , &width, &height, &descent, &externalLeading ); - SetBrush( backgroundBrush ); - // to make sure our 'OffsetToPixelBoundaries' doesn't move the fill shape - SetPen( wxNullGraphicsPen ); - - wxGraphicsPath path = CreatePath(); - path.MoveToPoint( x , y ); - path.AddLineToPoint( (int) (x + sin(angle) * height) , (int) (y + cos(angle) * height) ); - path.AddLineToPoint( - (int) (x + sin(angle) * height + cos(angle) * width) , - (int) (y + cos(angle) * height - sin(angle) * width)); - path.AddLineToPoint((int) (x + cos(angle) * width) , (int) (y - sin(angle) * width) ); - FillPath( path ); - DrawText( str, x ,y, angle); - SetBrush( formerBrush ); - SetPen( formerPen ); -} - -void wxGraphicsContext::StrokeLine( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2) -{ - wxGraphicsPath path = CreatePath(); - path.MoveToPoint(x1, y1); - path.AddLineToPoint( x2, y2 ); - StrokePath( path ); -} - -void wxGraphicsContext::DrawRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h) -{ - wxGraphicsPath path = CreatePath(); - path.AddRectangle( x , y , w , h ); - DrawPath( path ); -} - -void wxGraphicsContext::DrawEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h) -{ - wxGraphicsPath path = CreatePath(); - path.AddEllipse(x,y,w,h); - DrawPath(path); -} - -void wxGraphicsContext::DrawRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius) -{ - wxGraphicsPath path = CreatePath(); - path.AddRoundedRectangle(x,y,w,h,radius); - DrawPath(path); -} - -void wxGraphicsContext::StrokeLines( size_t n, const wxPoint2DDouble *points) -{ - wxASSERT(n > 1); - wxGraphicsPath path = CreatePath(); - path.MoveToPoint(points[0].m_x, points[0].m_y); - for ( size_t i = 1; i < n; ++i) - path.AddLineToPoint( points[i].m_x, points[i].m_y ); - StrokePath( path ); -} - -void wxGraphicsContext::DrawLines( size_t n, const wxPoint2DDouble *points, int fillStyle) -{ - wxASSERT(n > 1); - wxGraphicsPath path = CreatePath(); - path.MoveToPoint(points[0].m_x, points[0].m_y); - for ( size_t i = 1; i < n; ++i) - path.AddLineToPoint( points[i].m_x, points[i].m_y ); - DrawPath( path , fillStyle); -} - -void wxGraphicsContext::StrokeLines( size_t n, const wxPoint2DDouble *beginPoints, const wxPoint2DDouble *endPoints) -{ - wxASSERT(n > 0); - wxGraphicsPath path = CreatePath(); - for ( size_t i = 0; i < n; ++i) - { - path.MoveToPoint(beginPoints[i].m_x, beginPoints[i].m_y); - path.AddLineToPoint( endPoints[i].m_x, endPoints[i].m_y ); - } - StrokePath( path ); -} - -// create a 'native' matrix corresponding to these values -wxGraphicsMatrix wxGraphicsContext::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d, - wxDouble tx, wxDouble ty) const -{ - return GetRenderer()->CreateMatrix(a,b,c,d,tx,ty); -} - -wxGraphicsPath wxGraphicsContext::CreatePath() const -{ - return GetRenderer()->CreatePath(); -} - -wxGraphicsPen wxGraphicsContext::CreatePen(const wxPen& pen) const -{ - return GetRenderer()->CreatePen(pen); -} - -wxGraphicsBrush wxGraphicsContext::CreateBrush(const wxBrush& brush ) const -{ - return GetRenderer()->CreateBrush(brush); -} - -// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 -wxGraphicsBrush wxGraphicsContext::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, - const wxColour&c1, const wxColour&c2) const -{ - return GetRenderer()->CreateLinearGradientBrush(x1,y1,x2,y2,c1,c2); -} - -// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) -// with radius r and color cColor -wxGraphicsBrush wxGraphicsContext::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, - const wxColour &oColor, const wxColour &cColor) const -{ - return GetRenderer()->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor); -} - -// sets the font -wxGraphicsFont wxGraphicsContext::CreateFont( const wxFont &font , const wxColour &col ) const -{ - return GetRenderer()->CreateFont(font,col); -} - -wxGraphicsBitmap wxGraphicsContext::CreateBitmap( const wxBitmap& bmp ) const -{ - return GetRenderer()->CreateBitmap(bmp); -} - -wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC& dc) -{ - return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(dc); -} -#ifdef __WXMSW__ -wxGraphicsContext* wxGraphicsContext::Create( const wxMemoryDC& dc) -{ - return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(dc); -} -#endif - -wxGraphicsContext* wxGraphicsContext::CreateFromNative( void * context ) -{ - return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromNativeContext(context); -} - -wxGraphicsContext* wxGraphicsContext::CreateFromNativeWindow( void * window ) -{ - return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromNativeWindow(window); -} - -wxGraphicsContext* wxGraphicsContext::Create( wxWindow* window ) -{ - return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(window); -} - -wxGraphicsContext* wxGraphicsContext::Create() -{ - return wxGraphicsRenderer::GetDefaultRenderer()->CreateMeasuringContext(); -} - -//----------------------------------------------------------------------------- -// wxGraphicsRenderer -//----------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxGraphicsRenderer, wxObject) - -#endif // wxUSE_GRAPHICS_CONTEXT +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/graphcmn.cpp +// Purpose: graphics context methods common to all platforms +// Author: Stefan Csomor +// Modified by: +// Created: +// RCS-ID: $Id: graphcmn.cpp 56801 2008-11-16 23:25:09Z KO $ +// Copyright: (c) Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#if wxUSE_GRAPHICS_CONTEXT + +#include "wx/graphics.h" + +#ifndef WX_PRECOMP + #include "wx/icon.h" + #include "wx/bitmap.h" + #include "wx/dcmemory.h" + #include "wx/region.h" + #include "wx/log.h" +#endif + +#if !defined(wxMAC_USE_CORE_GRAPHICS_BLEND_MODES) +#define wxMAC_USE_CORE_GRAPHICS_BLEND_MODES 0 +#endif + +//----------------------------------------------------------------------------- +// constants +//----------------------------------------------------------------------------- + +static const double RAD2DEG = 180.0 / M_PI; + +//----------------------------------------------------------------------------- +// Local functions +//----------------------------------------------------------------------------- + +static inline double DegToRad(double deg) +{ + return (deg * M_PI) / 180.0; +} + +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// wxGraphicsObject +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGraphicsObject, wxObject) + +wxGraphicsObjectRefData::wxGraphicsObjectRefData( wxGraphicsRenderer* renderer ) +{ + m_renderer = renderer; +} +wxGraphicsObjectRefData::wxGraphicsObjectRefData( const wxGraphicsObjectRefData* data ) +{ + m_renderer = data->m_renderer; +} +wxGraphicsRenderer* wxGraphicsObjectRefData::GetRenderer() const +{ + return m_renderer ; +} + +wxGraphicsObjectRefData* wxGraphicsObjectRefData::Clone() const +{ + return new wxGraphicsObjectRefData(this); +} + +wxGraphicsObject::wxGraphicsObject() +{ +} + +wxGraphicsObject::wxGraphicsObject( wxGraphicsRenderer* renderer ) +{ + SetRefData( new wxGraphicsObjectRefData(renderer)); +} + +wxGraphicsObject::~wxGraphicsObject() +{ +} + +bool wxGraphicsObject::IsNull() const +{ + return m_refData == NULL; +} + +wxGraphicsRenderer* wxGraphicsObject::GetRenderer() const +{ + return ( IsNull() ? NULL : GetGraphicsData()->GetRenderer() ); +} + +wxGraphicsObjectRefData* wxGraphicsObject::GetGraphicsData() const +{ + return (wxGraphicsObjectRefData*) m_refData; +} + +wxObjectRefData* wxGraphicsObject::CreateRefData() const +{ + wxLogDebug(wxT("A Null Object cannot be changed")); + return NULL; +} + +wxObjectRefData* wxGraphicsObject::CloneRefData(const wxObjectRefData* data) const +{ + const wxGraphicsObjectRefData* ptr = (const wxGraphicsObjectRefData*) data; + return ptr->Clone(); +} + +//----------------------------------------------------------------------------- +// pens etc. +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGraphicsPen, wxGraphicsObject) +IMPLEMENT_DYNAMIC_CLASS(wxGraphicsBrush, wxGraphicsObject) +IMPLEMENT_DYNAMIC_CLASS(wxGraphicsFont, wxGraphicsObject) +IMPLEMENT_DYNAMIC_CLASS(wxGraphicsBitmap, wxGraphicsObject) + +WXDLLIMPEXP_DATA_CORE(wxGraphicsPen) wxNullGraphicsPen; +WXDLLIMPEXP_DATA_CORE(wxGraphicsBrush) wxNullGraphicsBrush; +WXDLLIMPEXP_DATA_CORE(wxGraphicsFont) wxNullGraphicsFont; +WXDLLIMPEXP_DATA_CORE(wxGraphicsBitmap) wxNullGraphicsBitmap; + +//----------------------------------------------------------------------------- +// matrix +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGraphicsMatrix, wxGraphicsObject) +WXDLLIMPEXP_DATA_CORE(wxGraphicsMatrix) wxNullGraphicsMatrix; + +// concatenates the matrix +void wxGraphicsMatrix::Concat( const wxGraphicsMatrix *t ) +{ + AllocExclusive(); + GetMatrixData()->Concat(t->GetMatrixData()); +} + +// sets the matrix to the respective values +void wxGraphicsMatrix::Set(wxDouble a, wxDouble b, wxDouble c, wxDouble d, + wxDouble tx, wxDouble ty) +{ + AllocExclusive(); + GetMatrixData()->Set(a,b,c,d,tx,ty); +} + +// gets the component valuess of the matrix +void wxGraphicsMatrix::Get(wxDouble* a, wxDouble* b, wxDouble* c, + wxDouble* d, wxDouble* tx, wxDouble* ty) const +{ + GetMatrixData()->Get(a, b, c, d, tx, ty); +} + +// makes this the inverse matrix +void wxGraphicsMatrix::Invert() +{ + AllocExclusive(); + GetMatrixData()->Invert(); +} + +// returns true if the elements of the transformation matrix are equal ? +bool wxGraphicsMatrix::IsEqual( const wxGraphicsMatrix* t) const +{ + return GetMatrixData()->IsEqual(t->GetMatrixData()); +} + +// return true if this is the identity matrix +bool wxGraphicsMatrix::IsIdentity() const +{ + return GetMatrixData()->IsIdentity(); +} + +// add the translation to this matrix +void wxGraphicsMatrix::Translate( wxDouble dx , wxDouble dy ) +{ + AllocExclusive(); + GetMatrixData()->Translate(dx,dy); +} + +// add the scale to this matrix +void wxGraphicsMatrix::Scale( wxDouble xScale , wxDouble yScale ) +{ + AllocExclusive(); + GetMatrixData()->Scale(xScale,yScale); +} + +// add the rotation to this matrix (radians) +void wxGraphicsMatrix::Rotate( wxDouble angle ) +{ + AllocExclusive(); + GetMatrixData()->Rotate(angle); +} + +// +// apply the transforms +// + +// applies that matrix to the point +void wxGraphicsMatrix::TransformPoint( wxDouble *x, wxDouble *y ) const +{ + GetMatrixData()->TransformPoint(x,y); +} + +// applies the matrix except for translations +void wxGraphicsMatrix::TransformDistance( wxDouble *dx, wxDouble *dy ) const +{ + GetMatrixData()->TransformDistance(dx,dy); +} + +// returns the native representation +void * wxGraphicsMatrix::GetNativeMatrix() const +{ + return GetMatrixData()->GetNativeMatrix(); +} + +//----------------------------------------------------------------------------- +// path +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxGraphicsPath, wxGraphicsObject) +WXDLLIMPEXP_DATA_CORE(wxGraphicsPath) wxNullGraphicsPath; + +// convenience functions, for using wxPoint2DDouble etc + +wxPoint2DDouble wxGraphicsPath::GetCurrentPoint() const +{ + wxDouble x,y; + GetCurrentPoint(&x,&y); + return wxPoint2DDouble(x,y); +} + +void wxGraphicsPath::MoveToPoint( const wxPoint2DDouble& p) +{ + MoveToPoint( p.m_x , p.m_y); +} + +void wxGraphicsPath::AddLineToPoint( const wxPoint2DDouble& p) +{ + AddLineToPoint( p.m_x , p.m_y); +} + +void wxGraphicsPath::AddCurveToPoint( const wxPoint2DDouble& c1, const wxPoint2DDouble& c2, const wxPoint2DDouble& e) +{ + AddCurveToPoint(c1.m_x, c1.m_y, c2.m_x, c2.m_y, e.m_x, e.m_y); +} + +void wxGraphicsPath::AddArc( const wxPoint2DDouble& c, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise) +{ + AddArc(c.m_x, c.m_y, r, startAngle, endAngle, clockwise); +} + +wxRect2DDouble wxGraphicsPath::GetBox() const +{ + wxDouble x,y,w,h; + GetBox(&x,&y,&w,&h); + return wxRect2DDouble( x,y,w,h ); +} + +bool wxGraphicsPath::Contains( const wxPoint2DDouble& c, int fillStyle ) const +{ + return Contains( c.m_x, c.m_y, fillStyle); +} + +// true redirections + +// begins a new subpath at (x,y) +void wxGraphicsPath::MoveToPoint( wxDouble x, wxDouble y ) +{ + AllocExclusive(); + GetPathData()->MoveToPoint(x,y); +} + +// adds a straight line from the current point to (x,y) +void wxGraphicsPath::AddLineToPoint( wxDouble x, wxDouble y ) +{ + AllocExclusive(); + GetPathData()->AddLineToPoint(x,y); +} + +// adds a cubic Bezier curve from the current point, using two control points and an end point +void wxGraphicsPath::AddCurveToPoint( wxDouble cx1, wxDouble cy1, wxDouble cx2, wxDouble cy2, wxDouble x, wxDouble y ) +{ + AllocExclusive(); + GetPathData()->AddCurveToPoint(cx1,cy1,cx2,cy2,x,y); +} + +// adds another path +void wxGraphicsPath::AddPath( const wxGraphicsPath& path ) +{ + AllocExclusive(); + GetPathData()->AddPath(path.GetPathData()); +} + +// closes the current sub-path +void wxGraphicsPath::CloseSubpath() +{ + AllocExclusive(); + GetPathData()->CloseSubpath(); +} + +// gets the last point of the current path, (0,0) if not yet set +void wxGraphicsPath::GetCurrentPoint( wxDouble* x, wxDouble* y) const +{ + GetPathData()->GetCurrentPoint(x,y); +} + +// adds an arc of a circle centering at (x,y) with radius (r) from startAngle to endAngle +void wxGraphicsPath::AddArc( wxDouble x, wxDouble y, wxDouble r, wxDouble startAngle, wxDouble endAngle, bool clockwise ) +{ + AllocExclusive(); + GetPathData()->AddArc(x,y,r,startAngle,endAngle,clockwise); +} + +// +// These are convenience functions which - if not available natively will be assembled +// using the primitives from above +// + +// adds a quadratic Bezier curve from the current point, using a control point and an end point +void wxGraphicsPath::AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y ) +{ + AllocExclusive(); + GetPathData()->AddQuadCurveToPoint(cx,cy,x,y); +} + +// appends a rectangle as a new closed subpath +void wxGraphicsPath::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) +{ + AllocExclusive(); + GetPathData()->AddRectangle(x,y,w,h); +} + +// appends an ellipsis as a new closed subpath fitting the passed rectangle +void wxGraphicsPath::AddCircle( wxDouble x, wxDouble y, wxDouble r ) +{ + AllocExclusive(); + GetPathData()->AddCircle(x,y,r); +} + +// appends a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1) +void wxGraphicsPath::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) +{ + GetPathData()->AddArcToPoint(x1,y1,x2,y2,r); +} + +// appends an ellipse +void wxGraphicsPath::AddEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h) +{ + AllocExclusive(); + GetPathData()->AddEllipse(x,y,w,h); +} + +// appends a rounded rectangle +void wxGraphicsPath::AddRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius) +{ + AllocExclusive(); + GetPathData()->AddRoundedRectangle(x,y,w,h,radius); +} + +// returns the native path +void * wxGraphicsPath::GetNativePath() const +{ + return GetPathData()->GetNativePath(); +} + +// give the native path returned by GetNativePath() back (there might be some deallocations necessary) +void wxGraphicsPath::UnGetNativePath(void *p)const +{ + GetPathData()->UnGetNativePath(p); +} + +// transforms each point of this path by the matrix +void wxGraphicsPath::Transform( const wxGraphicsMatrix& matrix ) +{ + AllocExclusive(); + GetPathData()->Transform(matrix.GetMatrixData()); +} + +// gets the bounding box enclosing all points (possibly including control points) +void wxGraphicsPath::GetBox(wxDouble *x, wxDouble *y, wxDouble *w, wxDouble *h) const +{ + GetPathData()->GetBox(x,y,w,h); +} + +bool wxGraphicsPath::Contains( wxDouble x, wxDouble y, int fillStyle ) const +{ + return GetPathData()->Contains(x,y,fillStyle); +} + +// +// Emulations, these mus be implemented in the ...Data classes in order to allow for proper overrides +// + +void wxGraphicsPathData::AddQuadCurveToPoint( wxDouble cx, wxDouble cy, wxDouble x, wxDouble y ) +{ + // calculate using degree elevation to a cubic bezier + wxPoint2DDouble c1; + wxPoint2DDouble c2; + + wxPoint2DDouble start; + GetCurrentPoint(&start.m_x,&start.m_y); + wxPoint2DDouble end(x,y); + wxPoint2DDouble c(cx,cy); + c1 = wxDouble(1/3.0) * start + wxDouble(2/3.0) * c; + c2 = wxDouble(2/3.0) * c + wxDouble(1/3.0) * end; + AddCurveToPoint(c1.m_x,c1.m_y,c2.m_x,c2.m_y,x,y); +} + +void wxGraphicsPathData::AddRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h ) +{ + MoveToPoint(x,y); + AddLineToPoint(x,y+h); + AddLineToPoint(x+w,y+h); + AddLineToPoint(x+w,y); + CloseSubpath(); +} + +void wxGraphicsPathData::AddCircle( wxDouble x, wxDouble y, wxDouble r ) +{ + MoveToPoint(x+r,y); + AddArc( x,y,r,0,2*M_PI,false); + CloseSubpath(); +} + +void wxGraphicsPathData::AddEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h) +{ + wxDouble rw = w/2; + wxDouble rh = h/2; + wxDouble xc = x + rw; + wxDouble yc = y + rh; + wxGraphicsMatrix m = GetRenderer()->CreateMatrix(); + m.Translate(xc,yc); + m.Scale(rw/rh,1.0); + wxGraphicsPath p = GetRenderer()->CreatePath(); + p.AddCircle(0,0,rh); + p.Transform(m); + AddPath(p.GetPathData()); +} + +void wxGraphicsPathData::AddRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius) +{ + if ( radius == 0 ) + AddRectangle(x,y,w,h); + else + { + MoveToPoint( x + w, y + h / 2); + AddArcToPoint(x + w, y + h, x + w / 2, y + h, radius); + AddArcToPoint(x, y + h, x, y + h / 2, radius); + AddArcToPoint(x, y , x + w / 2, y, radius); + AddArcToPoint(x + w, y, x + w, y + h / 2, radius); + CloseSubpath(); + } +} + +// draws a an arc to two tangents connecting (current) to (x1,y1) and (x1,y1) to (x2,y2), also a straight line from (current) to (x1,y1) +void wxGraphicsPathData::AddArcToPoint( wxDouble x1, wxDouble y1 , wxDouble x2, wxDouble y2, wxDouble r ) +{ + wxPoint2DDouble current; + GetCurrentPoint(¤t.m_x,¤t.m_y); + wxPoint2DDouble p1(x1,y1); + wxPoint2DDouble p2(x2,y2); + + wxPoint2DDouble v1 = current - p1; + v1.Normalize(); + wxPoint2DDouble v2 = p2 - p1; + v2.Normalize(); + + wxDouble alpha = v1.GetVectorAngle() - v2.GetVectorAngle(); + + if ( alpha < 0 ) + alpha = 360 + alpha; + // TODO obtuse angles + + alpha = DegToRad(alpha); + + wxDouble dist = r / sin(alpha/2) * cos(alpha/2); + // calculate tangential points + wxPoint2DDouble t1 = dist*v1 + p1; + wxPoint2DDouble t2 = dist*v2 + p1; + + wxPoint2DDouble nv1 = v1; + nv1.SetVectorAngle(v1.GetVectorAngle()-90); + wxPoint2DDouble c = t1 + r*nv1; + + wxDouble a1 = v1.GetVectorAngle()+90; + wxDouble a2 = v2.GetVectorAngle()-90; + + AddLineToPoint(t1.m_x,t1.m_y); + AddArc(c.m_x,c.m_y,r,DegToRad(a1),DegToRad(a2),true); + AddLineToPoint(p2.m_x,p2.m_y); +} + +//----------------------------------------------------------------------------- +// wxGraphicsContext Convenience Methods +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxGraphicsContext, wxObject) + + +wxGraphicsContext::wxGraphicsContext(wxGraphicsRenderer* renderer) : wxGraphicsObject(renderer) +{ + m_logicalFunction = wxCOPY; +} + +wxGraphicsContext::~wxGraphicsContext() +{ +} + +// sets the pen +void wxGraphicsContext::SetPen( const wxGraphicsPen& pen ) +{ + m_pen = pen; +} + +void wxGraphicsContext::SetPen( const wxPen& pen ) +{ + if ( !pen.Ok() || pen.GetStyle() == wxTRANSPARENT ) + SetPen( wxNullGraphicsPen ); + else + SetPen( CreatePen( pen ) ); +} + +// sets the brush for filling +void wxGraphicsContext::SetBrush( const wxGraphicsBrush& brush ) +{ + m_brush = brush; +} + +void wxGraphicsContext::SetBrush( const wxBrush& brush ) +{ + if ( !brush.Ok() || brush.GetStyle() == wxTRANSPARENT ) + SetBrush( wxNullGraphicsBrush ); + else + SetBrush( CreateBrush( brush ) ); +} + +// sets the brush for filling +void wxGraphicsContext::SetFont( const wxGraphicsFont& font ) +{ + m_font = font; +} + +bool wxGraphicsContext::SetLogicalFunction( int function ) +{ + if ( function == wxCOPY ) + { + m_logicalFunction = function; + return true; + } + return false; +} + +void wxGraphicsContext::SetFont( const wxFont& font, const wxColour& colour ) +{ + if ( font.Ok() ) + SetFont( CreateFont( font, colour ) ); + else + SetFont( wxNullGraphicsFont ); +} + +void wxGraphicsContext::DrawPath( const wxGraphicsPath& path, int fillStyle ) +{ + FillPath( path , fillStyle ); + StrokePath( path ); +} + +void wxGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle ) +{ + Translate(x,y); + Rotate( -angle ); + DrawText( str , 0, 0 ); + Rotate( angle ); + Translate(-x,-y); +} + +void wxGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, const wxGraphicsBrush& backgroundBrush ) +{ + wxGraphicsBrush formerBrush = m_brush; + wxGraphicsPen formerPen = m_pen; + wxDouble width; + wxDouble height; + wxDouble descent; + wxDouble externalLeading; + GetTextExtent( str , &width, &height, &descent, &externalLeading ); + SetBrush( backgroundBrush ); + // to make sure our 'OffsetToPixelBoundaries' doesn't move the fill shape + SetPen( wxNullGraphicsPen ); + + wxGraphicsPath path = CreatePath(); + path.AddRectangle( x , y, width, height ); + FillPath( path ); + + DrawText( str, x ,y); + SetBrush( formerBrush ); + SetPen( formerPen ); +} + +void wxGraphicsContext::DrawText( const wxString &str, wxDouble x, wxDouble y, wxDouble angle, const wxGraphicsBrush& backgroundBrush ) +{ + wxGraphicsBrush formerBrush = m_brush; + wxGraphicsPen formerPen = m_pen; + + wxDouble width; + wxDouble height; + wxDouble descent; + wxDouble externalLeading; + GetTextExtent( str , &width, &height, &descent, &externalLeading ); + SetBrush( backgroundBrush ); + // to make sure our 'OffsetToPixelBoundaries' doesn't move the fill shape + SetPen( wxNullGraphicsPen ); + + wxGraphicsPath path = CreatePath(); + path.MoveToPoint( x , y ); + path.AddLineToPoint( (int) (x + sin(angle) * height) , (int) (y + cos(angle) * height) ); + path.AddLineToPoint( + (int) (x + sin(angle) * height + cos(angle) * width) , + (int) (y + cos(angle) * height - sin(angle) * width)); + path.AddLineToPoint((int) (x + cos(angle) * width) , (int) (y - sin(angle) * width) ); + FillPath( path ); + DrawText( str, x ,y, angle); + SetBrush( formerBrush ); + SetPen( formerPen ); +} + +void wxGraphicsContext::StrokeLine( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2) +{ + wxGraphicsPath path = CreatePath(); + path.MoveToPoint(x1, y1); + path.AddLineToPoint( x2, y2 ); + StrokePath( path ); +} + +void wxGraphicsContext::DrawRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h) +{ + wxGraphicsPath path = CreatePath(); + path.AddRectangle( x , y , w , h ); + DrawPath( path ); +} + +void wxGraphicsContext::DrawEllipse( wxDouble x, wxDouble y, wxDouble w, wxDouble h) +{ + wxGraphicsPath path = CreatePath(); + path.AddEllipse(x,y,w,h); + DrawPath(path); +} + +void wxGraphicsContext::DrawRoundedRectangle( wxDouble x, wxDouble y, wxDouble w, wxDouble h, wxDouble radius) +{ + wxGraphicsPath path = CreatePath(); + path.AddRoundedRectangle(x,y,w,h,radius); + DrawPath(path); +} + +void wxGraphicsContext::StrokeLines( size_t n, const wxPoint2DDouble *points) +{ + wxASSERT(n > 1); + wxGraphicsPath path = CreatePath(); + path.MoveToPoint(points[0].m_x, points[0].m_y); + for ( size_t i = 1; i < n; ++i) + path.AddLineToPoint( points[i].m_x, points[i].m_y ); + StrokePath( path ); +} + +void wxGraphicsContext::DrawLines( size_t n, const wxPoint2DDouble *points, int fillStyle) +{ + wxASSERT(n > 1); + wxGraphicsPath path = CreatePath(); + path.MoveToPoint(points[0].m_x, points[0].m_y); + for ( size_t i = 1; i < n; ++i) + path.AddLineToPoint( points[i].m_x, points[i].m_y ); + DrawPath( path , fillStyle); +} + +void wxGraphicsContext::StrokeLines( size_t n, const wxPoint2DDouble *beginPoints, const wxPoint2DDouble *endPoints) +{ + wxASSERT(n > 0); + wxGraphicsPath path = CreatePath(); + for ( size_t i = 0; i < n; ++i) + { + path.MoveToPoint(beginPoints[i].m_x, beginPoints[i].m_y); + path.AddLineToPoint( endPoints[i].m_x, endPoints[i].m_y ); + } + StrokePath( path ); +} + +// create a 'native' matrix corresponding to these values +wxGraphicsMatrix wxGraphicsContext::CreateMatrix( wxDouble a, wxDouble b, wxDouble c, wxDouble d, + wxDouble tx, wxDouble ty) const +{ + return GetRenderer()->CreateMatrix(a,b,c,d,tx,ty); +} + +wxGraphicsPath wxGraphicsContext::CreatePath() const +{ + return GetRenderer()->CreatePath(); +} + +wxGraphicsPen wxGraphicsContext::CreatePen(const wxPen& pen) const +{ + return GetRenderer()->CreatePen(pen); +} + +wxGraphicsBrush wxGraphicsContext::CreateBrush(const wxBrush& brush ) const +{ + return GetRenderer()->CreateBrush(brush); +} + +// sets the brush to a linear gradient, starting at (x1,y1) with color c1 to (x2,y2) with color c2 +wxGraphicsBrush wxGraphicsContext::CreateLinearGradientBrush( wxDouble x1, wxDouble y1, wxDouble x2, wxDouble y2, + const wxColour&c1, const wxColour&c2) const +{ + return GetRenderer()->CreateLinearGradientBrush(x1,y1,x2,y2,c1,c2); +} + +// sets the brush to a radial gradient originating at (xo,yc) with color oColor and ends on a circle around (xc,yc) +// with radius r and color cColor +wxGraphicsBrush wxGraphicsContext::CreateRadialGradientBrush( wxDouble xo, wxDouble yo, wxDouble xc, wxDouble yc, wxDouble radius, + const wxColour &oColor, const wxColour &cColor) const +{ + return GetRenderer()->CreateRadialGradientBrush(xo,yo,xc,yc,radius,oColor,cColor); +} + +// sets the font +wxGraphicsFont wxGraphicsContext::CreateFont( const wxFont &font , const wxColour &col ) const +{ + return GetRenderer()->CreateFont(font,col); +} + +wxGraphicsBitmap wxGraphicsContext::CreateBitmap( const wxBitmap& bmp ) const +{ + return GetRenderer()->CreateBitmap(bmp); +} + +wxGraphicsContext* wxGraphicsContext::Create( const wxWindowDC& dc) +{ + return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(dc); +} +#ifdef __WXMSW__ +wxGraphicsContext* wxGraphicsContext::Create( const wxMemoryDC& dc) +{ + return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(dc); +} +#endif + +wxGraphicsContext* wxGraphicsContext::CreateFromNative( void * context ) +{ + return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromNativeContext(context); +} + +wxGraphicsContext* wxGraphicsContext::CreateFromNativeWindow( void * window ) +{ + return wxGraphicsRenderer::GetDefaultRenderer()->CreateContextFromNativeWindow(window); +} + +wxGraphicsContext* wxGraphicsContext::Create( wxWindow* window ) +{ + return wxGraphicsRenderer::GetDefaultRenderer()->CreateContext(window); +} + +wxGraphicsContext* wxGraphicsContext::Create() +{ + return wxGraphicsRenderer::GetDefaultRenderer()->CreateMeasuringContext(); +} + +//----------------------------------------------------------------------------- +// wxGraphicsRenderer +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxGraphicsRenderer, wxObject) + +#endif // wxUSE_GRAPHICS_CONTEXT diff --git a/Source/3rd Party/wx/src/common/hash.cpp b/Source/3rd Party/wx/src/common/hash.cpp index 4fb13b438..9969bb188 100644 --- a/Source/3rd Party/wx/src/common/hash.cpp +++ b/Source/3rd Party/wx/src/common/hash.cpp @@ -1,1077 +1,1077 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/hash.cpp -// Purpose: wxHashTable implementation -// Author: Julian Smart -// Modified by: VZ at 25.02.00: type safe hashes with WX_DECLARE_HASH() -// Created: 01/02/97 -// RCS-ID: $Id: hash.cpp 49529 2007-10-30 00:32:18Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/list.h" - #include "wx/hash.h" -#endif - -#if wxUSE_OLD_HASH_TABLE - -#include -#include - -// ---------------------------------------------------------------------------- -// wxWin macros -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxHashTable, wxObject) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxHashTablleBase for working with "void *" data -// ---------------------------------------------------------------------------- - -wxHashTableBase::wxHashTableBase() -{ - m_deleteContents = false; - m_hashTable = (wxListBase **)NULL; - m_hashSize = 0; - m_count = 0; - m_keyType = wxKEY_NONE; -} - -void wxHashTableBase::Create(wxKeyType keyType, size_t size) -{ - Destroy(); - - m_hashSize = size; - m_keyType = keyType; - m_hashTable = new wxListBase *[size]; - for ( size_t n = 0; n < m_hashSize; n++ ) - { - m_hashTable[n] = (wxListBase *) NULL; - } -} - -void wxHashTableBase::Destroy() -{ - if ( m_hashTable ) - { - for ( size_t n = 0; n < m_hashSize; n++ ) - { - delete m_hashTable[n]; - } - - delete [] m_hashTable; - - m_hashTable = (wxListBase **)NULL; - - m_count = 0; - } -} - -void wxHashTableBase::DeleteContents(bool flag) -{ - m_deleteContents = flag; - for ( size_t n = 0; n < m_hashSize; n++ ) - { - if ( m_hashTable[n] ) - { - m_hashTable[n]->DeleteContents(flag); - } - } -} - -wxNodeBase *wxHashTableBase::GetNode(long key, long value) const -{ - size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); - - wxNodeBase *node; - if ( m_hashTable[slot] ) - { - node = m_hashTable[slot]->Find(wxListKey(value)); - } - else - { - node = (wxNodeBase *)NULL; - } - - return node; -} - -#if WXWIN_COMPATIBILITY_2_4 - -// ---------------------------------------------------------------------------- -// wxHashTableLong -// ---------------------------------------------------------------------------- - -wxHashTableLong::~wxHashTableLong() -{ - Destroy(); -} - -void wxHashTableLong::Init(size_t size) -{ - m_hashSize = size; - m_values = new wxArrayLong *[size]; - m_keys = new wxArrayLong *[size]; - - for ( size_t n = 0; n < m_hashSize; n++ ) - { - m_values[n] = - m_keys[n] = (wxArrayLong *)NULL; - } - - m_count = 0; -} - -void wxHashTableLong::Create(size_t size) -{ - Init(size); -} - -void wxHashTableLong::Destroy() -{ - for ( size_t n = 0; n < m_hashSize; n++ ) - { - delete m_values[n]; - delete m_keys[n]; - } - - delete [] m_values; - delete [] m_keys; - m_hashSize = 0; - m_count = 0; -} - -void wxHashTableLong::Put(long key, long value) -{ - wxCHECK_RET( m_hashSize, _T("must call Create() first") ); - - size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); - - if ( !m_keys[slot] ) - { - m_keys[slot] = new wxArrayLong; - m_values[slot] = new wxArrayLong; - } - - m_keys[slot]->Add(key); - m_values[slot]->Add(value); - - m_count++; -} - -long wxHashTableLong::Get(long key) const -{ - wxCHECK_MSG( m_hashSize, wxNOT_FOUND, _T("must call Create() first") ); - - size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); - - wxArrayLong *keys = m_keys[slot]; - if ( keys ) - { - size_t count = keys->GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( keys->Item(n) == key ) - { - return m_values[slot]->Item(n); - } - } - } - - return wxNOT_FOUND; -} - -long wxHashTableLong::Delete(long key) -{ - wxCHECK_MSG( m_hashSize, wxNOT_FOUND, _T("must call Create() first") ); - - size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); - - wxArrayLong *keys = m_keys[slot]; - if ( keys ) - { - size_t count = keys->GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( keys->Item(n) == key ) - { - long val = m_values[slot]->Item(n); - - keys->RemoveAt(n); - m_values[slot]->RemoveAt(n); - - m_count--; - - return val; - } - } - } - - return wxNOT_FOUND; -} - -// ---------------------------------------------------------------------------- -// wxStringHashTable: more efficient than storing strings in a list -// ---------------------------------------------------------------------------- - -wxStringHashTable::wxStringHashTable(size_t sizeTable) -{ - m_keys = new wxArrayLong *[sizeTable]; - m_values = new wxArrayString *[sizeTable]; - - m_hashSize = sizeTable; - for ( size_t n = 0; n < m_hashSize; n++ ) - { - m_values[n] = (wxArrayString *)NULL; - m_keys[n] = (wxArrayLong *)NULL; - } -} - -wxStringHashTable::~wxStringHashTable() -{ - Destroy(); -} - -void wxStringHashTable::Destroy() -{ - for ( size_t n = 0; n < m_hashSize; n++ ) - { - delete m_values[n]; - delete m_keys[n]; - } - - delete [] m_values; - delete [] m_keys; - m_hashSize = 0; -} - -void wxStringHashTable::Put(long key, const wxString& value) -{ - wxCHECK_RET( m_hashSize, _T("must call Create() first") ); - - size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); - - if ( !m_keys[slot] ) - { - m_keys[slot] = new wxArrayLong; - m_values[slot] = new wxArrayString; - } - - m_keys[slot]->Add(key); - m_values[slot]->Add(value); -} - -wxString wxStringHashTable::Get(long key, bool *wasFound) const -{ - wxCHECK_MSG( m_hashSize, wxEmptyString, _T("must call Create() first") ); - - size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); - - wxArrayLong *keys = m_keys[slot]; - if ( keys ) - { - size_t count = keys->GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( keys->Item(n) == key ) - { - if ( wasFound ) - *wasFound = true; - - return m_values[slot]->Item(n); - } - } - } - - if ( wasFound ) - *wasFound = false; - - return wxEmptyString; -} - -bool wxStringHashTable::Delete(long key) const -{ - wxCHECK_MSG( m_hashSize, false, _T("must call Create() first") ); - - size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); - - wxArrayLong *keys = m_keys[slot]; - if ( keys ) - { - size_t count = keys->GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( keys->Item(n) == key ) - { - keys->RemoveAt(n); - m_values[slot]->RemoveAt(n); - return true; - } - } - } - - return false; -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -// ---------------------------------------------------------------------------- -// old not type safe wxHashTable -// ---------------------------------------------------------------------------- - -wxHashTable::wxHashTable (int the_key_type, int size) -{ - n = 0; - hash_table = (wxList**) NULL; - Create(the_key_type, size); - m_count = 0; - m_deleteContents = false; -/* - n = size; - current_position = -1; - current_node = (wxNode *) NULL; - - key_type = the_key_type; - hash_table = new wxList *[size]; - int i; - for (i = 0; i < size; i++) - hash_table[i] = (wxList *) NULL; -*/ -} - -wxHashTable::~wxHashTable () -{ - Destroy(); -} - -void wxHashTable::Destroy() -{ - if (!hash_table) return; - int i; - for (i = 0; i < n; i++) - if (hash_table[i]) - delete hash_table[i]; - delete[] hash_table; - hash_table = NULL; -} - -bool wxHashTable::Create(int the_key_type, int size) -{ - Destroy(); - - n = size; - current_position = -1; - current_node = (wxNode *) NULL; - - key_type = the_key_type; - hash_table = new wxList *[size]; - int i; - for (i = 0; i < size; i++) - hash_table[i] = (wxList *) NULL; - return true; -} - - -void wxHashTable::DoCopy(const wxHashTable& table) -{ - n = table.n; - m_count = table.m_count; - current_position = table.current_position; - current_node = NULL; // doesn't matter - Next() will reconstruct it - key_type = table.key_type; - - hash_table = new wxList *[n]; - for (int i = 0; i < n; i++) { - if (table.hash_table[i] == NULL) - hash_table[i] = NULL; - else { - hash_table[i] = new wxList(key_type); - *hash_table[i] = *(table.hash_table[i]); - } - } -} - -void wxHashTable::Put (long key, long value, wxObject * object) -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - { - hash_table[position] = new wxList (wxKEY_INTEGER); - if (m_deleteContents) hash_table[position]->DeleteContents(true); - } - - hash_table[position]->Append (value, object); - m_count++; -} - -void wxHashTable::Put (long key, const wxChar *value, wxObject * object) -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - { - hash_table[position] = new wxList (wxKEY_STRING); - if (m_deleteContents) hash_table[position]->DeleteContents(true); - } - - hash_table[position]->Append (value, object); - m_count++; -} - -void wxHashTable::Put (long key, wxObject * object) -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - { - hash_table[position] = new wxList (wxKEY_INTEGER); - if (m_deleteContents) hash_table[position]->DeleteContents(true); - } - - hash_table[position]->Append (k, object); - m_count++; -} - -void wxHashTable::Put (const wxChar *key, wxObject * object) -{ - int position = (int) (MakeKey (key) % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - { - hash_table[position] = new wxList (wxKEY_STRING); - if (m_deleteContents) hash_table[position]->DeleteContents(true); - } - - hash_table[position]->Append (key, object); - m_count++; -} - -wxObject *wxHashTable::Get (long key, long value) const -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (value); - if (node) - return node->GetData (); - else - return (wxObject *) NULL; - } -} - -wxObject *wxHashTable::Get (long key, const wxChar *value) const -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (value); - if (node) - return node->GetData (); - else - return (wxObject *) NULL; - } -} - -wxObject *wxHashTable::Get (long key) const -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (k); - return node ? node->GetData () : (wxObject*)NULL; - } -} - -wxObject *wxHashTable::Get (const wxChar *key) const -{ - int position = (int) (MakeKey (key) % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (key); - return node ? node->GetData () : (wxObject*)NULL; - } -} - -wxObject *wxHashTable::Delete (long key) -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (k); - if (node) - { - wxObject *data = node->GetData (); - delete node; - m_count--; - return data; - } - else - return (wxObject *) NULL; - } -} - -wxObject *wxHashTable::Delete (const wxChar *key) -{ - int position = (int) (MakeKey (key) % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (key); - if (node) - { - wxObject *data = node->GetData (); - delete node; - m_count--; - return data; - } - else - return (wxObject *) NULL; - } -} - -wxObject *wxHashTable::Delete (long key, int value) -{ - // Should NEVER be - long k = (long) key; - - int position = (int) (k % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (value); - if (node) - { - wxObject *data = node->GetData (); - delete node; - m_count--; - return data; - } - else - return (wxObject *) NULL; - } -} - -wxObject *wxHashTable::Delete (long key, const wxChar *value) -{ - int position = (int) (key % n); - if (position < 0) position = -position; - - if (!hash_table[position]) - return (wxObject *) NULL; - else - { - wxNode *node = hash_table[position]->Find (value); - if (node) - { - wxObject *data = node->GetData (); - delete node; - m_count--; - return data; - } - else - return (wxObject *) NULL; - } -} - -long wxHashTable::MakeKey (const wxChar *string) const -{ - long int_key = 0; - - while (*string) - int_key += (wxUChar) *string++; - - return int_key; -} - -void wxHashTable::BeginFind () -{ - current_position = -1; - current_node = (wxNode *) NULL; -} - -wxHashTable::Node* wxHashTable::Next () -{ - wxNode *found = (wxNode *) NULL; - bool end = false; - while (!end && !found) - { - if (!current_node) - { - current_position++; - if (current_position >= n) - { - current_position = -1; - current_node = (wxNode *) NULL; - end = true; - } - else - { - if (hash_table[current_position]) - { - current_node = hash_table[current_position]->GetFirst (); - found = current_node; - } - } - } - else - { - current_node = current_node->GetNext (); - found = current_node; - } - } - return found; -} - -void wxHashTable::DeleteContents (bool flag) -{ - int i; - m_deleteContents = flag; - for (i = 0; i < n; i++) - { - if (hash_table[i]) - hash_table[i]->DeleteContents (flag); - } -} - -void wxHashTable::Clear () -{ - int i; - if (hash_table) - { - for (i = 0; i < n; i++) - { - if (hash_table[i]) - hash_table[i]->Clear (); - } - } - m_count = 0; -} - -#else // if !wxUSE_OLD_HASH_TABLE - -wxHashTableBase_Node::wxHashTableBase_Node( long key, void* value, - wxHashTableBase* table ) - : m_value( value ), m_hashPtr( table ) -{ - m_key.integer = key; -} - -wxHashTableBase_Node::wxHashTableBase_Node( const wxChar* key, void* value, - wxHashTableBase* table ) - : m_value( value ), m_hashPtr( table ) -{ - m_key.string = wxStrcpy( new wxChar[wxStrlen( key ) + 1], key ); -} - -wxHashTableBase_Node::~wxHashTableBase_Node() -{ - if( m_hashPtr ) m_hashPtr->DoRemoveNode( this ); -} - -// - -wxHashTableBase::wxHashTableBase() - : m_size( 0 ), m_count( 0 ), m_table( NULL ), m_keyType( wxKEY_NONE ), - m_deleteContents( false ) -{ -} - -void wxHashTableBase::Create( wxKeyType keyType, size_t size ) -{ - m_keyType = keyType; - m_size = size; - m_table = new wxHashTableBase_Node*[ m_size ]; - - for( size_t i = 0; i < m_size; ++i ) - m_table[i] = NULL; -} - -void wxHashTableBase::Clear() -{ - for( size_t i = 0; i < m_size; ++i ) - { - Node* end = m_table[i]; - - if( end == NULL ) - continue; - - Node *curr, *next = end->GetNext(); - - do - { - curr = next; - next = curr->GetNext(); - - DoDestroyNode( curr ); - - delete curr; - } - while( curr != end ); - - m_table[i] = NULL; - } - - m_count = 0; -} - -void wxHashTableBase::DoRemoveNode( wxHashTableBase_Node* node ) -{ - size_t bucket = ( m_keyType == wxKEY_INTEGER ? - node->m_key.integer : - MakeKey( node->m_key.string ) ) % m_size; - - if( node->GetNext() == node ) - { - // single-node chain (common case) - m_table[bucket] = NULL; - } - else - { - Node *start = m_table[bucket], *curr; - Node* prev = start; - - for( curr = prev->GetNext(); curr != node; - prev = curr, curr = curr->GetNext() ) ; - - DoUnlinkNode( bucket, node, prev ); - } - - DoDestroyNode( node ); -} - -void wxHashTableBase::DoDestroyNode( wxHashTableBase_Node* node ) -{ - // if it is called from DoRemoveNode, node has already been - // removed, from other places it does not matter - node->m_hashPtr = NULL; - - if( m_keyType == wxKEY_STRING ) - delete[] node->m_key.string; - if( m_deleteContents ) - DoDeleteContents( node ); -} - -void wxHashTableBase::Destroy() -{ - Clear(); - - delete[] m_table; - - m_table = NULL; - m_size = 0; -} - -void wxHashTableBase::DoInsertNode( size_t bucket, wxHashTableBase_Node* node ) -{ - if( m_table[bucket] == NULL ) - { - m_table[bucket] = node->m_next = node; - } - else - { - Node *prev = m_table[bucket]; - Node *next = prev->m_next; - - prev->m_next = node; - node->m_next = next; - m_table[bucket] = node; - } - - ++m_count; -} - -void wxHashTableBase::DoPut( long key, long hash, void* data ) -{ - wxASSERT( m_keyType == wxKEY_INTEGER ); - - size_t bucket = size_t(hash) % m_size; - Node* node = new wxHashTableBase_Node( key, data, this ); - - DoInsertNode( bucket, node ); -} - -void wxHashTableBase::DoPut( const wxChar* key, long hash, void* data ) -{ - wxASSERT( m_keyType == wxKEY_STRING ); - - size_t bucket = size_t(hash) % m_size; - Node* node = new wxHashTableBase_Node( key, data, this ); - - DoInsertNode( bucket, node ); -} - -void* wxHashTableBase::DoGet( long key, long hash ) const -{ - wxASSERT( m_keyType == wxKEY_INTEGER ); - - size_t bucket = size_t(hash) % m_size; - - if( m_table[bucket] == NULL ) - return NULL; - - Node *first = m_table[bucket]->GetNext(), - *curr = first; - - do - { - if( curr->m_key.integer == key ) - return curr->m_value; - - curr = curr->GetNext(); - } - while( curr != first ); - - return NULL; -} - -void* wxHashTableBase::DoGet( const wxChar* key, long hash ) const -{ - wxASSERT( m_keyType == wxKEY_STRING ); - - size_t bucket = size_t(hash) % m_size; - - if( m_table[bucket] == NULL ) - return NULL; - - Node *first = m_table[bucket]->GetNext(), - *curr = first; - - do - { - if( wxStrcmp( curr->m_key.string, key ) == 0 ) - return curr->m_value; - - curr = curr->GetNext(); - } - while( curr != first ); - - return NULL; -} - -void wxHashTableBase::DoUnlinkNode( size_t bucket, wxHashTableBase_Node* node, - wxHashTableBase_Node* prev ) -{ - if( node == m_table[bucket] ) - m_table[bucket] = prev; - - if( prev == node && prev == node->GetNext() ) - m_table[bucket] = NULL; - else - prev->m_next = node->m_next; - - DoDestroyNode( node ); - --m_count; -} - -void* wxHashTableBase::DoDelete( long key, long hash ) -{ - wxASSERT( m_keyType == wxKEY_INTEGER ); - - size_t bucket = size_t(hash) % m_size; - - if( m_table[bucket] == NULL ) - return NULL; - - Node *first = m_table[bucket]->GetNext(), - *curr = first, - *prev = m_table[bucket]; - - do - { - if( curr->m_key.integer == key ) - { - void* retval = curr->m_value; - curr->m_value = NULL; - - DoUnlinkNode( bucket, curr, prev ); - delete curr; - - return retval; - } - - prev = curr; - curr = curr->GetNext(); - } - while( curr != first ); - - return NULL; -} - -void* wxHashTableBase::DoDelete( const wxChar* key, long hash ) -{ - wxASSERT( m_keyType == wxKEY_STRING ); - - size_t bucket = size_t(hash) % m_size; - - if( m_table[bucket] == NULL ) - return NULL; - - Node *first = m_table[bucket]->GetNext(), - *curr = first, - *prev = m_table[bucket]; - - do - { - if( wxStrcmp( curr->m_key.string, key ) == 0 ) - { - void* retval = curr->m_value; - curr->m_value = NULL; - - DoUnlinkNode( bucket, curr, prev ); - delete curr; - - return retval; - } - - prev = curr; - curr = curr->GetNext(); - } - while( curr != first ); - - return NULL; -} - -long wxHashTableBase::MakeKey( const wxChar *str ) -{ - long int_key = 0; - - while( *str ) - int_key += (wxUChar)*str++; - - return int_key; -} - -// ---------------------------------------------------------------------------- -// wxHashTable -// ---------------------------------------------------------------------------- - -wxHashTable::wxHashTable( const wxHashTable& table ) - : wxHashTableBase() -{ - DoCopy( table ); -} - -const wxHashTable& wxHashTable::operator=( const wxHashTable& table ) -{ - Destroy(); - DoCopy( table ); - - return *this; -} - -void wxHashTable::DoCopy( const wxHashTable& WXUNUSED(table) ) -{ - Create( m_keyType, m_size ); - - wxFAIL; -} - -void wxHashTable::DoDeleteContents( wxHashTableBase_Node* node ) -{ - delete ((wxHashTable_Node*)node)->GetData(); -} - -void wxHashTable::GetNextNode( size_t bucketStart ) -{ - for( size_t i = bucketStart; i < m_size; ++i ) - { - if( m_table[i] != NULL ) - { - m_curr = ((Node*)m_table[i])->GetNext(); - m_currBucket = i; - return; - } - } - - m_curr = NULL; - m_currBucket = 0; -} - -wxHashTable::Node* wxHashTable::Next() -{ - if( m_curr == NULL ) - GetNextNode( 0 ); - else - { - m_curr = m_curr->GetNext(); - - if( m_curr == ( (Node*)m_table[m_currBucket] )->GetNext() ) - GetNextNode( m_currBucket + 1 ); - } - - return m_curr; -} - -#endif // !wxUSE_OLD_HASH_TABLE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/hash.cpp +// Purpose: wxHashTable implementation +// Author: Julian Smart +// Modified by: VZ at 25.02.00: type safe hashes with WX_DECLARE_HASH() +// Created: 01/02/97 +// RCS-ID: $Id: hash.cpp 49529 2007-10-30 00:32:18Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/list.h" + #include "wx/hash.h" +#endif + +#if wxUSE_OLD_HASH_TABLE + +#include +#include + +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxHashTable, wxObject) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxHashTablleBase for working with "void *" data +// ---------------------------------------------------------------------------- + +wxHashTableBase::wxHashTableBase() +{ + m_deleteContents = false; + m_hashTable = (wxListBase **)NULL; + m_hashSize = 0; + m_count = 0; + m_keyType = wxKEY_NONE; +} + +void wxHashTableBase::Create(wxKeyType keyType, size_t size) +{ + Destroy(); + + m_hashSize = size; + m_keyType = keyType; + m_hashTable = new wxListBase *[size]; + for ( size_t n = 0; n < m_hashSize; n++ ) + { + m_hashTable[n] = (wxListBase *) NULL; + } +} + +void wxHashTableBase::Destroy() +{ + if ( m_hashTable ) + { + for ( size_t n = 0; n < m_hashSize; n++ ) + { + delete m_hashTable[n]; + } + + delete [] m_hashTable; + + m_hashTable = (wxListBase **)NULL; + + m_count = 0; + } +} + +void wxHashTableBase::DeleteContents(bool flag) +{ + m_deleteContents = flag; + for ( size_t n = 0; n < m_hashSize; n++ ) + { + if ( m_hashTable[n] ) + { + m_hashTable[n]->DeleteContents(flag); + } + } +} + +wxNodeBase *wxHashTableBase::GetNode(long key, long value) const +{ + size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); + + wxNodeBase *node; + if ( m_hashTable[slot] ) + { + node = m_hashTable[slot]->Find(wxListKey(value)); + } + else + { + node = (wxNodeBase *)NULL; + } + + return node; +} + +#if WXWIN_COMPATIBILITY_2_4 + +// ---------------------------------------------------------------------------- +// wxHashTableLong +// ---------------------------------------------------------------------------- + +wxHashTableLong::~wxHashTableLong() +{ + Destroy(); +} + +void wxHashTableLong::Init(size_t size) +{ + m_hashSize = size; + m_values = new wxArrayLong *[size]; + m_keys = new wxArrayLong *[size]; + + for ( size_t n = 0; n < m_hashSize; n++ ) + { + m_values[n] = + m_keys[n] = (wxArrayLong *)NULL; + } + + m_count = 0; +} + +void wxHashTableLong::Create(size_t size) +{ + Init(size); +} + +void wxHashTableLong::Destroy() +{ + for ( size_t n = 0; n < m_hashSize; n++ ) + { + delete m_values[n]; + delete m_keys[n]; + } + + delete [] m_values; + delete [] m_keys; + m_hashSize = 0; + m_count = 0; +} + +void wxHashTableLong::Put(long key, long value) +{ + wxCHECK_RET( m_hashSize, _T("must call Create() first") ); + + size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); + + if ( !m_keys[slot] ) + { + m_keys[slot] = new wxArrayLong; + m_values[slot] = new wxArrayLong; + } + + m_keys[slot]->Add(key); + m_values[slot]->Add(value); + + m_count++; +} + +long wxHashTableLong::Get(long key) const +{ + wxCHECK_MSG( m_hashSize, wxNOT_FOUND, _T("must call Create() first") ); + + size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); + + wxArrayLong *keys = m_keys[slot]; + if ( keys ) + { + size_t count = keys->GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( keys->Item(n) == key ) + { + return m_values[slot]->Item(n); + } + } + } + + return wxNOT_FOUND; +} + +long wxHashTableLong::Delete(long key) +{ + wxCHECK_MSG( m_hashSize, wxNOT_FOUND, _T("must call Create() first") ); + + size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); + + wxArrayLong *keys = m_keys[slot]; + if ( keys ) + { + size_t count = keys->GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( keys->Item(n) == key ) + { + long val = m_values[slot]->Item(n); + + keys->RemoveAt(n); + m_values[slot]->RemoveAt(n); + + m_count--; + + return val; + } + } + } + + return wxNOT_FOUND; +} + +// ---------------------------------------------------------------------------- +// wxStringHashTable: more efficient than storing strings in a list +// ---------------------------------------------------------------------------- + +wxStringHashTable::wxStringHashTable(size_t sizeTable) +{ + m_keys = new wxArrayLong *[sizeTable]; + m_values = new wxArrayString *[sizeTable]; + + m_hashSize = sizeTable; + for ( size_t n = 0; n < m_hashSize; n++ ) + { + m_values[n] = (wxArrayString *)NULL; + m_keys[n] = (wxArrayLong *)NULL; + } +} + +wxStringHashTable::~wxStringHashTable() +{ + Destroy(); +} + +void wxStringHashTable::Destroy() +{ + for ( size_t n = 0; n < m_hashSize; n++ ) + { + delete m_values[n]; + delete m_keys[n]; + } + + delete [] m_values; + delete [] m_keys; + m_hashSize = 0; +} + +void wxStringHashTable::Put(long key, const wxString& value) +{ + wxCHECK_RET( m_hashSize, _T("must call Create() first") ); + + size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); + + if ( !m_keys[slot] ) + { + m_keys[slot] = new wxArrayLong; + m_values[slot] = new wxArrayString; + } + + m_keys[slot]->Add(key); + m_values[slot]->Add(value); +} + +wxString wxStringHashTable::Get(long key, bool *wasFound) const +{ + wxCHECK_MSG( m_hashSize, wxEmptyString, _T("must call Create() first") ); + + size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); + + wxArrayLong *keys = m_keys[slot]; + if ( keys ) + { + size_t count = keys->GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( keys->Item(n) == key ) + { + if ( wasFound ) + *wasFound = true; + + return m_values[slot]->Item(n); + } + } + } + + if ( wasFound ) + *wasFound = false; + + return wxEmptyString; +} + +bool wxStringHashTable::Delete(long key) const +{ + wxCHECK_MSG( m_hashSize, false, _T("must call Create() first") ); + + size_t slot = (size_t)abs((int)(key % (long)m_hashSize)); + + wxArrayLong *keys = m_keys[slot]; + if ( keys ) + { + size_t count = keys->GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( keys->Item(n) == key ) + { + keys->RemoveAt(n); + m_values[slot]->RemoveAt(n); + return true; + } + } + } + + return false; +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +// ---------------------------------------------------------------------------- +// old not type safe wxHashTable +// ---------------------------------------------------------------------------- + +wxHashTable::wxHashTable (int the_key_type, int size) +{ + n = 0; + hash_table = (wxList**) NULL; + Create(the_key_type, size); + m_count = 0; + m_deleteContents = false; +/* + n = size; + current_position = -1; + current_node = (wxNode *) NULL; + + key_type = the_key_type; + hash_table = new wxList *[size]; + int i; + for (i = 0; i < size; i++) + hash_table[i] = (wxList *) NULL; +*/ +} + +wxHashTable::~wxHashTable () +{ + Destroy(); +} + +void wxHashTable::Destroy() +{ + if (!hash_table) return; + int i; + for (i = 0; i < n; i++) + if (hash_table[i]) + delete hash_table[i]; + delete[] hash_table; + hash_table = NULL; +} + +bool wxHashTable::Create(int the_key_type, int size) +{ + Destroy(); + + n = size; + current_position = -1; + current_node = (wxNode *) NULL; + + key_type = the_key_type; + hash_table = new wxList *[size]; + int i; + for (i = 0; i < size; i++) + hash_table[i] = (wxList *) NULL; + return true; +} + + +void wxHashTable::DoCopy(const wxHashTable& table) +{ + n = table.n; + m_count = table.m_count; + current_position = table.current_position; + current_node = NULL; // doesn't matter - Next() will reconstruct it + key_type = table.key_type; + + hash_table = new wxList *[n]; + for (int i = 0; i < n; i++) { + if (table.hash_table[i] == NULL) + hash_table[i] = NULL; + else { + hash_table[i] = new wxList(key_type); + *hash_table[i] = *(table.hash_table[i]); + } + } +} + +void wxHashTable::Put (long key, long value, wxObject * object) +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + { + hash_table[position] = new wxList (wxKEY_INTEGER); + if (m_deleteContents) hash_table[position]->DeleteContents(true); + } + + hash_table[position]->Append (value, object); + m_count++; +} + +void wxHashTable::Put (long key, const wxChar *value, wxObject * object) +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + { + hash_table[position] = new wxList (wxKEY_STRING); + if (m_deleteContents) hash_table[position]->DeleteContents(true); + } + + hash_table[position]->Append (value, object); + m_count++; +} + +void wxHashTable::Put (long key, wxObject * object) +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + { + hash_table[position] = new wxList (wxKEY_INTEGER); + if (m_deleteContents) hash_table[position]->DeleteContents(true); + } + + hash_table[position]->Append (k, object); + m_count++; +} + +void wxHashTable::Put (const wxChar *key, wxObject * object) +{ + int position = (int) (MakeKey (key) % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + { + hash_table[position] = new wxList (wxKEY_STRING); + if (m_deleteContents) hash_table[position]->DeleteContents(true); + } + + hash_table[position]->Append (key, object); + m_count++; +} + +wxObject *wxHashTable::Get (long key, long value) const +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (value); + if (node) + return node->GetData (); + else + return (wxObject *) NULL; + } +} + +wxObject *wxHashTable::Get (long key, const wxChar *value) const +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (value); + if (node) + return node->GetData (); + else + return (wxObject *) NULL; + } +} + +wxObject *wxHashTable::Get (long key) const +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (k); + return node ? node->GetData () : (wxObject*)NULL; + } +} + +wxObject *wxHashTable::Get (const wxChar *key) const +{ + int position = (int) (MakeKey (key) % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (key); + return node ? node->GetData () : (wxObject*)NULL; + } +} + +wxObject *wxHashTable::Delete (long key) +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (k); + if (node) + { + wxObject *data = node->GetData (); + delete node; + m_count--; + return data; + } + else + return (wxObject *) NULL; + } +} + +wxObject *wxHashTable::Delete (const wxChar *key) +{ + int position = (int) (MakeKey (key) % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (key); + if (node) + { + wxObject *data = node->GetData (); + delete node; + m_count--; + return data; + } + else + return (wxObject *) NULL; + } +} + +wxObject *wxHashTable::Delete (long key, int value) +{ + // Should NEVER be + long k = (long) key; + + int position = (int) (k % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (value); + if (node) + { + wxObject *data = node->GetData (); + delete node; + m_count--; + return data; + } + else + return (wxObject *) NULL; + } +} + +wxObject *wxHashTable::Delete (long key, const wxChar *value) +{ + int position = (int) (key % n); + if (position < 0) position = -position; + + if (!hash_table[position]) + return (wxObject *) NULL; + else + { + wxNode *node = hash_table[position]->Find (value); + if (node) + { + wxObject *data = node->GetData (); + delete node; + m_count--; + return data; + } + else + return (wxObject *) NULL; + } +} + +long wxHashTable::MakeKey (const wxChar *string) const +{ + long int_key = 0; + + while (*string) + int_key += (wxUChar) *string++; + + return int_key; +} + +void wxHashTable::BeginFind () +{ + current_position = -1; + current_node = (wxNode *) NULL; +} + +wxHashTable::Node* wxHashTable::Next () +{ + wxNode *found = (wxNode *) NULL; + bool end = false; + while (!end && !found) + { + if (!current_node) + { + current_position++; + if (current_position >= n) + { + current_position = -1; + current_node = (wxNode *) NULL; + end = true; + } + else + { + if (hash_table[current_position]) + { + current_node = hash_table[current_position]->GetFirst (); + found = current_node; + } + } + } + else + { + current_node = current_node->GetNext (); + found = current_node; + } + } + return found; +} + +void wxHashTable::DeleteContents (bool flag) +{ + int i; + m_deleteContents = flag; + for (i = 0; i < n; i++) + { + if (hash_table[i]) + hash_table[i]->DeleteContents (flag); + } +} + +void wxHashTable::Clear () +{ + int i; + if (hash_table) + { + for (i = 0; i < n; i++) + { + if (hash_table[i]) + hash_table[i]->Clear (); + } + } + m_count = 0; +} + +#else // if !wxUSE_OLD_HASH_TABLE + +wxHashTableBase_Node::wxHashTableBase_Node( long key, void* value, + wxHashTableBase* table ) + : m_value( value ), m_hashPtr( table ) +{ + m_key.integer = key; +} + +wxHashTableBase_Node::wxHashTableBase_Node( const wxChar* key, void* value, + wxHashTableBase* table ) + : m_value( value ), m_hashPtr( table ) +{ + m_key.string = wxStrcpy( new wxChar[wxStrlen( key ) + 1], key ); +} + +wxHashTableBase_Node::~wxHashTableBase_Node() +{ + if( m_hashPtr ) m_hashPtr->DoRemoveNode( this ); +} + +// + +wxHashTableBase::wxHashTableBase() + : m_size( 0 ), m_count( 0 ), m_table( NULL ), m_keyType( wxKEY_NONE ), + m_deleteContents( false ) +{ +} + +void wxHashTableBase::Create( wxKeyType keyType, size_t size ) +{ + m_keyType = keyType; + m_size = size; + m_table = new wxHashTableBase_Node*[ m_size ]; + + for( size_t i = 0; i < m_size; ++i ) + m_table[i] = NULL; +} + +void wxHashTableBase::Clear() +{ + for( size_t i = 0; i < m_size; ++i ) + { + Node* end = m_table[i]; + + if( end == NULL ) + continue; + + Node *curr, *next = end->GetNext(); + + do + { + curr = next; + next = curr->GetNext(); + + DoDestroyNode( curr ); + + delete curr; + } + while( curr != end ); + + m_table[i] = NULL; + } + + m_count = 0; +} + +void wxHashTableBase::DoRemoveNode( wxHashTableBase_Node* node ) +{ + size_t bucket = ( m_keyType == wxKEY_INTEGER ? + node->m_key.integer : + MakeKey( node->m_key.string ) ) % m_size; + + if( node->GetNext() == node ) + { + // single-node chain (common case) + m_table[bucket] = NULL; + } + else + { + Node *start = m_table[bucket], *curr; + Node* prev = start; + + for( curr = prev->GetNext(); curr != node; + prev = curr, curr = curr->GetNext() ) ; + + DoUnlinkNode( bucket, node, prev ); + } + + DoDestroyNode( node ); +} + +void wxHashTableBase::DoDestroyNode( wxHashTableBase_Node* node ) +{ + // if it is called from DoRemoveNode, node has already been + // removed, from other places it does not matter + node->m_hashPtr = NULL; + + if( m_keyType == wxKEY_STRING ) + delete[] node->m_key.string; + if( m_deleteContents ) + DoDeleteContents( node ); +} + +void wxHashTableBase::Destroy() +{ + Clear(); + + delete[] m_table; + + m_table = NULL; + m_size = 0; +} + +void wxHashTableBase::DoInsertNode( size_t bucket, wxHashTableBase_Node* node ) +{ + if( m_table[bucket] == NULL ) + { + m_table[bucket] = node->m_next = node; + } + else + { + Node *prev = m_table[bucket]; + Node *next = prev->m_next; + + prev->m_next = node; + node->m_next = next; + m_table[bucket] = node; + } + + ++m_count; +} + +void wxHashTableBase::DoPut( long key, long hash, void* data ) +{ + wxASSERT( m_keyType == wxKEY_INTEGER ); + + size_t bucket = size_t(hash) % m_size; + Node* node = new wxHashTableBase_Node( key, data, this ); + + DoInsertNode( bucket, node ); +} + +void wxHashTableBase::DoPut( const wxChar* key, long hash, void* data ) +{ + wxASSERT( m_keyType == wxKEY_STRING ); + + size_t bucket = size_t(hash) % m_size; + Node* node = new wxHashTableBase_Node( key, data, this ); + + DoInsertNode( bucket, node ); +} + +void* wxHashTableBase::DoGet( long key, long hash ) const +{ + wxASSERT( m_keyType == wxKEY_INTEGER ); + + size_t bucket = size_t(hash) % m_size; + + if( m_table[bucket] == NULL ) + return NULL; + + Node *first = m_table[bucket]->GetNext(), + *curr = first; + + do + { + if( curr->m_key.integer == key ) + return curr->m_value; + + curr = curr->GetNext(); + } + while( curr != first ); + + return NULL; +} + +void* wxHashTableBase::DoGet( const wxChar* key, long hash ) const +{ + wxASSERT( m_keyType == wxKEY_STRING ); + + size_t bucket = size_t(hash) % m_size; + + if( m_table[bucket] == NULL ) + return NULL; + + Node *first = m_table[bucket]->GetNext(), + *curr = first; + + do + { + if( wxStrcmp( curr->m_key.string, key ) == 0 ) + return curr->m_value; + + curr = curr->GetNext(); + } + while( curr != first ); + + return NULL; +} + +void wxHashTableBase::DoUnlinkNode( size_t bucket, wxHashTableBase_Node* node, + wxHashTableBase_Node* prev ) +{ + if( node == m_table[bucket] ) + m_table[bucket] = prev; + + if( prev == node && prev == node->GetNext() ) + m_table[bucket] = NULL; + else + prev->m_next = node->m_next; + + DoDestroyNode( node ); + --m_count; +} + +void* wxHashTableBase::DoDelete( long key, long hash ) +{ + wxASSERT( m_keyType == wxKEY_INTEGER ); + + size_t bucket = size_t(hash) % m_size; + + if( m_table[bucket] == NULL ) + return NULL; + + Node *first = m_table[bucket]->GetNext(), + *curr = first, + *prev = m_table[bucket]; + + do + { + if( curr->m_key.integer == key ) + { + void* retval = curr->m_value; + curr->m_value = NULL; + + DoUnlinkNode( bucket, curr, prev ); + delete curr; + + return retval; + } + + prev = curr; + curr = curr->GetNext(); + } + while( curr != first ); + + return NULL; +} + +void* wxHashTableBase::DoDelete( const wxChar* key, long hash ) +{ + wxASSERT( m_keyType == wxKEY_STRING ); + + size_t bucket = size_t(hash) % m_size; + + if( m_table[bucket] == NULL ) + return NULL; + + Node *first = m_table[bucket]->GetNext(), + *curr = first, + *prev = m_table[bucket]; + + do + { + if( wxStrcmp( curr->m_key.string, key ) == 0 ) + { + void* retval = curr->m_value; + curr->m_value = NULL; + + DoUnlinkNode( bucket, curr, prev ); + delete curr; + + return retval; + } + + prev = curr; + curr = curr->GetNext(); + } + while( curr != first ); + + return NULL; +} + +long wxHashTableBase::MakeKey( const wxChar *str ) +{ + long int_key = 0; + + while( *str ) + int_key += (wxUChar)*str++; + + return int_key; +} + +// ---------------------------------------------------------------------------- +// wxHashTable +// ---------------------------------------------------------------------------- + +wxHashTable::wxHashTable( const wxHashTable& table ) + : wxHashTableBase() +{ + DoCopy( table ); +} + +const wxHashTable& wxHashTable::operator=( const wxHashTable& table ) +{ + Destroy(); + DoCopy( table ); + + return *this; +} + +void wxHashTable::DoCopy( const wxHashTable& WXUNUSED(table) ) +{ + Create( m_keyType, m_size ); + + wxFAIL; +} + +void wxHashTable::DoDeleteContents( wxHashTableBase_Node* node ) +{ + delete ((wxHashTable_Node*)node)->GetData(); +} + +void wxHashTable::GetNextNode( size_t bucketStart ) +{ + for( size_t i = bucketStart; i < m_size; ++i ) + { + if( m_table[i] != NULL ) + { + m_curr = ((Node*)m_table[i])->GetNext(); + m_currBucket = i; + return; + } + } + + m_curr = NULL; + m_currBucket = 0; +} + +wxHashTable::Node* wxHashTable::Next() +{ + if( m_curr == NULL ) + GetNextNode( 0 ); + else + { + m_curr = m_curr->GetNext(); + + if( m_curr == ( (Node*)m_table[m_currBucket] )->GetNext() ) + GetNextNode( m_currBucket + 1 ); + } + + return m_curr; +} + +#endif // !wxUSE_OLD_HASH_TABLE diff --git a/Source/3rd Party/wx/src/common/hashmap.cpp b/Source/3rd Party/wx/src/common/hashmap.cpp index c3fba8dfc..215396f8e 100644 --- a/Source/3rd Party/wx/src/common/hashmap.cpp +++ b/Source/3rd Party/wx/src/common/hashmap.cpp @@ -1,152 +1,152 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/hashmap.cpp -// Purpose: wxHashMap implementation -// Author: Mattia Barbon -// Modified by: -// Created: 29/01/2002 -// RCS-ID: $Id: hashmap.cpp 39802 2006-06-20 10:24:07Z ABX $ -// Copyright: (c) Mattia Barbon -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/hashmap.h" - -/* FYI: This is the "One-at-a-Time" algorithm by Bob Jenkins */ -/* from requirements by Colin Plumb. */ -/* (http://burtleburtle.net/bob/hash/doobs.html) */ -/* adapted from Perl sources ( hv.h ) */ -unsigned long wxStringHash::wxCharStringHash( const wxChar* k ) -{ - unsigned long hash = 0; - - while( *k ) - { - hash += *k++; - hash += (hash << 10); - hash ^= (hash >> 6); - } - hash += (hash << 3); - hash ^= (hash >> 11); - - return hash + (hash << 15); -} - -#if wxUSE_UNICODE -unsigned long wxStringHash::charStringHash( const char* k ) -{ - unsigned long hash = 0; - - while( *k ) - { - hash += *k++; - hash += (hash << 10); - hash ^= (hash >> 6); - } - hash += (hash << 3); - hash ^= (hash >> 11); - - return hash + (hash << 15); -} -#endif - -#if !wxUSE_STL || !defined(HAVE_STL_HASH_MAP) - -/* from SGI STL */ -const unsigned long _wxHashTableBase2::ms_primes[prime_count] = -{ - 7ul, 13ul, 29ul, - 53ul, 97ul, 193ul, 389ul, 769ul, - 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, - 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, - 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, - 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, - 1610612741ul, 3221225473ul, 4294967291ul -}; - -unsigned long _wxHashTableBase2::GetNextPrime( unsigned long n ) -{ - const unsigned long* ptr = &ms_primes[0]; - for( size_t i = 0; i < prime_count; ++i, ++ptr ) - { - if( n < *ptr ) - return *ptr; - } - - /* someone might try to alloc a 2^32-element hash table */ - wxFAIL_MSG( _T("hash table too big?") ); - - /* quiet warning */ - return 0; -} - -unsigned long _wxHashTableBase2::GetPreviousPrime( unsigned long n ) -{ - const unsigned long* ptr = &ms_primes[prime_count - 1]; - - for( size_t i = 0; i < prime_count; ++i, --ptr ) - { - if( n > *ptr ) - return *ptr; - } - - /* quiet warning */ - return 1; -} - -void _wxHashTableBase2::DeleteNodes( size_t buckets, - _wxHashTable_NodeBase** table, - NodeDtor dtor ) -{ - size_t i; - - for( i = 0; i < buckets; ++i ) - { - _wxHashTable_NodeBase* node = table[i]; - _wxHashTable_NodeBase* tmp; - - while( node ) - { - tmp = node->m_nxt; - dtor( node ); - node = tmp; - } - } - - memset( table, 0, buckets * sizeof(void*) ); -} - -void _wxHashTableBase2::CopyHashTable( _wxHashTable_NodeBase** srcTable, - size_t srcBuckets, - _wxHashTableBase2* dst, - _wxHashTable_NodeBase** dstTable, - BucketFromNode func, ProcessNode proc ) -{ - for( size_t i = 0; i < srcBuckets; ++i ) - { - _wxHashTable_NodeBase* nextnode; - - for( _wxHashTable_NodeBase* node = srcTable[i]; node; node = nextnode ) - { - size_t bucket = func( dst, node ); - - nextnode = node->m_nxt; - _wxHashTable_NodeBase* newnode = proc( node ); - newnode->m_nxt = dstTable[bucket]; - dstTable[bucket] = newnode; - } - } -} - -_wxHashTable_NodeBase* _wxHashTableBase2::DummyProcessNode(_wxHashTable_NodeBase* node) -{ - return node; -} - -#endif // !wxUSE_STL || !defined(HAVE_STL_HASH_MAP) +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/hashmap.cpp +// Purpose: wxHashMap implementation +// Author: Mattia Barbon +// Modified by: +// Created: 29/01/2002 +// RCS-ID: $Id: hashmap.cpp 39802 2006-06-20 10:24:07Z ABX $ +// Copyright: (c) Mattia Barbon +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/hashmap.h" + +/* FYI: This is the "One-at-a-Time" algorithm by Bob Jenkins */ +/* from requirements by Colin Plumb. */ +/* (http://burtleburtle.net/bob/hash/doobs.html) */ +/* adapted from Perl sources ( hv.h ) */ +unsigned long wxStringHash::wxCharStringHash( const wxChar* k ) +{ + unsigned long hash = 0; + + while( *k ) + { + hash += *k++; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + + return hash + (hash << 15); +} + +#if wxUSE_UNICODE +unsigned long wxStringHash::charStringHash( const char* k ) +{ + unsigned long hash = 0; + + while( *k ) + { + hash += *k++; + hash += (hash << 10); + hash ^= (hash >> 6); + } + hash += (hash << 3); + hash ^= (hash >> 11); + + return hash + (hash << 15); +} +#endif + +#if !wxUSE_STL || !defined(HAVE_STL_HASH_MAP) + +/* from SGI STL */ +const unsigned long _wxHashTableBase2::ms_primes[prime_count] = +{ + 7ul, 13ul, 29ul, + 53ul, 97ul, 193ul, 389ul, 769ul, + 1543ul, 3079ul, 6151ul, 12289ul, 24593ul, + 49157ul, 98317ul, 196613ul, 393241ul, 786433ul, + 1572869ul, 3145739ul, 6291469ul, 12582917ul, 25165843ul, + 50331653ul, 100663319ul, 201326611ul, 402653189ul, 805306457ul, + 1610612741ul, 3221225473ul, 4294967291ul +}; + +unsigned long _wxHashTableBase2::GetNextPrime( unsigned long n ) +{ + const unsigned long* ptr = &ms_primes[0]; + for( size_t i = 0; i < prime_count; ++i, ++ptr ) + { + if( n < *ptr ) + return *ptr; + } + + /* someone might try to alloc a 2^32-element hash table */ + wxFAIL_MSG( _T("hash table too big?") ); + + /* quiet warning */ + return 0; +} + +unsigned long _wxHashTableBase2::GetPreviousPrime( unsigned long n ) +{ + const unsigned long* ptr = &ms_primes[prime_count - 1]; + + for( size_t i = 0; i < prime_count; ++i, --ptr ) + { + if( n > *ptr ) + return *ptr; + } + + /* quiet warning */ + return 1; +} + +void _wxHashTableBase2::DeleteNodes( size_t buckets, + _wxHashTable_NodeBase** table, + NodeDtor dtor ) +{ + size_t i; + + for( i = 0; i < buckets; ++i ) + { + _wxHashTable_NodeBase* node = table[i]; + _wxHashTable_NodeBase* tmp; + + while( node ) + { + tmp = node->m_nxt; + dtor( node ); + node = tmp; + } + } + + memset( table, 0, buckets * sizeof(void*) ); +} + +void _wxHashTableBase2::CopyHashTable( _wxHashTable_NodeBase** srcTable, + size_t srcBuckets, + _wxHashTableBase2* dst, + _wxHashTable_NodeBase** dstTable, + BucketFromNode func, ProcessNode proc ) +{ + for( size_t i = 0; i < srcBuckets; ++i ) + { + _wxHashTable_NodeBase* nextnode; + + for( _wxHashTable_NodeBase* node = srcTable[i]; node; node = nextnode ) + { + size_t bucket = func( dst, node ); + + nextnode = node->m_nxt; + _wxHashTable_NodeBase* newnode = proc( node ); + newnode->m_nxt = dstTable[bucket]; + dstTable[bucket] = newnode; + } + } +} + +_wxHashTable_NodeBase* _wxHashTableBase2::DummyProcessNode(_wxHashTable_NodeBase* node) +{ + return node; +} + +#endif // !wxUSE_STL || !defined(HAVE_STL_HASH_MAP) diff --git a/Source/3rd Party/wx/src/common/helpbase.cpp b/Source/3rd Party/wx/src/common/helpbase.cpp index b1f95e2de..83ede72d7 100644 --- a/Source/3rd Party/wx/src/common/helpbase.cpp +++ b/Source/3rd Party/wx/src/common/helpbase.cpp @@ -1,28 +1,28 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/helpbase.cpp -// Purpose: Help system base classes -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: helpbase.cpp 38787 2006-04-18 07:24:35Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_HELP - -#ifndef WX_PRECOMP -#endif - -#include "wx/helpbase.h" - -IMPLEMENT_CLASS(wxHelpControllerBase, wxObject) - -#endif // wxUSE_HELP +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/helpbase.cpp +// Purpose: Help system base classes +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: helpbase.cpp 38787 2006-04-18 07:24:35Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_HELP + +#ifndef WX_PRECOMP +#endif + +#include "wx/helpbase.h" + +IMPLEMENT_CLASS(wxHelpControllerBase, wxObject) + +#endif // wxUSE_HELP diff --git a/Source/3rd Party/wx/src/common/iconbndl.cpp b/Source/3rd Party/wx/src/common/iconbndl.cpp index 56ccc004b..98805d7e8 100644 --- a/Source/3rd Party/wx/src/common/iconbndl.cpp +++ b/Source/3rd Party/wx/src/common/iconbndl.cpp @@ -1,142 +1,142 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/iconbndl.cpp -// Purpose: wxIconBundle -// Author: Mattia Barbon -// Created: 23.03.2002 -// RCS-ID: $Id: iconbndl.cpp 40654 2006-08-17 16:08:13Z VS $ -// Copyright: (c) Mattia barbon -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/iconbndl.h" - -#ifndef WX_PRECOMP - #include "wx/settings.h" - #include "wx/icon.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/bitmap.h" - #include "wx/image.h" -#endif - -#include "wx/arrimpl.cpp" - -WX_DEFINE_OBJARRAY(wxIconArray) - -const wxIconBundle& wxIconBundle::operator =( const wxIconBundle& ic ) -{ - if( this == &ic ) return *this; - - size_t i, max = ic.m_icons.GetCount(); - - DeleteIcons(); - for( i = 0; i < max; ++i ) - m_icons.Add( ic.m_icons[i] ); - - return *this; -} - -void wxIconBundle::DeleteIcons() -{ - m_icons.Empty(); -} - -#if wxUSE_IMAGE -void wxIconBundle::AddIcon( const wxString& file, long type ) -#else -void wxIconBundle::AddIcon( const wxString& WXUNUSED(file), long WXUNUSED(type) ) -#endif -{ -#if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) - size_t count = wxImage::GetImageCount( file, type ); - size_t i; - wxImage image; - - for( i = 0; i < count; ++i ) - { - if( !image.LoadFile( file, type, i ) ) - { - wxLogError( _("Failed to load image %d from file '%s'."), - i, file.c_str() ); - continue; - } - - wxIcon* tmp = new wxIcon(); - tmp->CopyFromBitmap( wxBitmap( image ) ); - AddIcon( *tmp ); - delete tmp; - } -#endif -} - -const wxIcon& wxIconBundle::GetIcon( const wxSize& size ) const -{ - // temp. variable needed to fix Borland C++ 5.5.1 problem - // with passing a return value through two functions - wxIcon *tmp; - - size_t max = m_icons.GetCount(); - - // if we have one or no icon, we can return now without doing more work: - if ( max <= 1 ) - { - if ( max == 1 ) // fix for broken BCC - tmp = &m_icons[0]; - else // max == 0 - tmp = &wxNullIcon; - return *tmp; - } - - // there are more icons, find the best match: - wxCoord sysX = wxSystemSettings::GetMetric( wxSYS_ICON_X ), - sysY = wxSystemSettings::GetMetric( wxSYS_ICON_Y ); - - wxIcon *sysIcon = 0; - - for( size_t i = 0; i < max; i++ ) - { - if( !m_icons[i].Ok() ) - continue; - wxCoord sx = m_icons[i].GetWidth(), sy = m_icons[i].GetHeight(); - // requested size - if( sx == size.x && sy == size.y ) - { - tmp = &m_icons[i]; // fix for broken BCC - return *tmp; - } - // keep track if there is a system-size icon - if( sx == sysX && sy == sysY ) - sysIcon = &m_icons[i]; - } - - // return the system-sized icon if we've got one - if( sysIcon ) return *sysIcon; - // we certainly have at least one icon thanks to the <=1 check above - tmp = &m_icons[0]; - return *tmp; -} - -void wxIconBundle::AddIcon( const wxIcon& icon ) -{ - size_t i, max = m_icons.GetCount(); - - for( i = 0; i < max; ++i ) - { - wxIcon& tmp = m_icons[i]; - if( tmp.Ok() && tmp.GetWidth() == icon.GetWidth() && - tmp.GetHeight() == icon.GetHeight() ) - { - tmp = icon; - return; - } - } - - m_icons.Add( icon ); -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/iconbndl.cpp +// Purpose: wxIconBundle +// Author: Mattia Barbon +// Created: 23.03.2002 +// RCS-ID: $Id: iconbndl.cpp 40654 2006-08-17 16:08:13Z VS $ +// Copyright: (c) Mattia barbon +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/iconbndl.h" + +#ifndef WX_PRECOMP + #include "wx/settings.h" + #include "wx/icon.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/bitmap.h" + #include "wx/image.h" +#endif + +#include "wx/arrimpl.cpp" + +WX_DEFINE_OBJARRAY(wxIconArray) + +const wxIconBundle& wxIconBundle::operator =( const wxIconBundle& ic ) +{ + if( this == &ic ) return *this; + + size_t i, max = ic.m_icons.GetCount(); + + DeleteIcons(); + for( i = 0; i < max; ++i ) + m_icons.Add( ic.m_icons[i] ); + + return *this; +} + +void wxIconBundle::DeleteIcons() +{ + m_icons.Empty(); +} + +#if wxUSE_IMAGE +void wxIconBundle::AddIcon( const wxString& file, long type ) +#else +void wxIconBundle::AddIcon( const wxString& WXUNUSED(file), long WXUNUSED(type) ) +#endif +{ +#if wxUSE_IMAGE && (!defined(__WXMSW__) || wxUSE_WXDIB) + size_t count = wxImage::GetImageCount( file, type ); + size_t i; + wxImage image; + + for( i = 0; i < count; ++i ) + { + if( !image.LoadFile( file, type, i ) ) + { + wxLogError( _("Failed to load image %d from file '%s'."), + i, file.c_str() ); + continue; + } + + wxIcon* tmp = new wxIcon(); + tmp->CopyFromBitmap( wxBitmap( image ) ); + AddIcon( *tmp ); + delete tmp; + } +#endif +} + +const wxIcon& wxIconBundle::GetIcon( const wxSize& size ) const +{ + // temp. variable needed to fix Borland C++ 5.5.1 problem + // with passing a return value through two functions + wxIcon *tmp; + + size_t max = m_icons.GetCount(); + + // if we have one or no icon, we can return now without doing more work: + if ( max <= 1 ) + { + if ( max == 1 ) // fix for broken BCC + tmp = &m_icons[0]; + else // max == 0 + tmp = &wxNullIcon; + return *tmp; + } + + // there are more icons, find the best match: + wxCoord sysX = wxSystemSettings::GetMetric( wxSYS_ICON_X ), + sysY = wxSystemSettings::GetMetric( wxSYS_ICON_Y ); + + wxIcon *sysIcon = 0; + + for( size_t i = 0; i < max; i++ ) + { + if( !m_icons[i].Ok() ) + continue; + wxCoord sx = m_icons[i].GetWidth(), sy = m_icons[i].GetHeight(); + // requested size + if( sx == size.x && sy == size.y ) + { + tmp = &m_icons[i]; // fix for broken BCC + return *tmp; + } + // keep track if there is a system-size icon + if( sx == sysX && sy == sysY ) + sysIcon = &m_icons[i]; + } + + // return the system-sized icon if we've got one + if( sysIcon ) return *sysIcon; + // we certainly have at least one icon thanks to the <=1 check above + tmp = &m_icons[0]; + return *tmp; +} + +void wxIconBundle::AddIcon( const wxIcon& icon ) +{ + size_t i, max = m_icons.GetCount(); + + for( i = 0; i < max; ++i ) + { + wxIcon& tmp = m_icons[i]; + if( tmp.Ok() && tmp.GetWidth() == icon.GetWidth() && + tmp.GetHeight() == icon.GetHeight() ) + { + tmp = icon; + return; + } + } + + m_icons.Add( icon ); +} diff --git a/Source/3rd Party/wx/src/common/imagall.cpp b/Source/3rd Party/wx/src/common/imagall.cpp index 311c567e5..90e66ac95 100644 --- a/Source/3rd Party/wx/src/common/imagall.cpp +++ b/Source/3rd Party/wx/src/common/imagall.cpp @@ -1,64 +1,64 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagall.cpp -// Purpose: wxImage access all handler -// Author: Sylvain Bougnoux -// RCS-ID: $Id: imagall.cpp 42644 2006-10-29 18:58:25Z VZ $ -// Copyright: (c) Sylvain Bougnoux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE - -#ifndef WX_PRECOMP - #include "wx/image.h" -#endif - -//----------------------------------------------------------------------------- -// This function allows dynamic access to all image handlers compile within -// the library. This function should be in a separate file as some compilers -// link against the whole object file as long as just one of is function is called! - -void wxInitAllImageHandlers() -{ -#if wxUSE_LIBPNG - wxImage::AddHandler( new wxPNGHandler ); -#endif -#if wxUSE_LIBJPEG - wxImage::AddHandler( new wxJPEGHandler ); -#endif -#if wxUSE_LIBTIFF - wxImage::AddHandler( new wxTIFFHandler ); -#endif -#if wxUSE_GIF - wxImage::AddHandler( new wxGIFHandler ); -#endif -#if wxUSE_PNM - wxImage::AddHandler( new wxPNMHandler ); -#endif -#if wxUSE_PCX - wxImage::AddHandler( new wxPCXHandler ); -#endif -#if wxUSE_IFF - wxImage::AddHandler( new wxIFFHandler ); -#endif -#if wxUSE_ICO_CUR - wxImage::AddHandler( new wxICOHandler ); - wxImage::AddHandler( new wxCURHandler ); - wxImage::AddHandler( new wxANIHandler ); -#endif -#if wxUSE_TGA - wxImage::AddHandler( new wxTGAHandler ); -#endif -#if wxUSE_XPM - wxImage::AddHandler( new wxXPMHandler ); -#endif -} - -#endif // wxUSE_IMAGE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagall.cpp +// Purpose: wxImage access all handler +// Author: Sylvain Bougnoux +// RCS-ID: $Id: imagall.cpp 42644 2006-10-29 18:58:25Z VZ $ +// Copyright: (c) Sylvain Bougnoux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE + +#ifndef WX_PRECOMP + #include "wx/image.h" +#endif + +//----------------------------------------------------------------------------- +// This function allows dynamic access to all image handlers compile within +// the library. This function should be in a separate file as some compilers +// link against the whole object file as long as just one of is function is called! + +void wxInitAllImageHandlers() +{ +#if wxUSE_LIBPNG + wxImage::AddHandler( new wxPNGHandler ); +#endif +#if wxUSE_LIBJPEG + wxImage::AddHandler( new wxJPEGHandler ); +#endif +#if wxUSE_LIBTIFF + wxImage::AddHandler( new wxTIFFHandler ); +#endif +#if wxUSE_GIF + wxImage::AddHandler( new wxGIFHandler ); +#endif +#if wxUSE_PNM + wxImage::AddHandler( new wxPNMHandler ); +#endif +#if wxUSE_PCX + wxImage::AddHandler( new wxPCXHandler ); +#endif +#if wxUSE_IFF + wxImage::AddHandler( new wxIFFHandler ); +#endif +#if wxUSE_ICO_CUR + wxImage::AddHandler( new wxICOHandler ); + wxImage::AddHandler( new wxCURHandler ); + wxImage::AddHandler( new wxANIHandler ); +#endif +#if wxUSE_TGA + wxImage::AddHandler( new wxTGAHandler ); +#endif +#if wxUSE_XPM + wxImage::AddHandler( new wxXPMHandler ); +#endif +} + +#endif // wxUSE_IMAGE diff --git a/Source/3rd Party/wx/src/common/imagbmp.cpp b/Source/3rd Party/wx/src/common/imagbmp.cpp index 3b11ded17..d0930f464 100644 --- a/Source/3rd Party/wx/src/common/imagbmp.cpp +++ b/Source/3rd Party/wx/src/common/imagbmp.cpp @@ -1,1383 +1,1383 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagbmp.cpp -// Purpose: wxImage BMP,ICO and CUR handlers -// Author: Robert Roebling, Chris Elliott -// RCS-ID: $Id: imagbmp.cpp 54942 2008-08-03 00:23:38Z VZ $ -// Copyright: (c) Robert Roebling, Chris Elliott -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE - -#include "wx/imagbmp.h" - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/wrapwin.h" - #endif - #include "wx/log.h" - #include "wx/app.h" - #include "wx/bitmap.h" - #include "wx/palette.h" - #include "wx/intl.h" -#endif - -#include "wx/filefn.h" -#include "wx/wfstream.h" -#include "wx/quantize.h" -#include "wx/anidecod.h" - -// For memcpy -#include - -#ifdef __SALFORDC__ -#ifdef FAR -#undef FAR -#endif -#endif - -//----------------------------------------------------------------------------- -// wxBMPHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler) - -#if wxUSE_STREAMS - -#ifndef BI_RGB - #define BI_RGB 0 -#endif - -#ifndef BI_RLE8 -#define BI_RLE8 1 -#endif - -#ifndef BI_RLE4 -#define BI_RLE4 2 -#endif - -#ifndef BI_BITFIELDS -#define BI_BITFIELDS 3 -#endif - -#define poffset (line * width * 3 + column * 3) - -bool wxBMPHandler::SaveFile(wxImage *image, - wxOutputStream& stream, - bool verbose) -{ - return SaveDib(image, stream, verbose, true/*IsBmp*/, false/*IsMask*/); -} - -bool wxBMPHandler::SaveDib(wxImage *image, - wxOutputStream& stream, - bool verbose, - bool IsBmp, - bool IsMask) - -{ - wxCHECK_MSG( image, false, _T("invalid pointer in wxBMPHandler::SaveFile") ); - - if ( !image->Ok() ) - { - if ( verbose ) - wxLogError(_("BMP: Couldn't save invalid image.")); - return false; - } - - // get the format of the BMP file to save, else use 24bpp - unsigned format = wxBMP_24BPP; - if ( image->HasOption(wxIMAGE_OPTION_BMP_FORMAT) ) - format = image->GetOptionInt(wxIMAGE_OPTION_BMP_FORMAT); - - wxUint16 bpp; // # of bits per pixel - int palette_size; // # of color map entries, ie. 2^bpp colors - - // set the bpp and appropriate palette_size, and do additional checks - if ( (format == wxBMP_1BPP) || (format == wxBMP_1BPP_BW) ) - { - bpp = 1; - palette_size = 2; - } - else if ( format == wxBMP_4BPP ) - { - bpp = 4; - palette_size = 16; - } - else if ( (format == wxBMP_8BPP) || (format == wxBMP_8BPP_GREY) || - (format == wxBMP_8BPP_RED) || (format == wxBMP_8BPP_PALETTE) ) - { - // need to set a wxPalette to use this, HOW TO CHECK IF VALID, SIZE? - if ((format == wxBMP_8BPP_PALETTE) -#if wxUSE_PALETTE - && !image->HasPalette() -#endif // wxUSE_PALETTE - ) - { - if ( verbose ) - wxLogError(_("BMP: wxImage doesn't have own wxPalette.")); - return false; - } - bpp = 8; - palette_size = 256; - } - else // you get 24bpp - { - format = wxBMP_24BPP; - bpp = 24; - palette_size = 0; - } - - unsigned width = image->GetWidth(); - unsigned row_padding = (4 - int(width*bpp/8.0) % 4) % 4; // # bytes to pad to dword - unsigned row_width = int(width * bpp/8.0) + row_padding; // # of bytes per row - - struct - { - // BitmapHeader: - wxUint16 magic; // format magic, always 'BM' - wxUint32 filesize; // total file size, inc. headers - wxUint32 reserved; // for future use - wxUint32 data_offset; // image data offset in the file - - // BitmapInfoHeader: - wxUint32 bih_size; // 2nd part's size - wxUint32 width, height; // bitmap's dimensions - wxUint16 planes; // num of planes - wxUint16 bpp; // bits per pixel - wxUint32 compression; // compression method - wxUint32 size_of_bmp; // size of the bitmap - wxUint32 h_res, v_res; // image resolution in dpi - wxUint32 num_clrs; // number of colors used - wxUint32 num_signif_clrs;// number of significant colors - } hdr; - - wxUint32 hdr_size = 14/*BitmapHeader*/ + 40/*BitmapInfoHeader*/; - - hdr.magic = wxUINT16_SWAP_ON_BE(0x4D42/*'BM'*/); - hdr.filesize = wxUINT32_SWAP_ON_BE( hdr_size + palette_size*4 + - row_width * image->GetHeight() ); - hdr.reserved = 0; - hdr.data_offset = wxUINT32_SWAP_ON_BE(hdr_size + palette_size*4); - - hdr.bih_size = wxUINT32_SWAP_ON_BE(hdr_size - 14); - hdr.width = wxUINT32_SWAP_ON_BE(image->GetWidth()); - if ( IsBmp ) - { - hdr.height = wxUINT32_SWAP_ON_BE(image->GetHeight()); - } - else - { - hdr.height = wxUINT32_SWAP_ON_BE(2 * image->GetHeight()); - } - hdr.planes = wxUINT16_SWAP_ON_BE(1); // always 1 plane - hdr.bpp = wxUINT16_SWAP_ON_BE(bpp); - hdr.compression = 0; // RGB uncompressed - hdr.size_of_bmp = wxUINT32_SWAP_ON_BE(row_width * image->GetHeight()); - hdr.h_res = hdr.v_res = wxUINT32_SWAP_ON_BE(72); // 72dpi is standard - hdr.num_clrs = wxUINT32_SWAP_ON_BE(palette_size); // # colors in colormap - hdr.num_signif_clrs = 0; // all colors are significant - - if ( IsBmp ) - { - if (// VS: looks ugly but compilers tend to do ugly things with structs, - // like aligning hdr.filesize's ofset to dword :( - // VZ: we should add padding then... - !stream.Write(&hdr.magic, 2) || - !stream.Write(&hdr.filesize, 4) || - !stream.Write(&hdr.reserved, 4) || - !stream.Write(&hdr.data_offset, 4) - ) - { - if (verbose) - wxLogError(_("BMP: Couldn't write the file (Bitmap) header.")); - return false; - } - } - if ( !IsMask ) - { - if ( - !stream.Write(&hdr.bih_size, 4) || - !stream.Write(&hdr.width, 4) || - !stream.Write(&hdr.height, 4) || - !stream.Write(&hdr.planes, 2) || - !stream.Write(&hdr.bpp, 2) || - !stream.Write(&hdr.compression, 4) || - !stream.Write(&hdr.size_of_bmp, 4) || - !stream.Write(&hdr.h_res, 4) || - !stream.Write(&hdr.v_res, 4) || - !stream.Write(&hdr.num_clrs, 4) || - !stream.Write(&hdr.num_signif_clrs, 4) - ) - { - if (verbose) - wxLogError(_("BMP: Couldn't write the file (BitmapInfo) header.")); - return false; - } - } - - wxPalette *palette = NULL; // entries for quantized images - wxUint8 *rgbquad = NULL; // for the RGBQUAD bytes for the colormap - wxImage *q_image = NULL; // destination for quantized image - - // if <24bpp use quantization to reduce colors for *some* of the formats - if ( (format == wxBMP_1BPP) || (format == wxBMP_4BPP) || - (format == wxBMP_8BPP) || (format == wxBMP_8BPP_PALETTE) ) - { - // make a new palette and quantize the image - if (format != wxBMP_8BPP_PALETTE) - { - q_image = new wxImage(); - - // I get a delete error using Quantize when desired colors > 236 - int quantize = ((palette_size > 236) ? 236 : palette_size); - // fill the destination too, it gives much nicer 4bpp images - wxQuantize::Quantize( *image, *q_image, &palette, quantize, 0, - wxQUANTIZE_FILL_DESTINATION_IMAGE ); - } - else - { -#if wxUSE_PALETTE - palette = new wxPalette(image->GetPalette()); -#endif // wxUSE_PALETTE - } - - int i; - unsigned char r, g, b; - rgbquad = new wxUint8 [palette_size*4]; - - for (i = 0; i < palette_size; i++) - { -#if wxUSE_PALETTE - if ( !palette->GetRGB(i, &r, &g, &b) ) -#endif // wxUSE_PALETTE - r = g = b = 0; - - rgbquad[i*4] = b; - rgbquad[i*4+1] = g; - rgbquad[i*4+2] = r; - rgbquad[i*4+3] = 0; - } - } - // make a 256 entry greyscale colormap or 2 entry black & white - else if ( (format == wxBMP_8BPP_GREY) || (format == wxBMP_8BPP_RED) || - (format == wxBMP_1BPP_BW) ) - { - rgbquad = new wxUint8 [palette_size*4]; - - for ( int i = 0; i < palette_size; i++ ) - { - // if 1BPP_BW then the value should be either 0 or 255 - wxUint8 c = (wxUint8)((i > 0) && (format == wxBMP_1BPP_BW) ? 255 : i); - - rgbquad[i*4] = - rgbquad[i*4+1] = - rgbquad[i*4+2] = c; - rgbquad[i*4+3] = 0; - } - } - - // if the colormap was made, then it needs to be written - if (rgbquad) - { - if ( !IsMask ) - { - if ( !stream.Write(rgbquad, palette_size*4) ) - { - if (verbose) - wxLogError(_("BMP: Couldn't write RGB color map.")); - delete[] rgbquad; -#if wxUSE_PALETTE - delete palette; -#endif // wxUSE_PALETTE - delete q_image; - return false; - } - } - delete []rgbquad; - } - - // pointer to the image data, use quantized if available - wxUint8 *data = (wxUint8*) image->GetData(); - if (q_image) if (q_image->Ok()) data = (wxUint8*) q_image->GetData(); - - wxUint8 *buffer = new wxUint8[row_width]; - memset(buffer, 0, row_width); - int y; unsigned x; - long int pixel; - - for (y = image->GetHeight() -1; y >= 0; y--) - { - if ( format == wxBMP_24BPP ) // 3 bytes per pixel red,green,blue - { - for ( x = 0; x < width; x++ ) - { - pixel = 3*(y*width + x); - - buffer[3*x ] = data[pixel+2]; - buffer[3*x + 1] = data[pixel+1]; - buffer[3*x + 2] = data[pixel]; - } - } - else if ((format == wxBMP_8BPP) || // 1 byte per pixel in color - (format == wxBMP_8BPP_PALETTE)) - { - for (x = 0; x < width; x++) - { - pixel = 3*(y*width + x); -#if wxUSE_PALETTE - buffer[x] = (wxUint8)palette->GetPixel( data[pixel], - data[pixel+1], - data[pixel+2] ); -#else - // FIXME: what should this be? use some std palette maybe? - buffer[x] = 0; -#endif // wxUSE_PALETTE - } - } - else if ( format == wxBMP_8BPP_GREY ) // 1 byte per pix, rgb ave to grey - { - for (x = 0; x < width; x++) - { - pixel = 3*(y*width + x); - buffer[x] = (wxUint8)(.299*data[pixel] + - .587*data[pixel+1] + - .114*data[pixel+2]); - } - } - else if ( format == wxBMP_8BPP_RED ) // 1 byte per pixel, red as greys - { - for (x = 0; x < width; x++) - { - buffer[x] = (wxUint8)data[3*(y*width + x)]; - } - } - else if ( format == wxBMP_4BPP ) // 4 bpp in color - { - for (x = 0; x < width; x+=2) - { - pixel = 3*(y*width + x); - - // fill buffer, ignore if > width -#if wxUSE_PALETTE - buffer[x/2] = (wxUint8)( - ((wxUint8)palette->GetPixel(data[pixel], - data[pixel+1], - data[pixel+2]) << 4) | - (((x+1) > width) - ? 0 - : ((wxUint8)palette->GetPixel(data[pixel+3], - data[pixel+4], - data[pixel+5]) )) ); -#else - // FIXME: what should this be? use some std palette maybe? - buffer[x/2] = 0; -#endif // wxUSE_PALETTE - } - } - else if ( format == wxBMP_1BPP ) // 1 bpp in "color" - { - for (x = 0; x < width; x+=8) - { - pixel = 3*(y*width + x); - -#if wxUSE_PALETTE - buffer[x/8] = (wxUint8)( - ((wxUint8)palette->GetPixel(data[pixel], data[pixel+1], data[pixel+2]) << 7) | - (((x+1) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+3], data[pixel+4], data[pixel+5]) << 6)) | - (((x+2) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+6], data[pixel+7], data[pixel+8]) << 5)) | - (((x+3) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+9], data[pixel+10], data[pixel+11]) << 4)) | - (((x+4) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+12], data[pixel+13], data[pixel+14]) << 3)) | - (((x+5) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+15], data[pixel+16], data[pixel+17]) << 2)) | - (((x+6) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+18], data[pixel+19], data[pixel+20]) << 1)) | - (((x+7) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+21], data[pixel+22], data[pixel+23]) )) ); -#else - // FIXME: what should this be? use some std palette maybe? - buffer[x/8] = 0; -#endif // wxUSE_PALETTE - } - } - else if ( format == wxBMP_1BPP_BW ) // 1 bpp B&W colormap from red color ONLY - { - for (x = 0; x < width; x+=8) - { - pixel = 3*(y*width + x); - - buffer[x/8] = (wxUint8)( - (((wxUint8)(data[pixel] /128.)) << 7) | - (((x+1) > width) ? 0 : (((wxUint8)(data[pixel+3] /128.)) << 6)) | - (((x+2) > width) ? 0 : (((wxUint8)(data[pixel+6] /128.)) << 5)) | - (((x+3) > width) ? 0 : (((wxUint8)(data[pixel+9] /128.)) << 4)) | - (((x+4) > width) ? 0 : (((wxUint8)(data[pixel+12]/128.)) << 3)) | - (((x+5) > width) ? 0 : (((wxUint8)(data[pixel+15]/128.)) << 2)) | - (((x+6) > width) ? 0 : (((wxUint8)(data[pixel+18]/128.)) << 1)) | - (((x+7) > width) ? 0 : (((wxUint8)(data[pixel+21]/128.)) )) ); - } - } - - if ( !stream.Write(buffer, row_width) ) - { - if (verbose) - wxLogError(_("BMP: Couldn't write data.")); - delete[] buffer; -#if wxUSE_PALETTE - delete palette; -#endif // wxUSE_PALETTE - delete q_image; - return false; - } - } - delete[] buffer; -#if wxUSE_PALETTE - delete palette; -#endif // wxUSE_PALETTE - delete q_image; - - return true; -} - - -typedef struct -{ - unsigned char r, g, b; -} _cmap; - -bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, - int bpp, int ncolors, int comp, - wxFileOffset bmpOffset, wxInputStream& stream, - bool verbose, bool IsBmp, bool hasPalette) -{ - wxInt32 aDword, rmask = 0, gmask = 0, bmask = 0, amask = 0; - int rshift = 0, gshift = 0, bshift = 0, ashift = 0; - int rbits = 0, gbits = 0, bbits = 0, abits = 0; - wxInt32 dbuf[4]; - wxInt8 bbuf[4]; - wxUint8 aByte; - wxUint16 aWord; - - // allocate space for palette if needed: - _cmap *cmap; - - if ( bpp < 16 ) - { - cmap = new _cmap[ncolors]; - if ( !cmap ) - { - if (verbose) - wxLogError(_("BMP: Couldn't allocate memory.")); - return false; - } - } - else - cmap = NULL; - - // destroy existing here instead of: - image->Destroy(); - image->Create(width, height); - - unsigned char *ptr = image->GetData(); - - if ( !ptr ) - { - if ( verbose ) - wxLogError( _("BMP: Couldn't allocate memory.") ); - delete[] cmap; - return false; - } - - unsigned char *alpha; - if ( bpp == 32 ) - { - // tell the image to allocate an alpha buffer - image->SetAlpha(); - alpha = image->GetAlpha(); - if ( !alpha ) - { - if ( verbose ) - wxLogError(_("BMP: Couldn't allocate memory.")); - delete[] cmap; - return false; - } - } - else // no alpha - { - alpha = NULL; - } - - // Reading the palette, if it exists: - if ( bpp < 16 && ncolors != 0 ) - { - unsigned char* r = new unsigned char[ncolors]; - unsigned char* g = new unsigned char[ncolors]; - unsigned char* b = new unsigned char[ncolors]; - for (int j = 0; j < ncolors; j++) - { - if (hasPalette) - { - stream.Read(bbuf, 4); - cmap[j].b = bbuf[0]; - cmap[j].g = bbuf[1]; - cmap[j].r = bbuf[2]; - - r[j] = cmap[j].r; - g[j] = cmap[j].g; - b[j] = cmap[j].b; - } - else - { - //used in reading .ico file mask - r[j] = cmap[j].r = - g[j] = cmap[j].g = - b[j] = cmap[j].b = ( j ? 255 : 0 ); - } - } - -#if wxUSE_PALETTE - // Set the palette for the wxImage - image->SetPalette(wxPalette(ncolors, r, g, b)); -#endif // wxUSE_PALETTE - - delete[] r; - delete[] g; - delete[] b; - } - else if ( bpp == 16 || bpp == 32 ) - { - if ( comp == BI_BITFIELDS ) - { - int bit = 0; - stream.Read(dbuf, 4 * 3); - rmask = wxINT32_SWAP_ON_BE(dbuf[0]); - gmask = wxINT32_SWAP_ON_BE(dbuf[1]); - bmask = wxINT32_SWAP_ON_BE(dbuf[2]); - // find shift amount (Least significant bit of mask) - for (bit = bpp-1; bit>=0; bit--) - { - if (bmask & (1 << bit)) - bshift = bit; - if (gmask & (1 << bit)) - gshift = bit; - if (rmask & (1 << bit)) - rshift = bit; - } - // Find number of bits in mask (MSB-LSB+1) - for (bit = 0; bit < bpp; bit++) - { - if (bmask & (1 << bit)) - bbits = bit-bshift+1; - if (gmask & (1 << bit)) - gbits = bit-gshift+1; - if (rmask & (1 << bit)) - rbits = bit-rshift+1; - } - } - else if ( bpp == 16 ) - { - rmask = 0x7C00; - gmask = 0x03E0; - bmask = 0x001F; - rshift = 10; - gshift = 5; - bshift = 0; - rbits = 5; - gbits = 5; - bbits = 5; - } - else if ( bpp == 32 ) - { - rmask = 0x00FF0000; - gmask = 0x0000FF00; - bmask = 0x000000FF; - amask = 0xFF000000; - - ashift = 24; - rshift = 16; - gshift = 8; - bshift = 0; - abits = 8; - rbits = 8; - gbits = 8; - bbits = 8; - } - } - - /* - * Reading the image data - */ - if ( IsBmp ) - stream.SeekI(bmpOffset); // else icon, just carry on - - unsigned char *data = ptr; - - /* set the whole image to the background color */ - if ( bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8) ) - { - for (int i = 0; i < width * height; i++) - { - *ptr++ = cmap[0].r; - *ptr++ = cmap[0].g; - *ptr++ = cmap[0].b; - } - ptr = data; - } - - int linesize = ((width * bpp + 31) / 32) * 4; - - /* BMPs are stored upside down */ - for ( int line = (height - 1); line >= 0; line-- ) - { - int linepos = 0; - for ( int column = 0; column < width ; ) - { - if ( bpp < 16 ) - { - linepos++; - aByte = stream.GetC(); - if ( bpp == 1 ) - { - for (int bit = 0; bit < 8 && column < width; bit++) - { - int index = ((aByte & (0x80 >> bit)) ? 1 : 0); - ptr[poffset] = cmap[index].r; - ptr[poffset + 1] = cmap[index].g; - ptr[poffset + 2] = cmap[index].b; - column++; - } - } - else if ( bpp == 4 ) - { - if ( comp == BI_RLE4 ) - { - wxUint8 first; - first = aByte; - aByte = stream.GetC(); - if ( first == 0 ) - { - if ( aByte == 0 ) - { - if ( column > 0 ) - column = width; - } - else if ( aByte == 1 ) - { - column = width; - line = -1; - } - else if ( aByte == 2 ) - { - aByte = stream.GetC(); - column += aByte; - linepos = column * bpp / 4; - aByte = stream.GetC(); - line -= aByte; // upside down - } - else - { - int absolute = aByte; - wxUint8 nibble[2] ; - int readBytes = 0 ; - for (int k = 0; k < absolute; k++) - { - if ( !(k % 2 ) ) - { - ++readBytes ; - aByte = stream.GetC(); - nibble[0] = (wxUint8)( (aByte & 0xF0) >> 4 ) ; - nibble[1] = (wxUint8)( aByte & 0x0F ) ; - } - ptr[poffset ] = cmap[nibble[k%2]].r; - ptr[poffset + 1] = cmap[nibble[k%2]].g; - ptr[poffset + 2] = cmap[nibble[k%2]].b; - column++; - if ( k % 2 ) - linepos++; - } - if ( readBytes & 0x01 ) - aByte = stream.GetC(); - } - } - else - { - wxUint8 nibble[2] ; - nibble[0] = (wxUint8)( (aByte & 0xF0) >> 4 ) ; - nibble[1] = (wxUint8)( aByte & 0x0F ) ; - - for ( int l = 0; l < first && column < width; l++ ) - { - ptr[poffset ] = cmap[nibble[l%2]].r; - ptr[poffset + 1] = cmap[nibble[l%2]].g; - ptr[poffset + 2] = cmap[nibble[l%2]].b; - column++; - if ( l % 2 ) - linepos++; - } - } - } - else - { - for (int nibble = 0; nibble < 2 && column < width; nibble++) - { - int index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4)); - if ( index >= 16 ) - index = 15; - ptr[poffset] = cmap[index].r; - ptr[poffset + 1] = cmap[index].g; - ptr[poffset + 2] = cmap[index].b; - column++; - } - } - } - else if ( bpp == 8 ) - { - if ( comp == BI_RLE8 ) - { - unsigned char first; - first = aByte; - aByte = stream.GetC(); - if ( first == 0 ) - { - if ( aByte == 0 ) - { - /* column = width; */ - } - else if ( aByte == 1 ) - { - column = width; - line = -1; - } - else if ( aByte == 2 ) - { - aByte = stream.GetC(); - column += aByte; - linepos = column * bpp / 8; - aByte = stream.GetC(); - line += aByte; - } - else - { - int absolute = aByte; - for (int k = 0; k < absolute; k++) - { - linepos++; - aByte = stream.GetC(); - ptr[poffset ] = cmap[aByte].r; - ptr[poffset + 1] = cmap[aByte].g; - ptr[poffset + 2] = cmap[aByte].b; - column++; - } - if ( absolute & 0x01 ) - aByte = stream.GetC(); - } - } - else - { - for ( int l = 0; l < first && column < width; l++ ) - { - ptr[poffset ] = cmap[aByte].r; - ptr[poffset + 1] = cmap[aByte].g; - ptr[poffset + 2] = cmap[aByte].b; - column++; - linepos++; - } - } - } - else - { - ptr[poffset ] = cmap[aByte].r; - ptr[poffset + 1] = cmap[aByte].g; - ptr[poffset + 2] = cmap[aByte].b; - column++; - // linepos += size; seems to be wrong, RR - } - } - } - else if ( bpp == 24 ) - { - stream.Read(bbuf, 3); - linepos += 3; - ptr[poffset ] = (unsigned char)bbuf[2]; - ptr[poffset + 1] = (unsigned char)bbuf[1]; - ptr[poffset + 2] = (unsigned char)bbuf[0]; - column++; - } - else if ( bpp == 16 ) - { - unsigned char temp; - stream.Read(&aWord, 2); - aWord = wxUINT16_SWAP_ON_BE(aWord); - linepos += 2; - /* use the masks and calculated amonut of shift - to retrieve the color data out of the word. Then - shift it left by (8 - number of bits) such that - the image has the proper dynamic range */ - temp = (unsigned char)((aWord & rmask) >> rshift << (8-rbits)); - ptr[poffset] = temp; - temp = (unsigned char)((aWord & gmask) >> gshift << (8-gbits)); - ptr[poffset + 1] = temp; - temp = (unsigned char)((aWord & bmask) >> bshift << (8-bbits)); - ptr[poffset + 2] = temp; - column++; - } - else - { - unsigned char temp; - stream.Read(&aDword, 4); - aDword = wxINT32_SWAP_ON_BE(aDword); - linepos += 4; - temp = (unsigned char)((aDword & rmask) >> rshift); - ptr[poffset] = temp; - temp = (unsigned char)((aDword & gmask) >> gshift); - ptr[poffset + 1] = temp; - temp = (unsigned char)((aDword & bmask) >> bshift); - ptr[poffset + 2] = temp; - if ( alpha ) - { - temp = (unsigned char)((aDword & amask) >> ashift); - alpha[line * width + column] = temp; - } - column++; - } - } - while ( (linepos < linesize) && (comp != 1) && (comp != 2) ) - { - stream.Read(&aByte, 1); - linepos += 1; - if ( !stream ) - break; - } - } - - delete[] cmap; - - image->SetMask(false); - - const wxStreamError err = stream.GetLastError(); - return err == wxSTREAM_NO_ERROR || err == wxSTREAM_EOF; -} - -bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream, - bool verbose, bool IsBmp) -{ - wxUint16 aWord; - wxInt32 dbuf[4]; - wxInt8 bbuf[4]; - - wxFileOffset offset = 0; // keep gcc quiet - if ( IsBmp ) - { - // read the header off the .BMP format file - - offset = stream.TellI(); - if (offset == wxInvalidOffset) - offset = 0; - - stream.Read(bbuf, 2); - stream.Read(dbuf, 16); - } - else - { - stream.Read(dbuf, 4); - } - #if 0 // unused - wxInt32 size = wxINT32_SWAP_ON_BE(dbuf[0]); - #endif - offset = offset + wxINT32_SWAP_ON_BE(dbuf[2]); - - stream.Read(dbuf, 4 * 2); - int width = wxINT32_SWAP_ON_BE((int)dbuf[0]); - int height = wxINT32_SWAP_ON_BE((int)dbuf[1]); - if ( !IsBmp)height = height / 2; // for icons divide by 2 - - if ( width > 32767 ) - { - if (verbose) - wxLogError( _("DIB Header: Image width > 32767 pixels for file.") ); - return false; - } - if ( height > 32767 ) - { - if (verbose) - wxLogError( _("DIB Header: Image height > 32767 pixels for file.") ); - return false; - } - - stream.Read(&aWord, 2); - /* - TODO - int planes = (int)wxUINT16_SWAP_ON_BE( aWord ); - */ - stream.Read(&aWord, 2); - int bpp = wxUINT16_SWAP_ON_BE((int)aWord); - if ( bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32 ) - { - if (verbose) - wxLogError( _("DIB Header: Unknown bitdepth in file.") ); - return false; - } - - stream.Read(dbuf, 4 * 4); - int comp = wxINT32_SWAP_ON_BE((int)dbuf[0]); - if ( comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && - comp != BI_BITFIELDS ) - { - if (verbose) - wxLogError( _("DIB Header: Unknown encoding in file.") ); - return false; - } - - stream.Read(dbuf, 4 * 2); - int ncolors = wxINT32_SWAP_ON_BE( (int)dbuf[0] ); - if (ncolors == 0) - ncolors = 1 << bpp; - /* some more sanity checks */ - if (((comp == BI_RLE4) && (bpp != 4)) || - ((comp == BI_RLE8) && (bpp != 8)) || - ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32))) - { - if (verbose) - wxLogError( _("DIB Header: Encoding doesn't match bitdepth.") ); - return false; - } - - //read DIB; this is the BMP image or the XOR part of an icon image - if ( !DoLoadDib(image, width, height, bpp, ncolors, comp, offset, stream, - verbose, IsBmp, true) ) - { - if (verbose) - wxLogError( _("Error in reading image DIB.") ); - return false; - } - - if ( !IsBmp ) - { - //read Icon mask which is monochrome - //there is no palette, so we will create one - wxImage mask; - if ( !DoLoadDib(&mask, width, height, 1, 2, BI_RGB, offset, stream, - verbose, IsBmp, false) ) - { - if (verbose) - wxLogError( _("ICO: Error in reading mask DIB.") ); - return false; - } - image->SetMaskFromImage(mask, 255, 255, 255); - - } - - return true; -} - -bool wxBMPHandler::LoadFile(wxImage *image, wxInputStream& stream, - bool verbose, int WXUNUSED(index)) -{ - // Read a single DIB fom the file: - return LoadDib(image, stream, verbose, true/*isBmp*/); -} - -bool wxBMPHandler::DoCanRead(wxInputStream& stream) -{ - unsigned char hdr[2]; - - if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) - return false; - - // do we have the BMP file signature? - return hdr[0] == 'B' && hdr[1] == 'M'; -} - -#endif // wxUSE_STREAMS - - -#if wxUSE_ICO_CUR -//----------------------------------------------------------------------------- -// wxICOHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxICOHandler, wxBMPHandler) - -#if wxUSE_STREAMS - -struct ICONDIRENTRY -{ - wxUint8 bWidth; // Width of the image - wxUint8 bHeight; // Height of the image (times 2) - wxUint8 bColorCount; // Number of colors in image (0 if >=8bpp) - wxUint8 bReserved; // Reserved - - // these two are different in icons and cursors: - // icon or cursor - wxUint16 wPlanes; // Color Planes or XHotSpot - wxUint16 wBitCount; // Bits per pixel or YHotSpot - - wxUint32 dwBytesInRes; // how many bytes in this resource? - wxUint32 dwImageOffset; // where in the file is this image -}; - -struct ICONDIR -{ - wxUint16 idReserved; // Reserved - wxUint16 idType; // resource type (1 for icons, 2 for cursors) - wxUint16 idCount; // how many images? -}; - - -bool wxICOHandler::SaveFile(wxImage *image, - wxOutputStream& stream, - bool verbose) - -{ - //sanity check; icon must be less than 127 pixels high and 255 wide - if ( image->GetHeight () > 127 ) - { - if ( verbose ) - wxLogError(_("ICO: Image too tall for an icon.")); - return false; - } - if ( image->GetWidth () > 255 ) - { - if ( verbose ) - wxLogError(_("ICO: Image too wide for an icon.")); - return false; - } - - const int images = 1; // only generate one image - - // VS: This is a hack of sort - since ICO and CUR files are almost - // identical, we have all the meat in wxICOHandler and check for - // the actual (handler) type when the code has to distinguish between - // the two formats - int type = (this->GetType() == wxBITMAP_TYPE_CUR) ? 2 : 1; - - // write a header, (ICONDIR) - // Calculate the header size - wxUint32 offset = 3 * sizeof(wxUint16); - - ICONDIR IconDir; - IconDir.idReserved = 0; - IconDir.idType = wxUINT16_SWAP_ON_BE((wxUint16)type); - IconDir.idCount = wxUINT16_SWAP_ON_BE((wxUint16)images); - stream.Write(&IconDir.idReserved, sizeof(IconDir.idReserved)); - stream.Write(&IconDir.idType, sizeof(IconDir.idType)); - stream.Write(&IconDir.idCount, sizeof(IconDir.idCount)); - if ( !stream.IsOk() ) - { - if ( verbose ) - wxLogError(_("ICO: Error writing the image file!")); - return false; - } - - // for each iamage write a description ICONDIRENTRY: - ICONDIRENTRY icondirentry; - for (int img = 0; img < images; img++) - { - wxImage mask; - - if ( image->HasMask() ) - { - // make another image with black/white: - mask = image->ConvertToMono (image->GetMaskRed(), image->GetMaskGreen(), image->GetMaskBlue() ); - - // now we need to change the masked regions to black: - unsigned char r = image->GetMaskRed(); - unsigned char g = image->GetMaskGreen(); - unsigned char b = image->GetMaskBlue(); - if ( (r != 0) || (g != 0) || (b != 0) ) - { - // Go round and apply black to the masked bits: - int i, j; - for (i = 0; i < mask.GetWidth(); i++) - { - for (j = 0; j < mask.GetHeight(); j++) - { - if ((r == mask.GetRed(i, j)) && - (g == mask.GetGreen(i, j))&& - (b == mask.GetBlue(i, j)) ) - image->SetRGB(i, j, 0, 0, 0 ); - } - } - } - } - else - { - // just make a black mask all over: - mask = image->Copy(); - int i, j; - for (i = 0; i < mask.GetWidth(); i++) - for (j = 0; j < mask.GetHeight(); j++) - mask.SetRGB(i, j, 0, 0, 0 ); - } - // Set the formats for image and mask - // (Windows never saves with more than 8 colors): - image->SetOption(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_8BPP); - - // monochome bitmap: - mask.SetOption(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_1BPP_BW); - bool IsBmp = false; - bool IsMask = false; - - //calculate size and offset of image and mask - wxCountingOutputStream cStream; - bool bResult = SaveDib(image, cStream, verbose, IsBmp, IsMask); - if ( !bResult ) - { - if ( verbose ) - wxLogError(_("ICO: Error writing the image file!")); - return false; - } - IsMask = true; - - bResult = SaveDib(&mask, cStream, verbose, IsBmp, IsMask); - if ( !bResult ) - { - if ( verbose ) - wxLogError(_("ICO: Error writing the image file!")); - return false; - } - wxUint32 Size = cStream.GetSize(); - - // wxCountingOutputStream::IsOk() always returns true for now and this - // "if" provokes VC++ warnings in optimized build -#if 0 - if ( !cStream.Ok() ) - { - if ( verbose ) - wxLogError(_("ICO: Error writing the image file!")); - return false; - } -#endif // 0 - - offset = offset + sizeof(ICONDIRENTRY); - - icondirentry.bWidth = (wxUint8)image->GetWidth(); - icondirentry.bHeight = (wxUint8)(2 * image->GetHeight()); - icondirentry.bColorCount = 0; - icondirentry.bReserved = 0; - icondirentry.wPlanes = wxUINT16_SWAP_ON_BE(1); - icondirentry.wBitCount = wxUINT16_SWAP_ON_BE(wxBMP_8BPP); - if ( type == 2 /*CUR*/) - { - int hx = image->HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ? - image->GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X) : - image->GetWidth() / 2; - int hy = image->HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ? - image->GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y) : - image->GetHeight() / 2; - - // actually write the values of the hot spot here: - icondirentry.wPlanes = wxUINT16_SWAP_ON_BE((wxUint16)hx); - icondirentry.wBitCount = wxUINT16_SWAP_ON_BE((wxUint16)hy); - } - icondirentry.dwBytesInRes = wxUINT32_SWAP_ON_BE(Size); - icondirentry.dwImageOffset = wxUINT32_SWAP_ON_BE(offset); - - // increase size to allow for the data written: - offset += Size; - - // write to stream: - stream.Write(&icondirentry.bWidth, sizeof(icondirentry.bWidth)); - stream.Write(&icondirentry.bHeight, sizeof(icondirentry.bHeight)); - stream.Write(&icondirentry.bColorCount, sizeof(icondirentry.bColorCount)); - stream.Write(&icondirentry.bReserved, sizeof(icondirentry.bReserved)); - stream.Write(&icondirentry.wPlanes, sizeof(icondirentry.wPlanes)); - stream.Write(&icondirentry.wBitCount, sizeof(icondirentry.wBitCount)); - stream.Write(&icondirentry.dwBytesInRes, sizeof(icondirentry.dwBytesInRes)); - stream.Write(&icondirentry.dwImageOffset, sizeof(icondirentry.dwImageOffset)); - if ( !stream.IsOk() ) - { - if ( verbose ) - wxLogError(_("ICO: Error writing the image file!")); - return false; - } - - // actually save it: - IsMask = false; - bResult = SaveDib(image, stream, verbose, IsBmp, IsMask); - if ( !bResult ) - { - if ( verbose ) - wxLogError(_("ICO: Error writing the image file!")); - return false; - } - IsMask = true; - - bResult = SaveDib(&mask, stream, verbose, IsBmp, IsMask); - if ( !bResult ) - { - if ( verbose ) - wxLogError(_("ICO: Error writing the image file!")); - return false; - } - - } // end of for loop - - return true; -} - -bool wxICOHandler::LoadFile(wxImage *image, wxInputStream& stream, - bool verbose, int index) -{ - stream.SeekI(0); - return DoLoadFile(image, stream, verbose, index); -} - -bool wxICOHandler::DoLoadFile(wxImage *image, wxInputStream& stream, - bool WXUNUSED(verbose), int index) -{ - bool bResult wxDUMMY_INITIALIZE(false); - bool IsBmp = false; - - ICONDIR IconDir; - - wxFileOffset iPos = stream.TellI(); - stream.Read(&IconDir, sizeof(IconDir)); - wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount); - // nType is 1 for Icons, 2 for Cursors: - wxUint16 nType = wxUINT16_SWAP_ON_BE(IconDir.idType); - - // loop round the icons and choose the best one: - ICONDIRENTRY *pIconDirEntry = new ICONDIRENTRY[nIcons]; - ICONDIRENTRY *pCurrentEntry = pIconDirEntry; - int wMax = 0; - int colmax = 0; - int iSel = wxNOT_FOUND; - - for (int i = 0; i < nIcons; i++ ) - { - stream.Read(pCurrentEntry, sizeof(ICONDIRENTRY)); - // bHeight and bColorCount are wxUint8 - if ( pCurrentEntry->bWidth >= wMax ) - { - // see if we have more colors, ==0 indicates > 8bpp: - if ( pCurrentEntry->bColorCount == 0 ) - pCurrentEntry->bColorCount = 255; - if ( pCurrentEntry->bColorCount >= colmax ) - { - iSel = i; - wMax = pCurrentEntry->bWidth; - colmax = pCurrentEntry->bColorCount; - } - } - pCurrentEntry++; - } - - if ( index != -1 ) - { - // VS: Note that we *have* to run the loop above even if index != -1, because - // it reads ICONDIRENTRies. - iSel = index; - } - - if ( iSel == wxNOT_FOUND || iSel < 0 || iSel >= nIcons ) - { - wxLogError(_("ICO: Invalid icon index.")); - bResult = false; - } - else - { - // seek to selected icon: - pCurrentEntry = pIconDirEntry + iSel; - stream.SeekI(iPos + wxUINT32_SWAP_ON_BE(pCurrentEntry->dwImageOffset), wxFromStart); - bResult = LoadDib(image, stream, true, IsBmp); - bool bIsCursorType = (this->GetType() == wxBITMAP_TYPE_CUR) || (this->GetType() == wxBITMAP_TYPE_ANI); - if ( bResult && bIsCursorType && nType == 2 ) - { - // it is a cursor, so let's set the hotspot: - image->SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, wxUINT16_SWAP_ON_BE(pCurrentEntry->wPlanes)); - image->SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, wxUINT16_SWAP_ON_BE(pCurrentEntry->wBitCount)); - } - } - delete[] pIconDirEntry; - return bResult; -} - -int wxICOHandler::GetImageCount(wxInputStream& stream) -{ - ICONDIR IconDir; - wxFileOffset iPos = stream.TellI(); - stream.SeekI(0); - stream.Read(&IconDir, sizeof(IconDir)); - wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount); - stream.SeekI(iPos); - return (int)nIcons; -} - -bool wxICOHandler::DoCanRead(wxInputStream& stream) -{ - stream.SeekI(0); - unsigned char hdr[4]; - if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) - return false; - - // hdr[2] is one for an icon and two for a cursor - return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\1' && hdr[3] == '\0'; -} - -#endif // wxUSE_STREAMS - - -//----------------------------------------------------------------------------- -// wxCURHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxCURHandler, wxICOHandler) - -#if wxUSE_STREAMS - -bool wxCURHandler::DoCanRead(wxInputStream& stream) -{ - stream.SeekI(0); - unsigned char hdr[4]; - if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) - return false; - - // hdr[2] is one for an icon and two for a cursor - return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\2' && hdr[3] == '\0'; -} - -#endif // wxUSE_STREAMS - -//----------------------------------------------------------------------------- -// wxANIHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxANIHandler, wxCURHandler) - -#if wxUSE_STREAMS - -bool wxANIHandler::LoadFile(wxImage *image, wxInputStream& stream, - bool WXUNUSED(verbose), int index) -{ - wxANIDecoder decoder; - if (!decoder.Load(stream)) - return false; - - return decoder.ConvertToImage(index != -1 ? (size_t)index : 0, image); -} - -bool wxANIHandler::DoCanRead(wxInputStream& stream) -{ - wxANIDecoder decod; - return decod.CanRead(stream); -} - -int wxANIHandler::GetImageCount(wxInputStream& stream) -{ - wxANIDecoder decoder; - if (!decoder.Load(stream)) - return wxNOT_FOUND; - - return decoder.GetFrameCount(); -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_ICO_CUR - -#endif // wxUSE_IMAGE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagbmp.cpp +// Purpose: wxImage BMP,ICO and CUR handlers +// Author: Robert Roebling, Chris Elliott +// RCS-ID: $Id: imagbmp.cpp 54942 2008-08-03 00:23:38Z VZ $ +// Copyright: (c) Robert Roebling, Chris Elliott +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE + +#include "wx/imagbmp.h" + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" + #endif + #include "wx/log.h" + #include "wx/app.h" + #include "wx/bitmap.h" + #include "wx/palette.h" + #include "wx/intl.h" +#endif + +#include "wx/filefn.h" +#include "wx/wfstream.h" +#include "wx/quantize.h" +#include "wx/anidecod.h" + +// For memcpy +#include + +#ifdef __SALFORDC__ +#ifdef FAR +#undef FAR +#endif +#endif + +//----------------------------------------------------------------------------- +// wxBMPHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxBMPHandler,wxImageHandler) + +#if wxUSE_STREAMS + +#ifndef BI_RGB + #define BI_RGB 0 +#endif + +#ifndef BI_RLE8 +#define BI_RLE8 1 +#endif + +#ifndef BI_RLE4 +#define BI_RLE4 2 +#endif + +#ifndef BI_BITFIELDS +#define BI_BITFIELDS 3 +#endif + +#define poffset (line * width * 3 + column * 3) + +bool wxBMPHandler::SaveFile(wxImage *image, + wxOutputStream& stream, + bool verbose) +{ + return SaveDib(image, stream, verbose, true/*IsBmp*/, false/*IsMask*/); +} + +bool wxBMPHandler::SaveDib(wxImage *image, + wxOutputStream& stream, + bool verbose, + bool IsBmp, + bool IsMask) + +{ + wxCHECK_MSG( image, false, _T("invalid pointer in wxBMPHandler::SaveFile") ); + + if ( !image->Ok() ) + { + if ( verbose ) + wxLogError(_("BMP: Couldn't save invalid image.")); + return false; + } + + // get the format of the BMP file to save, else use 24bpp + unsigned format = wxBMP_24BPP; + if ( image->HasOption(wxIMAGE_OPTION_BMP_FORMAT) ) + format = image->GetOptionInt(wxIMAGE_OPTION_BMP_FORMAT); + + wxUint16 bpp; // # of bits per pixel + int palette_size; // # of color map entries, ie. 2^bpp colors + + // set the bpp and appropriate palette_size, and do additional checks + if ( (format == wxBMP_1BPP) || (format == wxBMP_1BPP_BW) ) + { + bpp = 1; + palette_size = 2; + } + else if ( format == wxBMP_4BPP ) + { + bpp = 4; + palette_size = 16; + } + else if ( (format == wxBMP_8BPP) || (format == wxBMP_8BPP_GREY) || + (format == wxBMP_8BPP_RED) || (format == wxBMP_8BPP_PALETTE) ) + { + // need to set a wxPalette to use this, HOW TO CHECK IF VALID, SIZE? + if ((format == wxBMP_8BPP_PALETTE) +#if wxUSE_PALETTE + && !image->HasPalette() +#endif // wxUSE_PALETTE + ) + { + if ( verbose ) + wxLogError(_("BMP: wxImage doesn't have own wxPalette.")); + return false; + } + bpp = 8; + palette_size = 256; + } + else // you get 24bpp + { + format = wxBMP_24BPP; + bpp = 24; + palette_size = 0; + } + + unsigned width = image->GetWidth(); + unsigned row_padding = (4 - int(width*bpp/8.0) % 4) % 4; // # bytes to pad to dword + unsigned row_width = int(width * bpp/8.0) + row_padding; // # of bytes per row + + struct + { + // BitmapHeader: + wxUint16 magic; // format magic, always 'BM' + wxUint32 filesize; // total file size, inc. headers + wxUint32 reserved; // for future use + wxUint32 data_offset; // image data offset in the file + + // BitmapInfoHeader: + wxUint32 bih_size; // 2nd part's size + wxUint32 width, height; // bitmap's dimensions + wxUint16 planes; // num of planes + wxUint16 bpp; // bits per pixel + wxUint32 compression; // compression method + wxUint32 size_of_bmp; // size of the bitmap + wxUint32 h_res, v_res; // image resolution in dpi + wxUint32 num_clrs; // number of colors used + wxUint32 num_signif_clrs;// number of significant colors + } hdr; + + wxUint32 hdr_size = 14/*BitmapHeader*/ + 40/*BitmapInfoHeader*/; + + hdr.magic = wxUINT16_SWAP_ON_BE(0x4D42/*'BM'*/); + hdr.filesize = wxUINT32_SWAP_ON_BE( hdr_size + palette_size*4 + + row_width * image->GetHeight() ); + hdr.reserved = 0; + hdr.data_offset = wxUINT32_SWAP_ON_BE(hdr_size + palette_size*4); + + hdr.bih_size = wxUINT32_SWAP_ON_BE(hdr_size - 14); + hdr.width = wxUINT32_SWAP_ON_BE(image->GetWidth()); + if ( IsBmp ) + { + hdr.height = wxUINT32_SWAP_ON_BE(image->GetHeight()); + } + else + { + hdr.height = wxUINT32_SWAP_ON_BE(2 * image->GetHeight()); + } + hdr.planes = wxUINT16_SWAP_ON_BE(1); // always 1 plane + hdr.bpp = wxUINT16_SWAP_ON_BE(bpp); + hdr.compression = 0; // RGB uncompressed + hdr.size_of_bmp = wxUINT32_SWAP_ON_BE(row_width * image->GetHeight()); + hdr.h_res = hdr.v_res = wxUINT32_SWAP_ON_BE(72); // 72dpi is standard + hdr.num_clrs = wxUINT32_SWAP_ON_BE(palette_size); // # colors in colormap + hdr.num_signif_clrs = 0; // all colors are significant + + if ( IsBmp ) + { + if (// VS: looks ugly but compilers tend to do ugly things with structs, + // like aligning hdr.filesize's ofset to dword :( + // VZ: we should add padding then... + !stream.Write(&hdr.magic, 2) || + !stream.Write(&hdr.filesize, 4) || + !stream.Write(&hdr.reserved, 4) || + !stream.Write(&hdr.data_offset, 4) + ) + { + if (verbose) + wxLogError(_("BMP: Couldn't write the file (Bitmap) header.")); + return false; + } + } + if ( !IsMask ) + { + if ( + !stream.Write(&hdr.bih_size, 4) || + !stream.Write(&hdr.width, 4) || + !stream.Write(&hdr.height, 4) || + !stream.Write(&hdr.planes, 2) || + !stream.Write(&hdr.bpp, 2) || + !stream.Write(&hdr.compression, 4) || + !stream.Write(&hdr.size_of_bmp, 4) || + !stream.Write(&hdr.h_res, 4) || + !stream.Write(&hdr.v_res, 4) || + !stream.Write(&hdr.num_clrs, 4) || + !stream.Write(&hdr.num_signif_clrs, 4) + ) + { + if (verbose) + wxLogError(_("BMP: Couldn't write the file (BitmapInfo) header.")); + return false; + } + } + + wxPalette *palette = NULL; // entries for quantized images + wxUint8 *rgbquad = NULL; // for the RGBQUAD bytes for the colormap + wxImage *q_image = NULL; // destination for quantized image + + // if <24bpp use quantization to reduce colors for *some* of the formats + if ( (format == wxBMP_1BPP) || (format == wxBMP_4BPP) || + (format == wxBMP_8BPP) || (format == wxBMP_8BPP_PALETTE) ) + { + // make a new palette and quantize the image + if (format != wxBMP_8BPP_PALETTE) + { + q_image = new wxImage(); + + // I get a delete error using Quantize when desired colors > 236 + int quantize = ((palette_size > 236) ? 236 : palette_size); + // fill the destination too, it gives much nicer 4bpp images + wxQuantize::Quantize( *image, *q_image, &palette, quantize, 0, + wxQUANTIZE_FILL_DESTINATION_IMAGE ); + } + else + { +#if wxUSE_PALETTE + palette = new wxPalette(image->GetPalette()); +#endif // wxUSE_PALETTE + } + + int i; + unsigned char r, g, b; + rgbquad = new wxUint8 [palette_size*4]; + + for (i = 0; i < palette_size; i++) + { +#if wxUSE_PALETTE + if ( !palette->GetRGB(i, &r, &g, &b) ) +#endif // wxUSE_PALETTE + r = g = b = 0; + + rgbquad[i*4] = b; + rgbquad[i*4+1] = g; + rgbquad[i*4+2] = r; + rgbquad[i*4+3] = 0; + } + } + // make a 256 entry greyscale colormap or 2 entry black & white + else if ( (format == wxBMP_8BPP_GREY) || (format == wxBMP_8BPP_RED) || + (format == wxBMP_1BPP_BW) ) + { + rgbquad = new wxUint8 [palette_size*4]; + + for ( int i = 0; i < palette_size; i++ ) + { + // if 1BPP_BW then the value should be either 0 or 255 + wxUint8 c = (wxUint8)((i > 0) && (format == wxBMP_1BPP_BW) ? 255 : i); + + rgbquad[i*4] = + rgbquad[i*4+1] = + rgbquad[i*4+2] = c; + rgbquad[i*4+3] = 0; + } + } + + // if the colormap was made, then it needs to be written + if (rgbquad) + { + if ( !IsMask ) + { + if ( !stream.Write(rgbquad, palette_size*4) ) + { + if (verbose) + wxLogError(_("BMP: Couldn't write RGB color map.")); + delete[] rgbquad; +#if wxUSE_PALETTE + delete palette; +#endif // wxUSE_PALETTE + delete q_image; + return false; + } + } + delete []rgbquad; + } + + // pointer to the image data, use quantized if available + wxUint8 *data = (wxUint8*) image->GetData(); + if (q_image) if (q_image->Ok()) data = (wxUint8*) q_image->GetData(); + + wxUint8 *buffer = new wxUint8[row_width]; + memset(buffer, 0, row_width); + int y; unsigned x; + long int pixel; + + for (y = image->GetHeight() -1; y >= 0; y--) + { + if ( format == wxBMP_24BPP ) // 3 bytes per pixel red,green,blue + { + for ( x = 0; x < width; x++ ) + { + pixel = 3*(y*width + x); + + buffer[3*x ] = data[pixel+2]; + buffer[3*x + 1] = data[pixel+1]; + buffer[3*x + 2] = data[pixel]; + } + } + else if ((format == wxBMP_8BPP) || // 1 byte per pixel in color + (format == wxBMP_8BPP_PALETTE)) + { + for (x = 0; x < width; x++) + { + pixel = 3*(y*width + x); +#if wxUSE_PALETTE + buffer[x] = (wxUint8)palette->GetPixel( data[pixel], + data[pixel+1], + data[pixel+2] ); +#else + // FIXME: what should this be? use some std palette maybe? + buffer[x] = 0; +#endif // wxUSE_PALETTE + } + } + else if ( format == wxBMP_8BPP_GREY ) // 1 byte per pix, rgb ave to grey + { + for (x = 0; x < width; x++) + { + pixel = 3*(y*width + x); + buffer[x] = (wxUint8)(.299*data[pixel] + + .587*data[pixel+1] + + .114*data[pixel+2]); + } + } + else if ( format == wxBMP_8BPP_RED ) // 1 byte per pixel, red as greys + { + for (x = 0; x < width; x++) + { + buffer[x] = (wxUint8)data[3*(y*width + x)]; + } + } + else if ( format == wxBMP_4BPP ) // 4 bpp in color + { + for (x = 0; x < width; x+=2) + { + pixel = 3*(y*width + x); + + // fill buffer, ignore if > width +#if wxUSE_PALETTE + buffer[x/2] = (wxUint8)( + ((wxUint8)palette->GetPixel(data[pixel], + data[pixel+1], + data[pixel+2]) << 4) | + (((x+1) > width) + ? 0 + : ((wxUint8)palette->GetPixel(data[pixel+3], + data[pixel+4], + data[pixel+5]) )) ); +#else + // FIXME: what should this be? use some std palette maybe? + buffer[x/2] = 0; +#endif // wxUSE_PALETTE + } + } + else if ( format == wxBMP_1BPP ) // 1 bpp in "color" + { + for (x = 0; x < width; x+=8) + { + pixel = 3*(y*width + x); + +#if wxUSE_PALETTE + buffer[x/8] = (wxUint8)( + ((wxUint8)palette->GetPixel(data[pixel], data[pixel+1], data[pixel+2]) << 7) | + (((x+1) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+3], data[pixel+4], data[pixel+5]) << 6)) | + (((x+2) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+6], data[pixel+7], data[pixel+8]) << 5)) | + (((x+3) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+9], data[pixel+10], data[pixel+11]) << 4)) | + (((x+4) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+12], data[pixel+13], data[pixel+14]) << 3)) | + (((x+5) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+15], data[pixel+16], data[pixel+17]) << 2)) | + (((x+6) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+18], data[pixel+19], data[pixel+20]) << 1)) | + (((x+7) > width) ? 0 : ((wxUint8)palette->GetPixel(data[pixel+21], data[pixel+22], data[pixel+23]) )) ); +#else + // FIXME: what should this be? use some std palette maybe? + buffer[x/8] = 0; +#endif // wxUSE_PALETTE + } + } + else if ( format == wxBMP_1BPP_BW ) // 1 bpp B&W colormap from red color ONLY + { + for (x = 0; x < width; x+=8) + { + pixel = 3*(y*width + x); + + buffer[x/8] = (wxUint8)( + (((wxUint8)(data[pixel] /128.)) << 7) | + (((x+1) > width) ? 0 : (((wxUint8)(data[pixel+3] /128.)) << 6)) | + (((x+2) > width) ? 0 : (((wxUint8)(data[pixel+6] /128.)) << 5)) | + (((x+3) > width) ? 0 : (((wxUint8)(data[pixel+9] /128.)) << 4)) | + (((x+4) > width) ? 0 : (((wxUint8)(data[pixel+12]/128.)) << 3)) | + (((x+5) > width) ? 0 : (((wxUint8)(data[pixel+15]/128.)) << 2)) | + (((x+6) > width) ? 0 : (((wxUint8)(data[pixel+18]/128.)) << 1)) | + (((x+7) > width) ? 0 : (((wxUint8)(data[pixel+21]/128.)) )) ); + } + } + + if ( !stream.Write(buffer, row_width) ) + { + if (verbose) + wxLogError(_("BMP: Couldn't write data.")); + delete[] buffer; +#if wxUSE_PALETTE + delete palette; +#endif // wxUSE_PALETTE + delete q_image; + return false; + } + } + delete[] buffer; +#if wxUSE_PALETTE + delete palette; +#endif // wxUSE_PALETTE + delete q_image; + + return true; +} + + +typedef struct +{ + unsigned char r, g, b; +} _cmap; + +bool wxBMPHandler::DoLoadDib(wxImage * image, int width, int height, + int bpp, int ncolors, int comp, + wxFileOffset bmpOffset, wxInputStream& stream, + bool verbose, bool IsBmp, bool hasPalette) +{ + wxInt32 aDword, rmask = 0, gmask = 0, bmask = 0, amask = 0; + int rshift = 0, gshift = 0, bshift = 0, ashift = 0; + int rbits = 0, gbits = 0, bbits = 0, abits = 0; + wxInt32 dbuf[4]; + wxInt8 bbuf[4]; + wxUint8 aByte; + wxUint16 aWord; + + // allocate space for palette if needed: + _cmap *cmap; + + if ( bpp < 16 ) + { + cmap = new _cmap[ncolors]; + if ( !cmap ) + { + if (verbose) + wxLogError(_("BMP: Couldn't allocate memory.")); + return false; + } + } + else + cmap = NULL; + + // destroy existing here instead of: + image->Destroy(); + image->Create(width, height); + + unsigned char *ptr = image->GetData(); + + if ( !ptr ) + { + if ( verbose ) + wxLogError( _("BMP: Couldn't allocate memory.") ); + delete[] cmap; + return false; + } + + unsigned char *alpha; + if ( bpp == 32 ) + { + // tell the image to allocate an alpha buffer + image->SetAlpha(); + alpha = image->GetAlpha(); + if ( !alpha ) + { + if ( verbose ) + wxLogError(_("BMP: Couldn't allocate memory.")); + delete[] cmap; + return false; + } + } + else // no alpha + { + alpha = NULL; + } + + // Reading the palette, if it exists: + if ( bpp < 16 && ncolors != 0 ) + { + unsigned char* r = new unsigned char[ncolors]; + unsigned char* g = new unsigned char[ncolors]; + unsigned char* b = new unsigned char[ncolors]; + for (int j = 0; j < ncolors; j++) + { + if (hasPalette) + { + stream.Read(bbuf, 4); + cmap[j].b = bbuf[0]; + cmap[j].g = bbuf[1]; + cmap[j].r = bbuf[2]; + + r[j] = cmap[j].r; + g[j] = cmap[j].g; + b[j] = cmap[j].b; + } + else + { + //used in reading .ico file mask + r[j] = cmap[j].r = + g[j] = cmap[j].g = + b[j] = cmap[j].b = ( j ? 255 : 0 ); + } + } + +#if wxUSE_PALETTE + // Set the palette for the wxImage + image->SetPalette(wxPalette(ncolors, r, g, b)); +#endif // wxUSE_PALETTE + + delete[] r; + delete[] g; + delete[] b; + } + else if ( bpp == 16 || bpp == 32 ) + { + if ( comp == BI_BITFIELDS ) + { + int bit = 0; + stream.Read(dbuf, 4 * 3); + rmask = wxINT32_SWAP_ON_BE(dbuf[0]); + gmask = wxINT32_SWAP_ON_BE(dbuf[1]); + bmask = wxINT32_SWAP_ON_BE(dbuf[2]); + // find shift amount (Least significant bit of mask) + for (bit = bpp-1; bit>=0; bit--) + { + if (bmask & (1 << bit)) + bshift = bit; + if (gmask & (1 << bit)) + gshift = bit; + if (rmask & (1 << bit)) + rshift = bit; + } + // Find number of bits in mask (MSB-LSB+1) + for (bit = 0; bit < bpp; bit++) + { + if (bmask & (1 << bit)) + bbits = bit-bshift+1; + if (gmask & (1 << bit)) + gbits = bit-gshift+1; + if (rmask & (1 << bit)) + rbits = bit-rshift+1; + } + } + else if ( bpp == 16 ) + { + rmask = 0x7C00; + gmask = 0x03E0; + bmask = 0x001F; + rshift = 10; + gshift = 5; + bshift = 0; + rbits = 5; + gbits = 5; + bbits = 5; + } + else if ( bpp == 32 ) + { + rmask = 0x00FF0000; + gmask = 0x0000FF00; + bmask = 0x000000FF; + amask = 0xFF000000; + + ashift = 24; + rshift = 16; + gshift = 8; + bshift = 0; + abits = 8; + rbits = 8; + gbits = 8; + bbits = 8; + } + } + + /* + * Reading the image data + */ + if ( IsBmp ) + stream.SeekI(bmpOffset); // else icon, just carry on + + unsigned char *data = ptr; + + /* set the whole image to the background color */ + if ( bpp < 16 && (comp == BI_RLE4 || comp == BI_RLE8) ) + { + for (int i = 0; i < width * height; i++) + { + *ptr++ = cmap[0].r; + *ptr++ = cmap[0].g; + *ptr++ = cmap[0].b; + } + ptr = data; + } + + int linesize = ((width * bpp + 31) / 32) * 4; + + /* BMPs are stored upside down */ + for ( int line = (height - 1); line >= 0; line-- ) + { + int linepos = 0; + for ( int column = 0; column < width ; ) + { + if ( bpp < 16 ) + { + linepos++; + aByte = stream.GetC(); + if ( bpp == 1 ) + { + for (int bit = 0; bit < 8 && column < width; bit++) + { + int index = ((aByte & (0x80 >> bit)) ? 1 : 0); + ptr[poffset] = cmap[index].r; + ptr[poffset + 1] = cmap[index].g; + ptr[poffset + 2] = cmap[index].b; + column++; + } + } + else if ( bpp == 4 ) + { + if ( comp == BI_RLE4 ) + { + wxUint8 first; + first = aByte; + aByte = stream.GetC(); + if ( first == 0 ) + { + if ( aByte == 0 ) + { + if ( column > 0 ) + column = width; + } + else if ( aByte == 1 ) + { + column = width; + line = -1; + } + else if ( aByte == 2 ) + { + aByte = stream.GetC(); + column += aByte; + linepos = column * bpp / 4; + aByte = stream.GetC(); + line -= aByte; // upside down + } + else + { + int absolute = aByte; + wxUint8 nibble[2] ; + int readBytes = 0 ; + for (int k = 0; k < absolute; k++) + { + if ( !(k % 2 ) ) + { + ++readBytes ; + aByte = stream.GetC(); + nibble[0] = (wxUint8)( (aByte & 0xF0) >> 4 ) ; + nibble[1] = (wxUint8)( aByte & 0x0F ) ; + } + ptr[poffset ] = cmap[nibble[k%2]].r; + ptr[poffset + 1] = cmap[nibble[k%2]].g; + ptr[poffset + 2] = cmap[nibble[k%2]].b; + column++; + if ( k % 2 ) + linepos++; + } + if ( readBytes & 0x01 ) + aByte = stream.GetC(); + } + } + else + { + wxUint8 nibble[2] ; + nibble[0] = (wxUint8)( (aByte & 0xF0) >> 4 ) ; + nibble[1] = (wxUint8)( aByte & 0x0F ) ; + + for ( int l = 0; l < first && column < width; l++ ) + { + ptr[poffset ] = cmap[nibble[l%2]].r; + ptr[poffset + 1] = cmap[nibble[l%2]].g; + ptr[poffset + 2] = cmap[nibble[l%2]].b; + column++; + if ( l % 2 ) + linepos++; + } + } + } + else + { + for (int nibble = 0; nibble < 2 && column < width; nibble++) + { + int index = ((aByte & (0xF0 >> nibble * 4)) >> (!nibble * 4)); + if ( index >= 16 ) + index = 15; + ptr[poffset] = cmap[index].r; + ptr[poffset + 1] = cmap[index].g; + ptr[poffset + 2] = cmap[index].b; + column++; + } + } + } + else if ( bpp == 8 ) + { + if ( comp == BI_RLE8 ) + { + unsigned char first; + first = aByte; + aByte = stream.GetC(); + if ( first == 0 ) + { + if ( aByte == 0 ) + { + /* column = width; */ + } + else if ( aByte == 1 ) + { + column = width; + line = -1; + } + else if ( aByte == 2 ) + { + aByte = stream.GetC(); + column += aByte; + linepos = column * bpp / 8; + aByte = stream.GetC(); + line += aByte; + } + else + { + int absolute = aByte; + for (int k = 0; k < absolute; k++) + { + linepos++; + aByte = stream.GetC(); + ptr[poffset ] = cmap[aByte].r; + ptr[poffset + 1] = cmap[aByte].g; + ptr[poffset + 2] = cmap[aByte].b; + column++; + } + if ( absolute & 0x01 ) + aByte = stream.GetC(); + } + } + else + { + for ( int l = 0; l < first && column < width; l++ ) + { + ptr[poffset ] = cmap[aByte].r; + ptr[poffset + 1] = cmap[aByte].g; + ptr[poffset + 2] = cmap[aByte].b; + column++; + linepos++; + } + } + } + else + { + ptr[poffset ] = cmap[aByte].r; + ptr[poffset + 1] = cmap[aByte].g; + ptr[poffset + 2] = cmap[aByte].b; + column++; + // linepos += size; seems to be wrong, RR + } + } + } + else if ( bpp == 24 ) + { + stream.Read(bbuf, 3); + linepos += 3; + ptr[poffset ] = (unsigned char)bbuf[2]; + ptr[poffset + 1] = (unsigned char)bbuf[1]; + ptr[poffset + 2] = (unsigned char)bbuf[0]; + column++; + } + else if ( bpp == 16 ) + { + unsigned char temp; + stream.Read(&aWord, 2); + aWord = wxUINT16_SWAP_ON_BE(aWord); + linepos += 2; + /* use the masks and calculated amonut of shift + to retrieve the color data out of the word. Then + shift it left by (8 - number of bits) such that + the image has the proper dynamic range */ + temp = (unsigned char)((aWord & rmask) >> rshift << (8-rbits)); + ptr[poffset] = temp; + temp = (unsigned char)((aWord & gmask) >> gshift << (8-gbits)); + ptr[poffset + 1] = temp; + temp = (unsigned char)((aWord & bmask) >> bshift << (8-bbits)); + ptr[poffset + 2] = temp; + column++; + } + else + { + unsigned char temp; + stream.Read(&aDword, 4); + aDword = wxINT32_SWAP_ON_BE(aDword); + linepos += 4; + temp = (unsigned char)((aDword & rmask) >> rshift); + ptr[poffset] = temp; + temp = (unsigned char)((aDword & gmask) >> gshift); + ptr[poffset + 1] = temp; + temp = (unsigned char)((aDword & bmask) >> bshift); + ptr[poffset + 2] = temp; + if ( alpha ) + { + temp = (unsigned char)((aDword & amask) >> ashift); + alpha[line * width + column] = temp; + } + column++; + } + } + while ( (linepos < linesize) && (comp != 1) && (comp != 2) ) + { + stream.Read(&aByte, 1); + linepos += 1; + if ( !stream ) + break; + } + } + + delete[] cmap; + + image->SetMask(false); + + const wxStreamError err = stream.GetLastError(); + return err == wxSTREAM_NO_ERROR || err == wxSTREAM_EOF; +} + +bool wxBMPHandler::LoadDib(wxImage *image, wxInputStream& stream, + bool verbose, bool IsBmp) +{ + wxUint16 aWord; + wxInt32 dbuf[4]; + wxInt8 bbuf[4]; + + wxFileOffset offset = 0; // keep gcc quiet + if ( IsBmp ) + { + // read the header off the .BMP format file + + offset = stream.TellI(); + if (offset == wxInvalidOffset) + offset = 0; + + stream.Read(bbuf, 2); + stream.Read(dbuf, 16); + } + else + { + stream.Read(dbuf, 4); + } + #if 0 // unused + wxInt32 size = wxINT32_SWAP_ON_BE(dbuf[0]); + #endif + offset = offset + wxINT32_SWAP_ON_BE(dbuf[2]); + + stream.Read(dbuf, 4 * 2); + int width = wxINT32_SWAP_ON_BE((int)dbuf[0]); + int height = wxINT32_SWAP_ON_BE((int)dbuf[1]); + if ( !IsBmp)height = height / 2; // for icons divide by 2 + + if ( width > 32767 ) + { + if (verbose) + wxLogError( _("DIB Header: Image width > 32767 pixels for file.") ); + return false; + } + if ( height > 32767 ) + { + if (verbose) + wxLogError( _("DIB Header: Image height > 32767 pixels for file.") ); + return false; + } + + stream.Read(&aWord, 2); + /* + TODO + int planes = (int)wxUINT16_SWAP_ON_BE( aWord ); + */ + stream.Read(&aWord, 2); + int bpp = wxUINT16_SWAP_ON_BE((int)aWord); + if ( bpp != 1 && bpp != 4 && bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32 ) + { + if (verbose) + wxLogError( _("DIB Header: Unknown bitdepth in file.") ); + return false; + } + + stream.Read(dbuf, 4 * 4); + int comp = wxINT32_SWAP_ON_BE((int)dbuf[0]); + if ( comp != BI_RGB && comp != BI_RLE4 && comp != BI_RLE8 && + comp != BI_BITFIELDS ) + { + if (verbose) + wxLogError( _("DIB Header: Unknown encoding in file.") ); + return false; + } + + stream.Read(dbuf, 4 * 2); + int ncolors = wxINT32_SWAP_ON_BE( (int)dbuf[0] ); + if (ncolors == 0) + ncolors = 1 << bpp; + /* some more sanity checks */ + if (((comp == BI_RLE4) && (bpp != 4)) || + ((comp == BI_RLE8) && (bpp != 8)) || + ((comp == BI_BITFIELDS) && (bpp != 16 && bpp != 32))) + { + if (verbose) + wxLogError( _("DIB Header: Encoding doesn't match bitdepth.") ); + return false; + } + + //read DIB; this is the BMP image or the XOR part of an icon image + if ( !DoLoadDib(image, width, height, bpp, ncolors, comp, offset, stream, + verbose, IsBmp, true) ) + { + if (verbose) + wxLogError( _("Error in reading image DIB.") ); + return false; + } + + if ( !IsBmp ) + { + //read Icon mask which is monochrome + //there is no palette, so we will create one + wxImage mask; + if ( !DoLoadDib(&mask, width, height, 1, 2, BI_RGB, offset, stream, + verbose, IsBmp, false) ) + { + if (verbose) + wxLogError( _("ICO: Error in reading mask DIB.") ); + return false; + } + image->SetMaskFromImage(mask, 255, 255, 255); + + } + + return true; +} + +bool wxBMPHandler::LoadFile(wxImage *image, wxInputStream& stream, + bool verbose, int WXUNUSED(index)) +{ + // Read a single DIB fom the file: + return LoadDib(image, stream, verbose, true/*isBmp*/); +} + +bool wxBMPHandler::DoCanRead(wxInputStream& stream) +{ + unsigned char hdr[2]; + + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + // do we have the BMP file signature? + return hdr[0] == 'B' && hdr[1] == 'M'; +} + +#endif // wxUSE_STREAMS + + +#if wxUSE_ICO_CUR +//----------------------------------------------------------------------------- +// wxICOHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxICOHandler, wxBMPHandler) + +#if wxUSE_STREAMS + +struct ICONDIRENTRY +{ + wxUint8 bWidth; // Width of the image + wxUint8 bHeight; // Height of the image (times 2) + wxUint8 bColorCount; // Number of colors in image (0 if >=8bpp) + wxUint8 bReserved; // Reserved + + // these two are different in icons and cursors: + // icon or cursor + wxUint16 wPlanes; // Color Planes or XHotSpot + wxUint16 wBitCount; // Bits per pixel or YHotSpot + + wxUint32 dwBytesInRes; // how many bytes in this resource? + wxUint32 dwImageOffset; // where in the file is this image +}; + +struct ICONDIR +{ + wxUint16 idReserved; // Reserved + wxUint16 idType; // resource type (1 for icons, 2 for cursors) + wxUint16 idCount; // how many images? +}; + + +bool wxICOHandler::SaveFile(wxImage *image, + wxOutputStream& stream, + bool verbose) + +{ + //sanity check; icon must be less than 127 pixels high and 255 wide + if ( image->GetHeight () > 127 ) + { + if ( verbose ) + wxLogError(_("ICO: Image too tall for an icon.")); + return false; + } + if ( image->GetWidth () > 255 ) + { + if ( verbose ) + wxLogError(_("ICO: Image too wide for an icon.")); + return false; + } + + const int images = 1; // only generate one image + + // VS: This is a hack of sort - since ICO and CUR files are almost + // identical, we have all the meat in wxICOHandler and check for + // the actual (handler) type when the code has to distinguish between + // the two formats + int type = (this->GetType() == wxBITMAP_TYPE_CUR) ? 2 : 1; + + // write a header, (ICONDIR) + // Calculate the header size + wxUint32 offset = 3 * sizeof(wxUint16); + + ICONDIR IconDir; + IconDir.idReserved = 0; + IconDir.idType = wxUINT16_SWAP_ON_BE((wxUint16)type); + IconDir.idCount = wxUINT16_SWAP_ON_BE((wxUint16)images); + stream.Write(&IconDir.idReserved, sizeof(IconDir.idReserved)); + stream.Write(&IconDir.idType, sizeof(IconDir.idType)); + stream.Write(&IconDir.idCount, sizeof(IconDir.idCount)); + if ( !stream.IsOk() ) + { + if ( verbose ) + wxLogError(_("ICO: Error writing the image file!")); + return false; + } + + // for each iamage write a description ICONDIRENTRY: + ICONDIRENTRY icondirentry; + for (int img = 0; img < images; img++) + { + wxImage mask; + + if ( image->HasMask() ) + { + // make another image with black/white: + mask = image->ConvertToMono (image->GetMaskRed(), image->GetMaskGreen(), image->GetMaskBlue() ); + + // now we need to change the masked regions to black: + unsigned char r = image->GetMaskRed(); + unsigned char g = image->GetMaskGreen(); + unsigned char b = image->GetMaskBlue(); + if ( (r != 0) || (g != 0) || (b != 0) ) + { + // Go round and apply black to the masked bits: + int i, j; + for (i = 0; i < mask.GetWidth(); i++) + { + for (j = 0; j < mask.GetHeight(); j++) + { + if ((r == mask.GetRed(i, j)) && + (g == mask.GetGreen(i, j))&& + (b == mask.GetBlue(i, j)) ) + image->SetRGB(i, j, 0, 0, 0 ); + } + } + } + } + else + { + // just make a black mask all over: + mask = image->Copy(); + int i, j; + for (i = 0; i < mask.GetWidth(); i++) + for (j = 0; j < mask.GetHeight(); j++) + mask.SetRGB(i, j, 0, 0, 0 ); + } + // Set the formats for image and mask + // (Windows never saves with more than 8 colors): + image->SetOption(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_8BPP); + + // monochome bitmap: + mask.SetOption(wxIMAGE_OPTION_BMP_FORMAT, wxBMP_1BPP_BW); + bool IsBmp = false; + bool IsMask = false; + + //calculate size and offset of image and mask + wxCountingOutputStream cStream; + bool bResult = SaveDib(image, cStream, verbose, IsBmp, IsMask); + if ( !bResult ) + { + if ( verbose ) + wxLogError(_("ICO: Error writing the image file!")); + return false; + } + IsMask = true; + + bResult = SaveDib(&mask, cStream, verbose, IsBmp, IsMask); + if ( !bResult ) + { + if ( verbose ) + wxLogError(_("ICO: Error writing the image file!")); + return false; + } + wxUint32 Size = cStream.GetSize(); + + // wxCountingOutputStream::IsOk() always returns true for now and this + // "if" provokes VC++ warnings in optimized build +#if 0 + if ( !cStream.Ok() ) + { + if ( verbose ) + wxLogError(_("ICO: Error writing the image file!")); + return false; + } +#endif // 0 + + offset = offset + sizeof(ICONDIRENTRY); + + icondirentry.bWidth = (wxUint8)image->GetWidth(); + icondirentry.bHeight = (wxUint8)(2 * image->GetHeight()); + icondirentry.bColorCount = 0; + icondirentry.bReserved = 0; + icondirentry.wPlanes = wxUINT16_SWAP_ON_BE(1); + icondirentry.wBitCount = wxUINT16_SWAP_ON_BE(wxBMP_8BPP); + if ( type == 2 /*CUR*/) + { + int hx = image->HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ? + image->GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X) : + image->GetWidth() / 2; + int hy = image->HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ? + image->GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y) : + image->GetHeight() / 2; + + // actually write the values of the hot spot here: + icondirentry.wPlanes = wxUINT16_SWAP_ON_BE((wxUint16)hx); + icondirentry.wBitCount = wxUINT16_SWAP_ON_BE((wxUint16)hy); + } + icondirentry.dwBytesInRes = wxUINT32_SWAP_ON_BE(Size); + icondirentry.dwImageOffset = wxUINT32_SWAP_ON_BE(offset); + + // increase size to allow for the data written: + offset += Size; + + // write to stream: + stream.Write(&icondirentry.bWidth, sizeof(icondirentry.bWidth)); + stream.Write(&icondirentry.bHeight, sizeof(icondirentry.bHeight)); + stream.Write(&icondirentry.bColorCount, sizeof(icondirentry.bColorCount)); + stream.Write(&icondirentry.bReserved, sizeof(icondirentry.bReserved)); + stream.Write(&icondirentry.wPlanes, sizeof(icondirentry.wPlanes)); + stream.Write(&icondirentry.wBitCount, sizeof(icondirentry.wBitCount)); + stream.Write(&icondirentry.dwBytesInRes, sizeof(icondirentry.dwBytesInRes)); + stream.Write(&icondirentry.dwImageOffset, sizeof(icondirentry.dwImageOffset)); + if ( !stream.IsOk() ) + { + if ( verbose ) + wxLogError(_("ICO: Error writing the image file!")); + return false; + } + + // actually save it: + IsMask = false; + bResult = SaveDib(image, stream, verbose, IsBmp, IsMask); + if ( !bResult ) + { + if ( verbose ) + wxLogError(_("ICO: Error writing the image file!")); + return false; + } + IsMask = true; + + bResult = SaveDib(&mask, stream, verbose, IsBmp, IsMask); + if ( !bResult ) + { + if ( verbose ) + wxLogError(_("ICO: Error writing the image file!")); + return false; + } + + } // end of for loop + + return true; +} + +bool wxICOHandler::LoadFile(wxImage *image, wxInputStream& stream, + bool verbose, int index) +{ + stream.SeekI(0); + return DoLoadFile(image, stream, verbose, index); +} + +bool wxICOHandler::DoLoadFile(wxImage *image, wxInputStream& stream, + bool WXUNUSED(verbose), int index) +{ + bool bResult wxDUMMY_INITIALIZE(false); + bool IsBmp = false; + + ICONDIR IconDir; + + wxFileOffset iPos = stream.TellI(); + stream.Read(&IconDir, sizeof(IconDir)); + wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount); + // nType is 1 for Icons, 2 for Cursors: + wxUint16 nType = wxUINT16_SWAP_ON_BE(IconDir.idType); + + // loop round the icons and choose the best one: + ICONDIRENTRY *pIconDirEntry = new ICONDIRENTRY[nIcons]; + ICONDIRENTRY *pCurrentEntry = pIconDirEntry; + int wMax = 0; + int colmax = 0; + int iSel = wxNOT_FOUND; + + for (int i = 0; i < nIcons; i++ ) + { + stream.Read(pCurrentEntry, sizeof(ICONDIRENTRY)); + // bHeight and bColorCount are wxUint8 + if ( pCurrentEntry->bWidth >= wMax ) + { + // see if we have more colors, ==0 indicates > 8bpp: + if ( pCurrentEntry->bColorCount == 0 ) + pCurrentEntry->bColorCount = 255; + if ( pCurrentEntry->bColorCount >= colmax ) + { + iSel = i; + wMax = pCurrentEntry->bWidth; + colmax = pCurrentEntry->bColorCount; + } + } + pCurrentEntry++; + } + + if ( index != -1 ) + { + // VS: Note that we *have* to run the loop above even if index != -1, because + // it reads ICONDIRENTRies. + iSel = index; + } + + if ( iSel == wxNOT_FOUND || iSel < 0 || iSel >= nIcons ) + { + wxLogError(_("ICO: Invalid icon index.")); + bResult = false; + } + else + { + // seek to selected icon: + pCurrentEntry = pIconDirEntry + iSel; + stream.SeekI(iPos + wxUINT32_SWAP_ON_BE(pCurrentEntry->dwImageOffset), wxFromStart); + bResult = LoadDib(image, stream, true, IsBmp); + bool bIsCursorType = (this->GetType() == wxBITMAP_TYPE_CUR) || (this->GetType() == wxBITMAP_TYPE_ANI); + if ( bResult && bIsCursorType && nType == 2 ) + { + // it is a cursor, so let's set the hotspot: + image->SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, wxUINT16_SWAP_ON_BE(pCurrentEntry->wPlanes)); + image->SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, wxUINT16_SWAP_ON_BE(pCurrentEntry->wBitCount)); + } + } + delete[] pIconDirEntry; + return bResult; +} + +int wxICOHandler::GetImageCount(wxInputStream& stream) +{ + ICONDIR IconDir; + wxFileOffset iPos = stream.TellI(); + stream.SeekI(0); + stream.Read(&IconDir, sizeof(IconDir)); + wxUint16 nIcons = wxUINT16_SWAP_ON_BE(IconDir.idCount); + stream.SeekI(iPos); + return (int)nIcons; +} + +bool wxICOHandler::DoCanRead(wxInputStream& stream) +{ + stream.SeekI(0); + unsigned char hdr[4]; + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + // hdr[2] is one for an icon and two for a cursor + return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\1' && hdr[3] == '\0'; +} + +#endif // wxUSE_STREAMS + + +//----------------------------------------------------------------------------- +// wxCURHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxCURHandler, wxICOHandler) + +#if wxUSE_STREAMS + +bool wxCURHandler::DoCanRead(wxInputStream& stream) +{ + stream.SeekI(0); + unsigned char hdr[4]; + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + // hdr[2] is one for an icon and two for a cursor + return hdr[0] == '\0' && hdr[1] == '\0' && hdr[2] == '\2' && hdr[3] == '\0'; +} + +#endif // wxUSE_STREAMS + +//----------------------------------------------------------------------------- +// wxANIHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxANIHandler, wxCURHandler) + +#if wxUSE_STREAMS + +bool wxANIHandler::LoadFile(wxImage *image, wxInputStream& stream, + bool WXUNUSED(verbose), int index) +{ + wxANIDecoder decoder; + if (!decoder.Load(stream)) + return false; + + return decoder.ConvertToImage(index != -1 ? (size_t)index : 0, image); +} + +bool wxANIHandler::DoCanRead(wxInputStream& stream) +{ + wxANIDecoder decod; + return decod.CanRead(stream); +} + +int wxANIHandler::GetImageCount(wxInputStream& stream) +{ + wxANIDecoder decoder; + if (!decoder.Load(stream)) + return wxNOT_FOUND; + + return decoder.GetFrameCount(); +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_ICO_CUR + +#endif // wxUSE_IMAGE diff --git a/Source/3rd Party/wx/src/common/image.cpp b/Source/3rd Party/wx/src/common/image.cpp index ced69f5e1..7885d6486 100644 --- a/Source/3rd Party/wx/src/common/image.cpp +++ b/Source/3rd Party/wx/src/common/image.cpp @@ -1,3126 +1,3126 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/image.cpp -// Purpose: wxImage -// Author: Robert Roebling -// RCS-ID: $Id: image.cpp 59197 2009-02-28 15:44:53Z VZ $ -// Copyright: (c) Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE - -#include "wx/image.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/hash.h" - #include "wx/utils.h" - #include "wx/math.h" - #include "wx/module.h" - #include "wx/palette.h" - #include "wx/intl.h" -#endif - -#include "wx/filefn.h" -#include "wx/wfstream.h" -#include "wx/xpmdecod.h" - -// For memcpy -#include - -// make the code compile with either wxFile*Stream or wxFFile*Stream: -#define HAS_FILE_STREAMS (wxUSE_STREAMS && (wxUSE_FILE || wxUSE_FFILE)) - -#if HAS_FILE_STREAMS - #if wxUSE_FFILE - typedef wxFFileInputStream wxImageFileInputStream; - typedef wxFFileOutputStream wxImageFileOutputStream; - #elif wxUSE_FILE - typedef wxFileInputStream wxImageFileInputStream; - typedef wxFileOutputStream wxImageFileOutputStream; - #endif // wxUSE_FILE/wxUSE_FFILE -#endif // HAS_FILE_STREAMS - -#if wxUSE_VARIANT -IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxImage,WXDLLEXPORT) -#endif - -//----------------------------------------------------------------------------- -// wxImage -//----------------------------------------------------------------------------- - -class wxImageRefData: public wxObjectRefData -{ -public: - wxImageRefData(); - virtual ~wxImageRefData(); - - int m_width; - int m_height; - unsigned char *m_data; - - bool m_hasMask; - unsigned char m_maskRed,m_maskGreen,m_maskBlue; - - // alpha channel data, may be NULL for the formats without alpha support - unsigned char *m_alpha; - - bool m_ok; - - // if true, m_data is pointer to static data and shouldn't be freed - bool m_static; - - // same as m_static but for m_alpha - bool m_staticAlpha; - -#if wxUSE_PALETTE - wxPalette m_palette; -#endif // wxUSE_PALETTE - - wxArrayString m_optionNames; - wxArrayString m_optionValues; - - DECLARE_NO_COPY_CLASS(wxImageRefData) -}; - -wxImageRefData::wxImageRefData() -{ - m_width = 0; - m_height = 0; - m_data = - m_alpha = (unsigned char *) NULL; - - m_maskRed = 0; - m_maskGreen = 0; - m_maskBlue = 0; - m_hasMask = false; - - m_ok = false; - m_static = - m_staticAlpha = false; -} - -wxImageRefData::~wxImageRefData() -{ - if ( !m_static ) - free( m_data ); - if ( !m_staticAlpha ) - free( m_alpha ); -} - -wxList wxImage::sm_handlers; - -wxImage wxNullImage; - -//----------------------------------------------------------------------------- - -#define M_IMGDATA wx_static_cast(wxImageRefData*, m_refData) - -IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject) - -wxImage::wxImage( int width, int height, bool clear ) -{ - Create( width, height, clear ); -} - -wxImage::wxImage( int width, int height, unsigned char* data, bool static_data ) -{ - Create( width, height, data, static_data ); -} - -wxImage::wxImage( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data ) -{ - Create( width, height, data, alpha, static_data ); -} - -wxImage::wxImage( const wxString& name, long type, int index ) -{ - LoadFile( name, type, index ); -} - -wxImage::wxImage( const wxString& name, const wxString& mimetype, int index ) -{ - LoadFile( name, mimetype, index ); -} - -#if wxUSE_STREAMS -wxImage::wxImage( wxInputStream& stream, long type, int index ) -{ - LoadFile( stream, type, index ); -} - -wxImage::wxImage( wxInputStream& stream, const wxString& mimetype, int index ) -{ - LoadFile( stream, mimetype, index ); -} -#endif // wxUSE_STREAMS - -wxImage::wxImage(const char* const* xpmData) -{ - Create(xpmData); -} - -bool wxImage::Create(const char* const* xpmData) -{ -#if wxUSE_XPM - UnRef(); - - wxXPMDecoder decoder; - (*this) = decoder.ReadData(xpmData); - return Ok(); -#else - return false; -#endif -} - -bool wxImage::Create( int width, int height, bool clear ) -{ - UnRef(); - - m_refData = new wxImageRefData(); - - M_IMGDATA->m_data = (unsigned char *) malloc( width*height*3 ); - if (!M_IMGDATA->m_data) - { - UnRef(); - return false; - } - - if (clear) - memset(M_IMGDATA->m_data, 0, width*height*3); - - M_IMGDATA->m_width = width; - M_IMGDATA->m_height = height; - M_IMGDATA->m_ok = true; - - return true; -} - -bool wxImage::Create( int width, int height, unsigned char* data, bool static_data ) -{ - UnRef(); - - wxCHECK_MSG( data, false, _T("NULL data in wxImage::Create") ); - - m_refData = new wxImageRefData(); - - M_IMGDATA->m_data = data; - M_IMGDATA->m_width = width; - M_IMGDATA->m_height = height; - M_IMGDATA->m_ok = true; - M_IMGDATA->m_static = static_data; - - return true; -} - -bool wxImage::Create( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data ) -{ - UnRef(); - - wxCHECK_MSG( data, false, _T("NULL data in wxImage::Create") ); - - m_refData = new wxImageRefData(); - - M_IMGDATA->m_data = data; - M_IMGDATA->m_alpha = alpha; - M_IMGDATA->m_width = width; - M_IMGDATA->m_height = height; - M_IMGDATA->m_ok = true; - M_IMGDATA->m_static = static_data; - M_IMGDATA->m_staticAlpha = static_data; - - return true; -} - -void wxImage::Destroy() -{ - UnRef(); -} - -wxObjectRefData* wxImage::CreateRefData() const -{ - return new wxImageRefData; -} - -wxObjectRefData* wxImage::CloneRefData(const wxObjectRefData* that) const -{ - const wxImageRefData* refData = wx_static_cast(const wxImageRefData*, that); - wxCHECK_MSG(refData->m_ok, NULL, wxT("invalid image") ); - - wxImageRefData* refData_new = new wxImageRefData; - refData_new->m_width = refData->m_width; - refData_new->m_height = refData->m_height; - refData_new->m_maskRed = refData->m_maskRed; - refData_new->m_maskGreen = refData->m_maskGreen; - refData_new->m_maskBlue = refData->m_maskBlue; - refData_new->m_hasMask = refData->m_hasMask; - refData_new->m_ok = true; - unsigned size = unsigned(refData->m_width) * unsigned(refData->m_height); - if (refData->m_alpha != NULL) - { - refData_new->m_alpha = (unsigned char*)malloc(size); - memcpy(refData_new->m_alpha, refData->m_alpha, size); - } - size *= 3; - refData_new->m_data = (unsigned char*)malloc(size); - memcpy(refData_new->m_data, refData->m_data, size); -#if wxUSE_PALETTE - refData_new->m_palette = refData->m_palette; -#endif - refData_new->m_optionNames = refData->m_optionNames; - refData_new->m_optionValues = refData->m_optionValues; - return refData_new; -} - -wxImage wxImage::Copy() const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - image.m_refData = CloneRefData(m_refData); - - return image; -} - -wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const -{ - if( xFactor == 1 && yFactor == 1 ) - return *this; - - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - // can't scale to/from 0 size - wxCHECK_MSG( (xFactor > 0) && (yFactor > 0), image, - wxT("invalid new image size") ); - - long old_height = M_IMGDATA->m_height, - old_width = M_IMGDATA->m_width; - - wxCHECK_MSG( (old_height > 0) && (old_width > 0), image, - wxT("invalid old image size") ); - - long width = old_width / xFactor ; - long height = old_height / yFactor ; - - image.Create( width, height, false ); - - char unsigned *data = image.GetData(); - - wxCHECK_MSG( data, image, wxT("unable to create image") ); - - bool hasMask = false ; - unsigned char maskRed = 0; - unsigned char maskGreen = 0; - unsigned char maskBlue =0 ; - - unsigned char *source_data = M_IMGDATA->m_data; - unsigned char *target_data = data; - unsigned char *source_alpha = 0 ; - unsigned char *target_alpha = 0 ; - if (M_IMGDATA->m_hasMask) - { - hasMask = true ; - maskRed = M_IMGDATA->m_maskRed; - maskGreen = M_IMGDATA->m_maskGreen; - maskBlue =M_IMGDATA->m_maskBlue ; - - image.SetMaskColour( M_IMGDATA->m_maskRed, - M_IMGDATA->m_maskGreen, - M_IMGDATA->m_maskBlue ); - } - else - { - source_alpha = M_IMGDATA->m_alpha ; - if ( source_alpha ) - { - image.SetAlpha() ; - target_alpha = image.GetAlpha() ; - } - } - - for (long y = 0; y < height; y++) - { - for (long x = 0; x < width; x++) - { - unsigned long avgRed = 0 ; - unsigned long avgGreen = 0; - unsigned long avgBlue = 0; - unsigned long avgAlpha = 0 ; - unsigned long counter = 0 ; - // determine average - for ( int y1 = 0 ; y1 < yFactor ; ++y1 ) - { - long y_offset = (y * yFactor + y1) * old_width; - for ( int x1 = 0 ; x1 < xFactor ; ++x1 ) - { - unsigned char *pixel = source_data + 3 * ( y_offset + x * xFactor + x1 ) ; - unsigned char red = pixel[0] ; - unsigned char green = pixel[1] ; - unsigned char blue = pixel[2] ; - unsigned char alpha = 255 ; - if ( source_alpha ) - alpha = *(source_alpha + y_offset + x * xFactor + x1) ; - if ( !hasMask || red != maskRed || green != maskGreen || blue != maskBlue ) - { - if ( alpha > 0 ) - { - avgRed += red ; - avgGreen += green ; - avgBlue += blue ; - } - avgAlpha += alpha ; - counter++ ; - } - } - } - if ( counter == 0 ) - { - *(target_data++) = M_IMGDATA->m_maskRed ; - *(target_data++) = M_IMGDATA->m_maskGreen ; - *(target_data++) = M_IMGDATA->m_maskBlue ; - } - else - { - if ( source_alpha ) - *(target_alpha++) = (unsigned char)(avgAlpha / counter ) ; - *(target_data++) = (unsigned char)(avgRed / counter); - *(target_data++) = (unsigned char)(avgGreen / counter); - *(target_data++) = (unsigned char)(avgBlue / counter); - } - } - } - - // In case this is a cursor, make sure the hotspot is scaled accordingly: - if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ) - image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, - (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X))/xFactor); - if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ) - image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, - (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y))/yFactor); - - return image; -} - -wxImage wxImage::Scale( int width, int height, int quality ) const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - // can't scale to/from 0 size - wxCHECK_MSG( (width > 0) && (height > 0), image, - wxT("invalid new image size") ); - - long old_height = M_IMGDATA->m_height, - old_width = M_IMGDATA->m_width; - wxCHECK_MSG( (old_height > 0) && (old_width > 0), image, - wxT("invalid old image size") ); - - // If the image's new width and height are the same as the original, no - // need to waste time or CPU cycles - if ( old_width == width && old_height == height ) - return *this; - - // Scale the image (...or more appropriately, resample the image) using - // either the high-quality or normal method as specified - if ( quality == wxIMAGE_QUALITY_HIGH ) - { - // We need to check whether we are downsampling or upsampling the image - if ( width < old_width && height < old_height ) - { - // Downsample the image using the box averaging method for best results - image = ResampleBox(width, height); - } - else - { - // For upsampling or other random/wierd image dimensions we'll use - // a bicubic b-spline scaling method - image = ResampleBicubic(width, height); - } - } - else // Default scaling method == simple pixel replication - { - if ( old_width % width == 0 && old_width >= width && - old_height % height == 0 && old_height >= height ) - { - return ShrinkBy( old_width / width , old_height / height ) ; - } - image.Create( width, height, false ); - - unsigned char *data = image.GetData(); - - wxCHECK_MSG( data, image, wxT("unable to create image") ); - - unsigned char *source_data = M_IMGDATA->m_data; - unsigned char *target_data = data; - unsigned char *source_alpha = 0 ; - unsigned char *target_alpha = 0 ; - - if ( !M_IMGDATA->m_hasMask ) - { - source_alpha = M_IMGDATA->m_alpha ; - if ( source_alpha ) - { - image.SetAlpha() ; - target_alpha = image.GetAlpha() ; - } - } - - long x_delta = (old_width<<16) / width; - long y_delta = (old_height<<16) / height; - - unsigned char* dest_pixel = target_data; - - long y = 0; - for ( long j = 0; j < height; j++ ) - { - unsigned char* src_line = &source_data[(y>>16)*old_width*3]; - unsigned char* src_alpha_line = source_alpha ? &source_alpha[(y>>16)*old_width] : 0 ; - - long x = 0; - for ( long i = 0; i < width; i++ ) - { - unsigned char* src_pixel = &src_line[(x>>16)*3]; - unsigned char* src_alpha_pixel = source_alpha ? &src_alpha_line[(x>>16)] : 0 ; - dest_pixel[0] = src_pixel[0]; - dest_pixel[1] = src_pixel[1]; - dest_pixel[2] = src_pixel[2]; - dest_pixel += 3; - if ( source_alpha ) - *(target_alpha++) = *src_alpha_pixel ; - x += x_delta; - } - - y += y_delta; - } - } - - // If the original image has a mask, apply the mask to the new image - if (M_IMGDATA->m_hasMask) - { - image.SetMaskColour( M_IMGDATA->m_maskRed, - M_IMGDATA->m_maskGreen, - M_IMGDATA->m_maskBlue ); - } - - // In case this is a cursor, make sure the hotspot is scaled accordingly: - if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ) - image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, - (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X)*width)/old_width); - if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ) - image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, - (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y)*height)/old_height); - - return image; -} - -wxImage wxImage::ResampleBox(int width, int height) const -{ - // This function implements a simple pre-blur/box averaging method for - // downsampling that gives reasonably smooth results To scale the image - // down we will need to gather a grid of pixels of the size of the scale - // factor in each direction and then do an averaging of the pixels. - - wxImage ret_image(width, height, false); - - const double scale_factor_x = double(M_IMGDATA->m_width) / width; - const double scale_factor_y = double(M_IMGDATA->m_height) / height; - - const int scale_factor_x_2 = (int)(scale_factor_x / 2); - const int scale_factor_y_2 = (int)(scale_factor_y / 2); - - unsigned char* src_data = M_IMGDATA->m_data; - unsigned char* src_alpha = M_IMGDATA->m_alpha; - unsigned char* dst_data = ret_image.GetData(); - unsigned char* dst_alpha = NULL; - - if ( src_alpha ) - { - ret_image.SetAlpha(); - dst_alpha = ret_image.GetAlpha(); - } - - int averaged_pixels, src_pixel_index; - double sum_r, sum_g, sum_b, sum_a; - - for ( int y = 0; y < height; y++ ) // Destination image - Y direction - { - // Source pixel in the Y direction - int src_y = (int)(y * scale_factor_y); - - for ( int x = 0; x < width; x++ ) // Destination image - X direction - { - // Source pixel in the X direction - int src_x = (int)(x * scale_factor_x); - - // Box of pixels to average - averaged_pixels = 0; - sum_r = sum_g = sum_b = sum_a = 0.0; - - for ( int j = int(src_y - scale_factor_y/2.0 + 1); - j <= int(src_y + scale_factor_y_2); - j++ ) - { - // We don't care to average pixels that don't exist (edges) - if ( j < 0 || j > M_IMGDATA->m_height - 1 ) - continue; - - for ( int i = int(src_x - scale_factor_x/2.0 + 1); - i <= src_x + scale_factor_x_2; - i++ ) - { - // Don't average edge pixels - if ( i < 0 || i > M_IMGDATA->m_width - 1 ) - continue; - - // Calculate the actual index in our source pixels - src_pixel_index = j * M_IMGDATA->m_width + i; - - sum_r += src_data[src_pixel_index * 3 + 0]; - sum_g += src_data[src_pixel_index * 3 + 1]; - sum_b += src_data[src_pixel_index * 3 + 2]; - if ( src_alpha ) - sum_a += src_alpha[src_pixel_index]; - - averaged_pixels++; - } - } - - // Calculate the average from the sum and number of averaged pixels - dst_data[0] = (unsigned char)(sum_r / averaged_pixels); - dst_data[1] = (unsigned char)(sum_g / averaged_pixels); - dst_data[2] = (unsigned char)(sum_b / averaged_pixels); - dst_data += 3; - if ( src_alpha ) - *dst_alpha++ = (unsigned char)(sum_a / averaged_pixels); - } - } - - return ret_image; -} - -// The following two local functions are for the B-spline weighting of the -// bicubic sampling algorithm -static inline double spline_cube(double value) -{ - return value <= 0.0 ? 0.0 : value * value * value; -} - -static inline double spline_weight(double value) -{ - return (spline_cube(value + 2) - - 4 * spline_cube(value + 1) + - 6 * spline_cube(value) - - 4 * spline_cube(value - 1)) / 6; -} - -// This is the bicubic resampling algorithm -wxImage wxImage::ResampleBicubic(int width, int height) const -{ - // This function implements a Bicubic B-Spline algorithm for resampling. - // This method is certainly a little slower than wxImage's default pixel - // replication method, however for most reasonably sized images not being - // upsampled too much on a fairly average CPU this difference is hardly - // noticeable and the results are far more pleasing to look at. - // - // This particular bicubic algorithm does pixel weighting according to a - // B-Spline that basically implements a Gaussian bell-like weighting - // kernel. Because of this method the results may appear a bit blurry when - // upsampling by large factors. This is basically because a slight - // gaussian blur is being performed to get the smooth look of the upsampled - // image. - - // Edge pixels: 3-4 possible solutions - // - (Wrap/tile) Wrap the image, take the color value from the opposite - // side of the image. - // - (Mirror) Duplicate edge pixels, so that pixel at coordinate (2, n), - // where n is nonpositive, will have the value of (2, 1). - // - (Ignore) Simply ignore the edge pixels and apply the kernel only to - // pixels which do have all neighbours. - // - (Clamp) Choose the nearest pixel along the border. This takes the - // border pixels and extends them out to infinity. - // - // NOTE: below the y_offset and x_offset variables are being set for edge - // pixels using the "Mirror" method mentioned above - - wxImage ret_image; - - ret_image.Create(width, height, false); - - unsigned char* src_data = M_IMGDATA->m_data; - unsigned char* src_alpha = M_IMGDATA->m_alpha; - unsigned char* dst_data = ret_image.GetData(); - unsigned char* dst_alpha = NULL; - - if ( src_alpha ) - { - ret_image.SetAlpha(); - dst_alpha = ret_image.GetAlpha(); - } - - for ( int dsty = 0; dsty < height; dsty++ ) - { - // We need to calculate the source pixel to interpolate from - Y-axis - double srcpixy = double(dsty * M_IMGDATA->m_height) / height; - double dy = srcpixy - (int)srcpixy; - - for ( int dstx = 0; dstx < width; dstx++ ) - { - // X-axis of pixel to interpolate from - double srcpixx = double(dstx * M_IMGDATA->m_width) / width; - double dx = srcpixx - (int)srcpixx; - - // Sums for each color channel - double sum_r = 0, sum_g = 0, sum_b = 0, sum_a = 0; - - // Here we actually determine the RGBA values for the destination pixel - for ( int k = -1; k <= 2; k++ ) - { - // Y offset - int y_offset = srcpixy + k < 0.0 - ? 0 - : srcpixy + k >= M_IMGDATA->m_height - ? M_IMGDATA->m_height - 1 - : (int)(srcpixy + k); - - // Loop across the X axis - for ( int i = -1; i <= 2; i++ ) - { - // X offset - int x_offset = srcpixx + i < 0.0 - ? 0 - : srcpixx + i >= M_IMGDATA->m_width - ? M_IMGDATA->m_width - 1 - : (int)(srcpixx + i); - - // Calculate the exact position where the source data - // should be pulled from based on the x_offset and y_offset - int src_pixel_index = y_offset*M_IMGDATA->m_width + x_offset; - - // Calculate the weight for the specified pixel according - // to the bicubic b-spline kernel we're using for - // interpolation - double - pixel_weight = spline_weight(i - dx)*spline_weight(k - dy); - - // Create a sum of all velues for each color channel - // adjusted for the pixel's calculated weight - sum_r += src_data[src_pixel_index * 3 + 0] * pixel_weight; - sum_g += src_data[src_pixel_index * 3 + 1] * pixel_weight; - sum_b += src_data[src_pixel_index * 3 + 2] * pixel_weight; - if ( src_alpha ) - sum_a += src_alpha[src_pixel_index] * pixel_weight; - } - } - - // Put the data into the destination image. The summed values are - // of double data type and are rounded here for accuracy - dst_data[0] = (unsigned char)(sum_r + 0.5); - dst_data[1] = (unsigned char)(sum_g + 0.5); - dst_data[2] = (unsigned char)(sum_b + 0.5); - dst_data += 3; - - if ( src_alpha ) - *dst_alpha++ = (unsigned char)sum_a; - } - } - - return ret_image; -} - -// Blur in the horizontal direction -wxImage wxImage::BlurHorizontal(int blurRadius) -{ - wxImage ret_image; - ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); - - unsigned char* src_data = M_IMGDATA->m_data; - unsigned char* dst_data = ret_image.GetData(); - unsigned char* src_alpha = M_IMGDATA->m_alpha; - unsigned char* dst_alpha = NULL; - - // Check for a mask or alpha - if ( M_IMGDATA->m_hasMask ) - { - ret_image.SetMaskColour(M_IMGDATA->m_maskRed, - M_IMGDATA->m_maskGreen, - M_IMGDATA->m_maskBlue); - } - else - { - if ( src_alpha ) - { - ret_image.SetAlpha(); - dst_alpha = ret_image.GetAlpha(); - } - } - - // number of pixels we average over - const int blurArea = blurRadius*2 + 1; - - // Horizontal blurring algorithm - average all pixels in the specified blur - // radius in the X or horizontal direction - for ( int y = 0; y < M_IMGDATA->m_height; y++ ) - { - // Variables used in the blurring algorithm - long sum_r = 0, - sum_g = 0, - sum_b = 0, - sum_a = 0; - - long pixel_idx; - const unsigned char *src; - unsigned char *dst; - - // Calculate the average of all pixels in the blur radius for the first - // pixel of the row - for ( int kernel_x = -blurRadius; kernel_x <= blurRadius; kernel_x++ ) - { - // To deal with the pixels at the start of a row so it's not - // grabbing GOK values from memory at negative indices of the - // image's data or grabbing from the previous row - if ( kernel_x < 0 ) - pixel_idx = y * M_IMGDATA->m_width; - else - pixel_idx = kernel_x + y * M_IMGDATA->m_width; - - src = src_data + pixel_idx*3; - sum_r += src[0]; - sum_g += src[1]; - sum_b += src[2]; - if ( src_alpha ) - sum_a += src_alpha[pixel_idx]; - } - - dst = dst_data + y * M_IMGDATA->m_width*3; - dst[0] = (unsigned char)(sum_r / blurArea); - dst[1] = (unsigned char)(sum_g / blurArea); - dst[2] = (unsigned char)(sum_b / blurArea); - if ( src_alpha ) - dst_alpha[y * M_IMGDATA->m_width] = (unsigned char)(sum_a / blurArea); - - // Now average the values of the rest of the pixels by just moving the - // blur radius box along the row - for ( int x = 1; x < M_IMGDATA->m_width; x++ ) - { - // Take care of edge pixels on the left edge by essentially - // duplicating the edge pixel - if ( x - blurRadius - 1 < 0 ) - pixel_idx = y * M_IMGDATA->m_width; - else - pixel_idx = (x - blurRadius - 1) + y * M_IMGDATA->m_width; - - // Subtract the value of the pixel at the left side of the blur - // radius box - src = src_data + pixel_idx*3; - sum_r -= src[0]; - sum_g -= src[1]; - sum_b -= src[2]; - if ( src_alpha ) - sum_a -= src_alpha[pixel_idx]; - - // Take care of edge pixels on the right edge - if ( x + blurRadius > M_IMGDATA->m_width - 1 ) - pixel_idx = M_IMGDATA->m_width - 1 + y * M_IMGDATA->m_width; - else - pixel_idx = x + blurRadius + y * M_IMGDATA->m_width; - - // Add the value of the pixel being added to the end of our box - src = src_data + pixel_idx*3; - sum_r += src[0]; - sum_g += src[1]; - sum_b += src[2]; - if ( src_alpha ) - sum_a += src_alpha[pixel_idx]; - - // Save off the averaged data - dst = dst_data + x*3 + y*M_IMGDATA->m_width*3; - dst[0] = (unsigned char)(sum_r / blurArea); - dst[1] = (unsigned char)(sum_g / blurArea); - dst[2] = (unsigned char)(sum_b / blurArea); - if ( src_alpha ) - dst_alpha[x + y * M_IMGDATA->m_width] = (unsigned char)(sum_a / blurArea); - } - } - - return ret_image; -} - -// Blur in the vertical direction -wxImage wxImage::BlurVertical(int blurRadius) -{ - wxImage ret_image; - ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); - - unsigned char* src_data = M_IMGDATA->m_data; - unsigned char* dst_data = ret_image.GetData(); - unsigned char* src_alpha = M_IMGDATA->m_alpha; - unsigned char* dst_alpha = NULL; - - // Check for a mask or alpha - if ( M_IMGDATA->m_hasMask ) - { - ret_image.SetMaskColour(M_IMGDATA->m_maskRed, - M_IMGDATA->m_maskGreen, - M_IMGDATA->m_maskBlue); - } - else - { - if ( src_alpha ) - { - ret_image.SetAlpha(); - dst_alpha = ret_image.GetAlpha(); - } - } - - // number of pixels we average over - const int blurArea = blurRadius*2 + 1; - - // Vertical blurring algorithm - same as horizontal but switched the - // opposite direction - for ( int x = 0; x < M_IMGDATA->m_width; x++ ) - { - // Variables used in the blurring algorithm - long sum_r = 0, - sum_g = 0, - sum_b = 0, - sum_a = 0; - - long pixel_idx; - const unsigned char *src; - unsigned char *dst; - - // Calculate the average of all pixels in our blur radius box for the - // first pixel of the column - for ( int kernel_y = -blurRadius; kernel_y <= blurRadius; kernel_y++ ) - { - // To deal with the pixels at the start of a column so it's not - // grabbing GOK values from memory at negative indices of the - // image's data or grabbing from the previous column - if ( kernel_y < 0 ) - pixel_idx = x; - else - pixel_idx = x + kernel_y * M_IMGDATA->m_width; - - src = src_data + pixel_idx*3; - sum_r += src[0]; - sum_g += src[1]; - sum_b += src[2]; - if ( src_alpha ) - sum_a += src_alpha[pixel_idx]; - } - - dst = dst_data + x*3; - dst[0] = (unsigned char)(sum_r / blurArea); - dst[1] = (unsigned char)(sum_g / blurArea); - dst[2] = (unsigned char)(sum_b / blurArea); - if ( src_alpha ) - dst_alpha[x] = (unsigned char)(sum_a / blurArea); - - // Now average the values of the rest of the pixels by just moving the - // box along the column from top to bottom - for ( int y = 1; y < M_IMGDATA->m_height; y++ ) - { - // Take care of pixels that would be beyond the top edge by - // duplicating the top edge pixel for the column - if ( y - blurRadius - 1 < 0 ) - pixel_idx = x; - else - pixel_idx = x + (y - blurRadius - 1) * M_IMGDATA->m_width; - - // Subtract the value of the pixel at the top of our blur radius box - src = src_data + pixel_idx*3; - sum_r -= src[0]; - sum_g -= src[1]; - sum_b -= src[2]; - if ( src_alpha ) - sum_a -= src_alpha[pixel_idx]; - - // Take care of the pixels that would be beyond the bottom edge of - // the image similar to the top edge - if ( y + blurRadius > M_IMGDATA->m_height - 1 ) - pixel_idx = x + (M_IMGDATA->m_height - 1) * M_IMGDATA->m_width; - else - pixel_idx = x + (blurRadius + y) * M_IMGDATA->m_width; - - // Add the value of the pixel being added to the end of our box - src = src_data + pixel_idx*3; - sum_r += src[0]; - sum_g += src[1]; - sum_b += src[2]; - if ( src_alpha ) - sum_a += src_alpha[pixel_idx]; - - // Save off the averaged data - dst = dst_data + (x + y * M_IMGDATA->m_width) * 3; - dst[0] = (unsigned char)(sum_r / blurArea); - dst[1] = (unsigned char)(sum_g / blurArea); - dst[2] = (unsigned char)(sum_b / blurArea); - if ( src_alpha ) - dst_alpha[x + y * M_IMGDATA->m_width] = (unsigned char)(sum_a / blurArea); - } - } - - return ret_image; -} - -// The new blur function -wxImage wxImage::Blur(int blurRadius) -{ - wxImage ret_image; - ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); - - // Blur the image in each direction - ret_image = BlurHorizontal(blurRadius); - ret_image = ret_image.BlurVertical(blurRadius); - - return ret_image; -} - -wxImage wxImage::Rotate90( bool clockwise ) const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - image.Create( M_IMGDATA->m_height, M_IMGDATA->m_width, false ); - - unsigned char *data = image.GetData(); - - wxCHECK_MSG( data, image, wxT("unable to create image") ); - - unsigned char *source_data = M_IMGDATA->m_data; - unsigned char *target_data; - unsigned char *alpha_data = 0 ; - unsigned char *source_alpha = 0 ; - unsigned char *target_alpha = 0 ; - - if (M_IMGDATA->m_hasMask) - { - image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); - } - else - { - source_alpha = M_IMGDATA->m_alpha ; - if ( source_alpha ) - { - image.SetAlpha() ; - alpha_data = image.GetAlpha() ; - } - } - - long height = M_IMGDATA->m_height; - long width = M_IMGDATA->m_width; - - for (long j = 0; j < height; j++) - { - for (long i = 0; i < width; i++) - { - if (clockwise) - { - target_data = data + (((i+1)*height) - j - 1)*3; - if(source_alpha) - target_alpha = alpha_data + (((i+1)*height) - j - 1); - } - else - { - target_data = data + ((height*(width-1)) + j - (i*height))*3; - if(source_alpha) - target_alpha = alpha_data + ((height*(width-1)) + j - (i*height)); - } - memcpy( target_data, source_data, 3 ); - source_data += 3; - - if(source_alpha) - { - memcpy( target_alpha, source_alpha, 1 ); - source_alpha += 1; - } - } - } - - return image; -} - -wxImage wxImage::Mirror( bool horizontally ) const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height, false ); - - unsigned char *data = image.GetData(); - unsigned char *alpha = NULL; - - wxCHECK_MSG( data, image, wxT("unable to create image") ); - - if (M_IMGDATA->m_alpha != NULL) { - image.SetAlpha(); - alpha = image.GetAlpha(); - wxCHECK_MSG( alpha, image, wxT("unable to create alpha channel") ); - } - - if (M_IMGDATA->m_hasMask) - image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); - - long height = M_IMGDATA->m_height; - long width = M_IMGDATA->m_width; - - unsigned char *source_data = M_IMGDATA->m_data; - unsigned char *target_data; - - if (horizontally) - { - for (long j = 0; j < height; j++) - { - data += width*3; - target_data = data-3; - for (long i = 0; i < width; i++) - { - memcpy( target_data, source_data, 3 ); - source_data += 3; - target_data -= 3; - } - } - - if (alpha != NULL) - { - // src_alpha starts at the first pixel and increases by 1 after each step - // (a step here is the copy of the alpha value of one pixel) - const unsigned char *src_alpha = M_IMGDATA->m_alpha; - // dest_alpha starts just beyond the first line, decreases before each step, - // and after each line is finished, increases by 2 widths (skipping the line - // just copied and the line that will be copied next) - unsigned char *dest_alpha = alpha + width; - - for (long jj = 0; jj < height; ++jj) - { - for (long i = 0; i < width; ++i) { - *(--dest_alpha) = *(src_alpha++); // copy one pixel - } - dest_alpha += 2 * width; // advance beyond the end of the next line - } - } - } - else - { - for (long i = 0; i < height; i++) - { - target_data = data + 3*width*(height-1-i); - memcpy( target_data, source_data, (size_t)3*width ); - source_data += 3*width; - } - - if (alpha != NULL) - { - // src_alpha starts at the first pixel and increases by 1 width after each step - // (a step here is the copy of the alpha channel of an entire line) - const unsigned char *src_alpha = M_IMGDATA->m_alpha; - // dest_alpha starts just beyond the last line (beyond the whole image) - // and decreases by 1 width before each step - unsigned char *dest_alpha = alpha + width * height; - - for (long jj = 0; jj < height; ++jj) - { - dest_alpha -= width; - memcpy( dest_alpha, src_alpha, (size_t)width ); - src_alpha += width; - } - } - } - - return image; -} - -wxImage wxImage::GetSubImage( const wxRect &rect ) const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) && - (rect.GetRight()<=GetWidth()) && (rect.GetBottom()<=GetHeight()), - image, wxT("invalid subimage size") ); - - const int subwidth = rect.GetWidth(); - const int subheight = rect.GetHeight(); - - image.Create( subwidth, subheight, false ); - - const unsigned char *src_data = GetData(); - const unsigned char *src_alpha = M_IMGDATA->m_alpha; - unsigned char *subdata = image.GetData(); - unsigned char *subalpha = NULL; - - wxCHECK_MSG( subdata, image, wxT("unable to create image") ); - - if (src_alpha != NULL) { - image.SetAlpha(); - subalpha = image.GetAlpha(); - wxCHECK_MSG( subalpha, image, wxT("unable to create alpha channel")); - } - - if (M_IMGDATA->m_hasMask) - image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); - - const int width = GetWidth(); - const int pixsoff = rect.GetLeft() + width * rect.GetTop(); - - src_data += 3 * pixsoff; - src_alpha += pixsoff; // won't be used if was NULL, so this is ok - - for (long j = 0; j < subheight; ++j) - { - memcpy( subdata, src_data, 3 * subwidth ); - subdata += 3 * subwidth; - src_data += 3 * width; - if (subalpha != NULL) { - memcpy( subalpha, src_alpha, subwidth ); - subalpha += subwidth; - src_alpha += width; - } - } - - return image; -} - -wxImage wxImage::Size( const wxSize& size, const wxPoint& pos, - int r_, int g_, int b_ ) const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - wxCHECK_MSG( (size.GetWidth() > 0) && (size.GetHeight() > 0), image, wxT("invalid size") ); - - int width = GetWidth(), height = GetHeight(); - image.Create(size.GetWidth(), size.GetHeight(), false); - - unsigned char r = (unsigned char)r_; - unsigned char g = (unsigned char)g_; - unsigned char b = (unsigned char)b_; - if ((r_ == -1) && (g_ == -1) && (b_ == -1)) - { - GetOrFindMaskColour( &r, &g, &b ); - image.SetMaskColour(r, g, b); - } - - image.SetRGB(wxRect(), r, g, b); - - wxRect subRect(pos.x, pos.y, width, height); - wxRect finalRect(0, 0, size.GetWidth(), size.GetHeight()); - if (pos.x < 0) - finalRect.width -= pos.x; - if (pos.y < 0) - finalRect.height -= pos.y; - - subRect.Intersect(finalRect); - - if (!subRect.IsEmpty()) - { - if ((subRect.GetWidth() == width) && (subRect.GetHeight() == height)) - image.Paste(*this, pos.x, pos.y); - else - image.Paste(GetSubImage(subRect), pos.x, pos.y); - } - - return image; -} - -void wxImage::Paste( const wxImage &image, int x, int y ) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - wxCHECK_RET( image.Ok(), wxT("invalid image") ); - - AllocExclusive(); - - int xx = 0; - int yy = 0; - int width = image.GetWidth(); - int height = image.GetHeight(); - - if (x < 0) - { - xx = -x; - width += x; - } - if (y < 0) - { - yy = -y; - height += y; - } - - if ((x+xx)+width > M_IMGDATA->m_width) - width = M_IMGDATA->m_width - (x+xx); - if ((y+yy)+height > M_IMGDATA->m_height) - height = M_IMGDATA->m_height - (y+yy); - - if (width < 1) return; - if (height < 1) return; - - if ((!HasMask() && !image.HasMask()) || - (HasMask() && !image.HasMask()) || - ((HasMask() && image.HasMask() && - (GetMaskRed()==image.GetMaskRed()) && - (GetMaskGreen()==image.GetMaskGreen()) && - (GetMaskBlue()==image.GetMaskBlue())))) - { - unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth(); - int source_step = image.GetWidth()*3; - - unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width; - int target_step = M_IMGDATA->m_width*3; - for (int j = 0; j < height; j++) - { - memcpy( target_data, source_data, width*3 ); - source_data += source_step; - target_data += target_step; - } - } - - // Copy over the alpha channel from the original image - if ( image.HasAlpha() ) - { - if ( !HasAlpha() ) - InitAlpha(); - - unsigned char* source_data = image.GetAlpha() + xx + yy*image.GetWidth(); - int source_step = image.GetWidth(); - - unsigned char* target_data = GetAlpha() + (x+xx) + (y+yy)*M_IMGDATA->m_width; - int target_step = M_IMGDATA->m_width; - - for (int j = 0; j < height; j++, - source_data += source_step, - target_data += target_step) - { - memcpy( target_data, source_data, width ); - } - } - - if (!HasMask() && image.HasMask()) - { - unsigned char r = image.GetMaskRed(); - unsigned char g = image.GetMaskGreen(); - unsigned char b = image.GetMaskBlue(); - - unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth(); - int source_step = image.GetWidth()*3; - - unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width; - int target_step = M_IMGDATA->m_width*3; - - for (int j = 0; j < height; j++) - { - for (int i = 0; i < width*3; i+=3) - { - if ((source_data[i] != r) || - (source_data[i+1] != g) || - (source_data[i+2] != b)) - { - memcpy( target_data+i, source_data+i, 3 ); - } - } - source_data += source_step; - target_data += target_step; - } - } -} - -void wxImage::Replace( unsigned char r1, unsigned char g1, unsigned char b1, - unsigned char r2, unsigned char g2, unsigned char b2 ) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - AllocExclusive(); - - unsigned char *data = GetData(); - - const int w = GetWidth(); - const int h = GetHeight(); - - for (int j = 0; j < h; j++) - for (int i = 0; i < w; i++) - { - if ((data[0] == r1) && (data[1] == g1) && (data[2] == b1)) - { - data[0] = r2; - data[1] = g2; - data[2] = b2; - } - data += 3; - } -} - -wxImage wxImage::ConvertToGreyscale( double lr, double lg, double lb ) const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); - - unsigned char *dest = image.GetData(); - - wxCHECK_MSG( dest, image, wxT("unable to create image") ); - - unsigned char *src = M_IMGDATA->m_data; - bool hasMask = M_IMGDATA->m_hasMask; - unsigned char maskRed = M_IMGDATA->m_maskRed; - unsigned char maskGreen = M_IMGDATA->m_maskGreen; - unsigned char maskBlue = M_IMGDATA->m_maskBlue; - - if ( hasMask ) - image.SetMaskColour(maskRed, maskGreen, maskBlue); - - const long size = M_IMGDATA->m_width * M_IMGDATA->m_height; - for ( long i = 0; i < size; i++, src += 3, dest += 3 ) - { - // don't modify the mask - if ( hasMask && src[0] == maskRed && src[1] == maskGreen && src[2] == maskBlue ) - { - memcpy(dest, src, 3); - } - else - { - // calculate the luma - double luma = (src[0] * lr + src[1] * lg + src[2] * lb) + 0.5; - dest[0] = dest[1] = dest[2] = wx_static_cast(unsigned char, luma); - } - } - - // copy the alpha channel, if any - if (HasAlpha()) - { - const size_t alphaSize = GetWidth() * GetHeight(); - unsigned char *alpha = (unsigned char*)malloc(alphaSize); - memcpy(alpha, GetAlpha(), alphaSize); - image.InitAlpha(); - image.SetAlpha(alpha); - } - - return image; -} - -wxImage wxImage::ConvertToMono( unsigned char r, unsigned char g, unsigned char b ) const -{ - wxImage image; - - wxCHECK_MSG( Ok(), image, wxT("invalid image") ); - - image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height, false ); - - unsigned char *data = image.GetData(); - - wxCHECK_MSG( data, image, wxT("unable to create image") ); - - if (M_IMGDATA->m_hasMask) - { - if (M_IMGDATA->m_maskRed == r && M_IMGDATA->m_maskGreen == g && - M_IMGDATA->m_maskBlue == b) - image.SetMaskColour( 255, 255, 255 ); - else - image.SetMaskColour( 0, 0, 0 ); - } - - long size = M_IMGDATA->m_height * M_IMGDATA->m_width; - - unsigned char *srcd = M_IMGDATA->m_data; - unsigned char *tard = image.GetData(); - - for ( long i = 0; i < size; i++, srcd += 3, tard += 3 ) - { - if (srcd[0] == r && srcd[1] == g && srcd[2] == b) - tard[0] = tard[1] = tard[2] = 255; - else - tard[0] = tard[1] = tard[2] = 0; - } - - return image; -} - -int wxImage::GetWidth() const -{ - wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); - - return M_IMGDATA->m_width; -} - -int wxImage::GetHeight() const -{ - wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); - - return M_IMGDATA->m_height; -} - -long wxImage::XYToIndex(int x, int y) const -{ - if ( Ok() && - x >= 0 && y >= 0 && - x < M_IMGDATA->m_width && y < M_IMGDATA->m_height ) - { - return y*M_IMGDATA->m_width + x; - } - - return -1; -} - -void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b ) -{ - long pos = XYToIndex(x, y); - wxCHECK_RET( pos != -1, wxT("invalid image coordinates") ); - - AllocExclusive(); - - pos *= 3; - - M_IMGDATA->m_data[ pos ] = r; - M_IMGDATA->m_data[ pos+1 ] = g; - M_IMGDATA->m_data[ pos+2 ] = b; -} - -void wxImage::SetRGB( const wxRect& rect_, unsigned char r, unsigned char g, unsigned char b ) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - AllocExclusive(); - - wxRect rect(rect_); - wxRect imageRect(0, 0, GetWidth(), GetHeight()); - if ( rect == wxRect() ) - { - rect = imageRect; - } - else - { - wxCHECK_RET( imageRect.Contains(rect.GetTopLeft()) && - imageRect.Contains(rect.GetBottomRight()), - wxT("invalid bounding rectangle") ); - } - - int x1 = rect.GetLeft(), - y1 = rect.GetTop(), - x2 = rect.GetRight() + 1, - y2 = rect.GetBottom() + 1; - - unsigned char *data wxDUMMY_INITIALIZE(NULL); - int x, y, width = GetWidth(); - for (y = y1; y < y2; y++) - { - data = M_IMGDATA->m_data + (y*width + x1)*3; - for (x = x1; x < x2; x++) - { - *data++ = r; - *data++ = g; - *data++ = b; - } - } -} - -unsigned char wxImage::GetRed( int x, int y ) const -{ - long pos = XYToIndex(x, y); - wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); - - pos *= 3; - - return M_IMGDATA->m_data[pos]; -} - -unsigned char wxImage::GetGreen( int x, int y ) const -{ - long pos = XYToIndex(x, y); - wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); - - pos *= 3; - - return M_IMGDATA->m_data[pos+1]; -} - -unsigned char wxImage::GetBlue( int x, int y ) const -{ - long pos = XYToIndex(x, y); - wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); - - pos *= 3; - - return M_IMGDATA->m_data[pos+2]; -} - -bool wxImage::IsOk() const -{ - // image of 0 width or height can't be considered ok - at least because it - // causes crashes in ConvertToBitmap() if we don't catch it in time - wxImageRefData *data = M_IMGDATA; - return data && data->m_ok && data->m_width && data->m_height; -} - -unsigned char *wxImage::GetData() const -{ - wxCHECK_MSG( Ok(), (unsigned char *)NULL, wxT("invalid image") ); - - return M_IMGDATA->m_data; -} - -void wxImage::SetData( unsigned char *data, bool static_data ) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - wxImageRefData *newRefData = new wxImageRefData(); - - newRefData->m_width = M_IMGDATA->m_width; - newRefData->m_height = M_IMGDATA->m_height; - newRefData->m_data = data; - newRefData->m_ok = true; - newRefData->m_maskRed = M_IMGDATA->m_maskRed; - newRefData->m_maskGreen = M_IMGDATA->m_maskGreen; - newRefData->m_maskBlue = M_IMGDATA->m_maskBlue; - newRefData->m_hasMask = M_IMGDATA->m_hasMask; - newRefData->m_static = static_data; - - UnRef(); - - m_refData = newRefData; -} - -void wxImage::SetData( unsigned char *data, int new_width, int new_height, bool static_data ) -{ - wxImageRefData *newRefData = new wxImageRefData(); - - if (m_refData) - { - newRefData->m_width = new_width; - newRefData->m_height = new_height; - newRefData->m_data = data; - newRefData->m_ok = true; - newRefData->m_maskRed = M_IMGDATA->m_maskRed; - newRefData->m_maskGreen = M_IMGDATA->m_maskGreen; - newRefData->m_maskBlue = M_IMGDATA->m_maskBlue; - newRefData->m_hasMask = M_IMGDATA->m_hasMask; - } - else - { - newRefData->m_width = new_width; - newRefData->m_height = new_height; - newRefData->m_data = data; - newRefData->m_ok = true; - } - newRefData->m_static = static_data; - - UnRef(); - - m_refData = newRefData; -} - -// ---------------------------------------------------------------------------- -// alpha channel support -// ---------------------------------------------------------------------------- - -void wxImage::SetAlpha(int x, int y, unsigned char alpha) -{ - wxCHECK_RET( HasAlpha(), wxT("no alpha channel") ); - - long pos = XYToIndex(x, y); - wxCHECK_RET( pos != -1, wxT("invalid image coordinates") ); - - AllocExclusive(); - - M_IMGDATA->m_alpha[pos] = alpha; -} - -unsigned char wxImage::GetAlpha(int x, int y) const -{ - wxCHECK_MSG( HasAlpha(), 0, wxT("no alpha channel") ); - - long pos = XYToIndex(x, y); - wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); - - return M_IMGDATA->m_alpha[pos]; -} - -bool -wxImage::ConvertColourToAlpha(unsigned char r, unsigned char g, unsigned char b) -{ - SetAlpha(NULL); - - const int w = M_IMGDATA->m_width; - const int h = M_IMGDATA->m_height; - - unsigned char *alpha = GetAlpha(); - unsigned char *data = GetData(); - - for ( int y = 0; y < h; y++ ) - { - for ( int x = 0; x < w; x++ ) - { - *alpha++ = *data; - *data++ = r; - *data++ = g; - *data++ = b; - } - } - - return true; -} - -void wxImage::SetAlpha( unsigned char *alpha, bool static_data ) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - AllocExclusive(); - - if ( !alpha ) - { - alpha = (unsigned char *)malloc(M_IMGDATA->m_width*M_IMGDATA->m_height); - } - - if( !M_IMGDATA->m_staticAlpha ) - free(M_IMGDATA->m_alpha); - - M_IMGDATA->m_alpha = alpha; - M_IMGDATA->m_staticAlpha = static_data; -} - -unsigned char *wxImage::GetAlpha() const -{ - wxCHECK_MSG( Ok(), (unsigned char *)NULL, wxT("invalid image") ); - - return M_IMGDATA->m_alpha; -} - -void wxImage::InitAlpha() -{ - wxCHECK_RET( !HasAlpha(), wxT("image already has an alpha channel") ); - - // initialize memory for alpha channel - SetAlpha(); - - unsigned char *alpha = M_IMGDATA->m_alpha; - const size_t lenAlpha = M_IMGDATA->m_width * M_IMGDATA->m_height; - - if ( HasMask() ) - { - // use the mask to initialize the alpha channel. - const unsigned char * const alphaEnd = alpha + lenAlpha; - - const unsigned char mr = M_IMGDATA->m_maskRed; - const unsigned char mg = M_IMGDATA->m_maskGreen; - const unsigned char mb = M_IMGDATA->m_maskBlue; - for ( unsigned char *src = M_IMGDATA->m_data; - alpha < alphaEnd; - src += 3, alpha++ ) - { - *alpha = (src[0] == mr && src[1] == mg && src[2] == mb) - ? wxIMAGE_ALPHA_TRANSPARENT - : wxIMAGE_ALPHA_OPAQUE; - } - - M_IMGDATA->m_hasMask = false; - } - else // no mask - { - // make the image fully opaque - memset(alpha, wxIMAGE_ALPHA_OPAQUE, lenAlpha); - } -} - -// ---------------------------------------------------------------------------- -// mask support -// ---------------------------------------------------------------------------- - -void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b ) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - AllocExclusive(); - - M_IMGDATA->m_maskRed = r; - M_IMGDATA->m_maskGreen = g; - M_IMGDATA->m_maskBlue = b; - M_IMGDATA->m_hasMask = true; -} - -bool wxImage::GetOrFindMaskColour( unsigned char *r, unsigned char *g, unsigned char *b ) const -{ - wxCHECK_MSG( Ok(), false, wxT("invalid image") ); - - if (M_IMGDATA->m_hasMask) - { - if (r) *r = M_IMGDATA->m_maskRed; - if (g) *g = M_IMGDATA->m_maskGreen; - if (b) *b = M_IMGDATA->m_maskBlue; - return true; - } - else - { - FindFirstUnusedColour(r, g, b); - return false; - } -} - -unsigned char wxImage::GetMaskRed() const -{ - wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); - - return M_IMGDATA->m_maskRed; -} - -unsigned char wxImage::GetMaskGreen() const -{ - wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); - - return M_IMGDATA->m_maskGreen; -} - -unsigned char wxImage::GetMaskBlue() const -{ - wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); - - return M_IMGDATA->m_maskBlue; -} - -void wxImage::SetMask( bool mask ) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - AllocExclusive(); - - M_IMGDATA->m_hasMask = mask; -} - -bool wxImage::HasMask() const -{ - wxCHECK_MSG( Ok(), false, wxT("invalid image") ); - - return M_IMGDATA->m_hasMask; -} - -bool wxImage::IsTransparent(int x, int y, unsigned char threshold) const -{ - long pos = XYToIndex(x, y); - wxCHECK_MSG( pos != -1, false, wxT("invalid image coordinates") ); - - // check mask - if ( M_IMGDATA->m_hasMask ) - { - const unsigned char *p = M_IMGDATA->m_data + 3*pos; - if ( p[0] == M_IMGDATA->m_maskRed && - p[1] == M_IMGDATA->m_maskGreen && - p[2] == M_IMGDATA->m_maskBlue ) - { - return true; - } - } - - // then check alpha - if ( M_IMGDATA->m_alpha ) - { - if ( M_IMGDATA->m_alpha[pos] < threshold ) - { - // transparent enough - return true; - } - } - - // not transparent - return false; -} - -bool wxImage::SetMaskFromImage(const wxImage& mask, - unsigned char mr, unsigned char mg, unsigned char mb) -{ - // check that the images are the same size - if ( (M_IMGDATA->m_height != mask.GetHeight() ) || (M_IMGDATA->m_width != mask.GetWidth () ) ) - { - wxLogError( _("Image and mask have different sizes.") ); - return false; - } - - // find unused colour - unsigned char r,g,b ; - if (!FindFirstUnusedColour(&r, &g, &b)) - { - wxLogError( _("No unused colour in image being masked.") ); - return false ; - } - - AllocExclusive(); - - unsigned char *imgdata = GetData(); - unsigned char *maskdata = mask.GetData(); - - const int w = GetWidth(); - const int h = GetHeight(); - - for (int j = 0; j < h; j++) - { - for (int i = 0; i < w; i++) - { - if ((maskdata[0] == mr) && (maskdata[1] == mg) && (maskdata[2] == mb)) - { - imgdata[0] = r; - imgdata[1] = g; - imgdata[2] = b; - } - imgdata += 3; - maskdata += 3; - } - } - - SetMaskColour(r, g, b); - SetMask(true); - - return true; -} - -bool wxImage::ConvertAlphaToMask(unsigned char threshold) -{ - if (!HasAlpha()) - return true; - - unsigned char mr, mg, mb; - if (!FindFirstUnusedColour(&mr, &mg, &mb)) - { - wxLogError( _("No unused colour in image being masked.") ); - return false; - } - - AllocExclusive(); - - SetMask(true); - SetMaskColour(mr, mg, mb); - - unsigned char *imgdata = GetData(); - unsigned char *alphadata = GetAlpha(); - - int w = GetWidth(); - int h = GetHeight(); - - for (int y = 0; y < h; y++) - { - for (int x = 0; x < w; x++, imgdata += 3, alphadata++) - { - if (*alphadata < threshold) - { - imgdata[0] = mr; - imgdata[1] = mg; - imgdata[2] = mb; - } - } - } - - if( !M_IMGDATA->m_staticAlpha ) - free(M_IMGDATA->m_alpha); - - M_IMGDATA->m_alpha = NULL; - M_IMGDATA->m_staticAlpha = false; - - return true; -} - -// ---------------------------------------------------------------------------- -// Palette functions -// ---------------------------------------------------------------------------- - -#if wxUSE_PALETTE - -bool wxImage::HasPalette() const -{ - if (!Ok()) - return false; - - return M_IMGDATA->m_palette.Ok(); -} - -const wxPalette& wxImage::GetPalette() const -{ - wxCHECK_MSG( Ok(), wxNullPalette, wxT("invalid image") ); - - return M_IMGDATA->m_palette; -} - -void wxImage::SetPalette(const wxPalette& palette) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - AllocExclusive(); - - M_IMGDATA->m_palette = palette; -} - -#endif // wxUSE_PALETTE - -// ---------------------------------------------------------------------------- -// Option functions (arbitrary name/value mapping) -// ---------------------------------------------------------------------------- - -void wxImage::SetOption(const wxString& name, const wxString& value) -{ - wxCHECK_RET( Ok(), wxT("invalid image") ); - - AllocExclusive(); - - int idx = M_IMGDATA->m_optionNames.Index(name, false); - if (idx == wxNOT_FOUND) - { - M_IMGDATA->m_optionNames.Add(name); - M_IMGDATA->m_optionValues.Add(value); - } - else - { - M_IMGDATA->m_optionNames[idx] = name; - M_IMGDATA->m_optionValues[idx] = value; - } -} - -void wxImage::SetOption(const wxString& name, int value) -{ - wxString valStr; - valStr.Printf(wxT("%d"), value); - SetOption(name, valStr); -} - -wxString wxImage::GetOption(const wxString& name) const -{ - wxCHECK_MSG( Ok(), wxEmptyString, wxT("invalid image") ); - - int idx = M_IMGDATA->m_optionNames.Index(name, false); - if (idx == wxNOT_FOUND) - return wxEmptyString; - else - return M_IMGDATA->m_optionValues[idx]; -} - -int wxImage::GetOptionInt(const wxString& name) const -{ - return wxAtoi(GetOption(name)); -} - -bool wxImage::HasOption(const wxString& name) const -{ - wxCHECK_MSG( Ok(), false, wxT("invalid image") ); - - return (M_IMGDATA->m_optionNames.Index(name, false) != wxNOT_FOUND); -} - -// ---------------------------------------------------------------------------- -// image I/O -// ---------------------------------------------------------------------------- - -bool wxImage::LoadFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), - long WXUNUSED_UNLESS_STREAMS(type), - int WXUNUSED_UNLESS_STREAMS(index) ) -{ -#if HAS_FILE_STREAMS - if (wxFileExists(filename)) - { - wxImageFileInputStream stream(filename); - wxBufferedInputStream bstream( stream ); - return LoadFile(bstream, type, index); - } - else - { - wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); - - return false; - } -#else // !HAS_FILE_STREAMS - return false; -#endif // HAS_FILE_STREAMS -} - -bool wxImage::LoadFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), - const wxString& WXUNUSED_UNLESS_STREAMS(mimetype), - int WXUNUSED_UNLESS_STREAMS(index) ) -{ -#if HAS_FILE_STREAMS - if (wxFileExists(filename)) - { - wxImageFileInputStream stream(filename); - wxBufferedInputStream bstream( stream ); - return LoadFile(bstream, mimetype, index); - } - else - { - wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); - - return false; - } -#else // !HAS_FILE_STREAMS - return false; -#endif // HAS_FILE_STREAMS -} - - - -bool wxImage::SaveFile( const wxString& filename ) const -{ - wxString ext = filename.AfterLast('.').Lower(); - - wxImageHandler * pHandler = FindHandler(ext, -1); - if (pHandler) - { - return SaveFile(filename, pHandler->GetType()); - } - - wxLogError(_("Can't save image to file '%s': unknown extension."), filename.c_str()); - - return false; -} - -bool wxImage::SaveFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), - int WXUNUSED_UNLESS_STREAMS(type) ) const -{ -#if HAS_FILE_STREAMS - wxCHECK_MSG( Ok(), false, wxT("invalid image") ); - - ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename); - - wxImageFileOutputStream stream(filename); - - if ( stream.IsOk() ) - { - wxBufferedOutputStream bstream( stream ); - return SaveFile(bstream, type); - } -#endif // HAS_FILE_STREAMS - - return false; -} - -bool wxImage::SaveFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), - const wxString& WXUNUSED_UNLESS_STREAMS(mimetype) ) const -{ -#if HAS_FILE_STREAMS - wxCHECK_MSG( Ok(), false, wxT("invalid image") ); - - ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename); - - wxImageFileOutputStream stream(filename); - - if ( stream.IsOk() ) - { - wxBufferedOutputStream bstream( stream ); - return SaveFile(bstream, mimetype); - } -#endif // HAS_FILE_STREAMS - - return false; -} - -bool wxImage::CanRead( const wxString& WXUNUSED_UNLESS_STREAMS(name) ) -{ -#if HAS_FILE_STREAMS - wxImageFileInputStream stream(name); - return CanRead(stream); -#else - return false; -#endif -} - -int wxImage::GetImageCount( const wxString& WXUNUSED_UNLESS_STREAMS(name), - long WXUNUSED_UNLESS_STREAMS(type) ) -{ -#if HAS_FILE_STREAMS - wxImageFileInputStream stream(name); - if (stream.Ok()) - return GetImageCount(stream, type); -#endif - - return 0; -} - -#if wxUSE_STREAMS - -bool wxImage::CanRead( wxInputStream &stream ) -{ - const wxList& list = GetHandlers(); - - for ( wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() ) - { - wxImageHandler *handler=(wxImageHandler*)node->GetData(); - if (handler->CanRead( stream )) - return true; - } - - return false; -} - -int wxImage::GetImageCount( wxInputStream &stream, long type ) -{ - wxImageHandler *handler; - - if ( type == wxBITMAP_TYPE_ANY ) - { - wxList &list=GetHandlers(); - - for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext()) - { - handler=(wxImageHandler*)node->GetData(); - if ( handler->CanRead(stream) ) - return handler->GetImageCount(stream); - - } - - wxLogWarning(_("No handler found for image type.")); - return 0; - } - - handler = FindHandler(type); - - if ( !handler ) - { - wxLogWarning(_("No image handler for type %ld defined."), type); - return false; - } - - if ( handler->CanRead(stream) ) - { - return handler->GetImageCount(stream); - } - else - { - wxLogError(_("Image file is not of type %ld."), type); - return 0; - } -} - -bool wxImage::LoadFile( wxInputStream& stream, long type, int index ) -{ - UnRef(); - - m_refData = new wxImageRefData; - - wxImageHandler *handler; - - if ( type == wxBITMAP_TYPE_ANY ) - { - wxList &list=GetHandlers(); - - for ( wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() ) - { - handler=(wxImageHandler*)node->GetData(); - if ( handler->CanRead(stream) ) - return handler->LoadFile(this, stream, true/*verbose*/, index); - - } - - wxLogWarning( _("No handler found for image type.") ); - return false; - } - - handler = FindHandler(type); - - if (handler == 0) - { - wxLogWarning( _("No image handler for type %ld defined."), type ); - - return false; - } - - if (stream.IsSeekable() && !handler->CanRead(stream)) - { - wxLogError(_("Image file is not of type %ld."), type); - return false; - } - else - return handler->LoadFile(this, stream, true/*verbose*/, index); -} - -bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype, int index ) -{ - UnRef(); - - m_refData = new wxImageRefData; - - wxImageHandler *handler = FindHandlerMime(mimetype); - - if (handler == 0) - { - wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() ); - - return false; - } - - if (stream.IsSeekable() && !handler->CanRead(stream)) - { - wxLogError(_("Image file is not of type %s."), (const wxChar*) mimetype); - return false; - } - else - return handler->LoadFile( this, stream, true/*verbose*/, index ); -} - -bool wxImage::SaveFile( wxOutputStream& stream, int type ) const -{ - wxCHECK_MSG( Ok(), false, wxT("invalid image") ); - - wxImageHandler *handler = FindHandler(type); - if ( !handler ) - { - wxLogWarning( _("No image handler for type %d defined."), type ); - - return false; - } - - return handler->SaveFile( (wxImage*)this, stream ); -} - -bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype ) const -{ - wxCHECK_MSG( Ok(), false, wxT("invalid image") ); - - wxImageHandler *handler = FindHandlerMime(mimetype); - if ( !handler ) - { - wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() ); - - return false; - } - - return handler->SaveFile( (wxImage*)this, stream ); -} -#endif // wxUSE_STREAMS - -// ---------------------------------------------------------------------------- -// image I/O handlers -// ---------------------------------------------------------------------------- - -void wxImage::AddHandler( wxImageHandler *handler ) -{ - // Check for an existing handler of the type being added. - if (FindHandler( handler->GetType() ) == 0) - { - sm_handlers.Append( handler ); - } - else - { - // This is not documented behaviour, merely the simplest 'fix' - // for preventing duplicate additions. If someone ever has - // a good reason to add and remove duplicate handlers (and they - // may) we should probably refcount the duplicates. - // also an issue in InsertHandler below. - - wxLogDebug( _T("Adding duplicate image handler for '%s'"), - handler->GetName().c_str() ); - delete handler; - } -} - -void wxImage::InsertHandler( wxImageHandler *handler ) -{ - // Check for an existing handler of the type being added. - if (FindHandler( handler->GetType() ) == 0) - { - sm_handlers.Insert( handler ); - } - else - { - // see AddHandler for additional comments. - wxLogDebug( _T("Inserting duplicate image handler for '%s'"), - handler->GetName().c_str() ); - delete handler; - } -} - -bool wxImage::RemoveHandler( const wxString& name ) -{ - wxImageHandler *handler = FindHandler(name); - if (handler) - { - sm_handlers.DeleteObject(handler); - delete handler; - return true; - } - else - return false; -} - -wxImageHandler *wxImage::FindHandler( const wxString& name ) -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while (node) - { - wxImageHandler *handler = (wxImageHandler*)node->GetData(); - if (handler->GetName().Cmp(name) == 0) return handler; - - node = node->GetNext(); - } - return 0; -} - -wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType ) -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while (node) - { - wxImageHandler *handler = (wxImageHandler*)node->GetData(); - if ( (handler->GetExtension().Cmp(extension) == 0) && - (bitmapType == -1 || handler->GetType() == bitmapType) ) - return handler; - node = node->GetNext(); - } - return 0; -} - -wxImageHandler *wxImage::FindHandler( long bitmapType ) -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while (node) - { - wxImageHandler *handler = (wxImageHandler *)node->GetData(); - if (handler->GetType() == bitmapType) return handler; - node = node->GetNext(); - } - return 0; -} - -wxImageHandler *wxImage::FindHandlerMime( const wxString& mimetype ) -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while (node) - { - wxImageHandler *handler = (wxImageHandler *)node->GetData(); - if (handler->GetMimeType().IsSameAs(mimetype, false)) return handler; - node = node->GetNext(); - } - return 0; -} - -void wxImage::InitStandardHandlers() -{ -#if wxUSE_STREAMS - AddHandler(new wxBMPHandler); -#endif // wxUSE_STREAMS -} - -void wxImage::CleanUpHandlers() -{ - wxList::compatibility_iterator node = sm_handlers.GetFirst(); - while (node) - { - wxImageHandler *handler = (wxImageHandler *)node->GetData(); - wxList::compatibility_iterator next = node->GetNext(); - delete handler; - node = next; - } - - sm_handlers.Clear(); -} - -wxString wxImage::GetImageExtWildcard() -{ - wxString fmts; - - wxList& Handlers = wxImage::GetHandlers(); - wxList::compatibility_iterator Node = Handlers.GetFirst(); - while ( Node ) - { - wxImageHandler* Handler = (wxImageHandler*)Node->GetData(); - fmts += wxT("*.") + Handler->GetExtension(); - Node = Node->GetNext(); - if ( Node ) fmts += wxT(";"); - } - - return wxT("(") + fmts + wxT(")|") + fmts; -} - -wxImage::HSVValue wxImage::RGBtoHSV(const RGBValue& rgb) -{ - const double red = rgb.red / 255.0, - green = rgb.green / 255.0, - blue = rgb.blue / 255.0; - - // find the min and max intensity (and remember which one was it for the - // latter) - double minimumRGB = red; - if ( green < minimumRGB ) - minimumRGB = green; - if ( blue < minimumRGB ) - minimumRGB = blue; - - enum { RED, GREEN, BLUE } chMax = RED; - double maximumRGB = red; - if ( green > maximumRGB ) - { - chMax = GREEN; - maximumRGB = green; - } - if ( blue > maximumRGB ) - { - chMax = BLUE; - maximumRGB = blue; - } - - const double value = maximumRGB; - - double hue = 0.0, saturation; - const double deltaRGB = maximumRGB - minimumRGB; - if ( wxIsNullDouble(deltaRGB) ) - { - // Gray has no color - hue = 0.0; - saturation = 0.0; - } - else - { - switch ( chMax ) - { - case RED: - hue = (green - blue) / deltaRGB; - break; - - case GREEN: - hue = 2.0 + (blue - red) / deltaRGB; - break; - - case BLUE: - hue = 4.0 + (red - green) / deltaRGB; - break; - - default: - wxFAIL_MSG(wxT("hue not specified")); - break; - } - - hue /= 6.0; - - if ( hue < 0.0 ) - hue += 1.0; - - saturation = deltaRGB / maximumRGB; - } - - return HSVValue(hue, saturation, value); -} - -wxImage::RGBValue wxImage::HSVtoRGB(const HSVValue& hsv) -{ - double red, green, blue; - - if ( wxIsNullDouble(hsv.saturation) ) - { - // Grey - red = hsv.value; - green = hsv.value; - blue = hsv.value; - } - else // not grey - { - double hue = hsv.hue * 6.0; // sector 0 to 5 - int i = (int)floor(hue); - double f = hue - i; // fractional part of h - double p = hsv.value * (1.0 - hsv.saturation); - - switch (i) - { - case 0: - red = hsv.value; - green = hsv.value * (1.0 - hsv.saturation * (1.0 - f)); - blue = p; - break; - - case 1: - red = hsv.value * (1.0 - hsv.saturation * f); - green = hsv.value; - blue = p; - break; - - case 2: - red = p; - green = hsv.value; - blue = hsv.value * (1.0 - hsv.saturation * (1.0 - f)); - break; - - case 3: - red = p; - green = hsv.value * (1.0 - hsv.saturation * f); - blue = hsv.value; - break; - - case 4: - red = hsv.value * (1.0 - hsv.saturation * (1.0 - f)); - green = p; - blue = hsv.value; - break; - - default: // case 5: - red = hsv.value; - green = p; - blue = hsv.value * (1.0 - hsv.saturation * f); - break; - } - } - - return RGBValue((unsigned char)(red * 255.0), - (unsigned char)(green * 255.0), - (unsigned char)(blue * 255.0)); -} - -/* - * Rotates the hue of each pixel of the image. angle is a double in the range - * -1.0..1.0 where -1.0 is -360 degrees and 1.0 is 360 degrees - */ -void wxImage::RotateHue(double angle) -{ - AllocExclusive(); - - unsigned char *srcBytePtr; - unsigned char *dstBytePtr; - unsigned long count; - wxImage::HSVValue hsv; - wxImage::RGBValue rgb; - - wxASSERT (angle >= -1.0 && angle <= 1.0); - count = M_IMGDATA->m_width * M_IMGDATA->m_height; - if ( count > 0 && !wxIsNullDouble(angle) ) - { - srcBytePtr = M_IMGDATA->m_data; - dstBytePtr = srcBytePtr; - do - { - rgb.red = *srcBytePtr++; - rgb.green = *srcBytePtr++; - rgb.blue = *srcBytePtr++; - hsv = RGBtoHSV(rgb); - - hsv.hue = hsv.hue + angle; - if (hsv.hue > 1.0) - hsv.hue = hsv.hue - 1.0; - else if (hsv.hue < 0.0) - hsv.hue = hsv.hue + 1.0; - - rgb = HSVtoRGB(hsv); - *dstBytePtr++ = rgb.red; - *dstBytePtr++ = rgb.green; - *dstBytePtr++ = rgb.blue; - } while (--count != 0); - } -} - -//----------------------------------------------------------------------------- -// wxImageHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxImageHandler,wxObject) - -#if wxUSE_STREAMS -bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream), bool WXUNUSED(verbose), int WXUNUSED(index) ) -{ - return false; -} - -bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool WXUNUSED(verbose) ) -{ - return false; -} - -int wxImageHandler::GetImageCount( wxInputStream& WXUNUSED(stream) ) -{ - return 1; -} - -bool wxImageHandler::CanRead( const wxString& name ) -{ - if (wxFileExists(name)) - { - wxImageFileInputStream stream(name); - return CanRead(stream); - } - - wxLogError( _("Can't check image format of file '%s': file does not exist."), name.c_str() ); - - return false; -} - -bool wxImageHandler::CallDoCanRead(wxInputStream& stream) -{ - wxFileOffset posOld = stream.TellI(); - if ( posOld == wxInvalidOffset ) - { - // can't test unseekable stream - return false; - } - - bool ok = DoCanRead(stream); - - // restore the old position to be able to test other formats and so on - if ( stream.SeekI(posOld) == wxInvalidOffset ) - { - wxLogDebug(_T("Failed to rewind the stream in wxImageHandler!")); - - // reading would fail anyhow as we're not at the right position - return false; - } - - return ok; -} - -#endif // wxUSE_STREAMS - -// ---------------------------------------------------------------------------- -// image histogram stuff -// ---------------------------------------------------------------------------- - -bool -wxImageHistogram::FindFirstUnusedColour(unsigned char *r, - unsigned char *g, - unsigned char *b, - unsigned char r2, - unsigned char b2, - unsigned char g2) const -{ - unsigned long key = MakeKey(r2, g2, b2); - - while ( find(key) != end() ) - { - // color already used - r2++; - if ( r2 >= 255 ) - { - r2 = 0; - g2++; - if ( g2 >= 255 ) - { - g2 = 0; - b2++; - if ( b2 >= 255 ) - { - wxLogError(_("No unused colour in image.") ); - return false; - } - } - } - - key = MakeKey(r2, g2, b2); - } - - if ( r ) - *r = r2; - if ( g ) - *g = g2; - if ( b ) - *b = b2; - - return true; -} - -bool -wxImage::FindFirstUnusedColour(unsigned char *r, - unsigned char *g, - unsigned char *b, - unsigned char r2, - unsigned char b2, - unsigned char g2) const -{ - wxImageHistogram histogram; - - ComputeHistogram(histogram); - - return histogram.FindFirstUnusedColour(r, g, b, r2, g2, b2); -} - - - -// GRG, Dic/99 -// Counts and returns the number of different colours. Optionally stops -// when it exceeds 'stopafter' different colours. This is useful, for -// example, to see if the image can be saved as 8-bit (256 colour or -// less, in this case it would be invoked as CountColours(256)). Default -// value for stopafter is -1 (don't care). -// -unsigned long wxImage::CountColours( unsigned long stopafter ) const -{ - wxHashTable h; - wxObject dummy; - unsigned char r, g, b; - unsigned char *p; - unsigned long size, nentries, key; - - p = GetData(); - size = GetWidth() * GetHeight(); - nentries = 0; - - for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++) - { - r = *(p++); - g = *(p++); - b = *(p++); - key = wxImageHistogram::MakeKey(r, g, b); - - if (h.Get(key) == NULL) - { - h.Put(key, &dummy); - nentries++; - } - } - - return nentries; -} - - -unsigned long wxImage::ComputeHistogram( wxImageHistogram &h ) const -{ - unsigned char *p = GetData(); - unsigned long nentries = 0; - - h.clear(); - - const unsigned long size = GetWidth() * GetHeight(); - - unsigned char r, g, b; - for ( unsigned long n = 0; n < size; n++ ) - { - r = *p++; - g = *p++; - b = *p++; - - wxImageHistogramEntry& entry = h[wxImageHistogram::MakeKey(r, g, b)]; - - if ( entry.value++ == 0 ) - entry.index = nentries++; - } - - return nentries; -} - -/* - * Rotation code by Carlos Moreno - */ - -static const double wxROTATE_EPSILON = 1e-10; - -// Auxiliary function to rotate a point (x,y) with respect to point p0 -// make it inline and use a straight return to facilitate optimization -// also, the function receives the sine and cosine of the angle to avoid -// repeating the time-consuming calls to these functions -- sin/cos can -// be computed and stored in the calling function. - -static inline wxRealPoint -wxRotatePoint(const wxRealPoint& p, double cos_angle, double sin_angle, - const wxRealPoint& p0) -{ - return wxRealPoint(p0.x + (p.x - p0.x) * cos_angle - (p.y - p0.y) * sin_angle, - p0.y + (p.y - p0.y) * cos_angle + (p.x - p0.x) * sin_angle); -} - -static inline wxRealPoint -wxRotatePoint(double x, double y, double cos_angle, double sin_angle, - const wxRealPoint & p0) -{ - return wxRotatePoint (wxRealPoint(x,y), cos_angle, sin_angle, p0); -} - -wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool interpolating, wxPoint * offset_after_rotation) const -{ - int i; - angle = -angle; // screen coordinates are a mirror image of "real" coordinates - - bool has_alpha = HasAlpha(); - - const int w = GetWidth(), - h = GetHeight(); - - // Create pointer-based array to accelerate access to wxImage's data - unsigned char ** data = new unsigned char * [h]; - data[0] = GetData(); - for (i = 1; i < h; i++) - data[i] = data[i - 1] + (3 * w); - - // Same for alpha channel - unsigned char ** alpha = NULL; - if (has_alpha) - { - alpha = new unsigned char * [h]; - alpha[0] = GetAlpha(); - for (i = 1; i < h; i++) - alpha[i] = alpha[i - 1] + w; - } - - // precompute coefficients for rotation formula - // (sine and cosine of the angle) - const double cos_angle = cos(angle); - const double sin_angle = sin(angle); - - // Create new Image to store the result - // First, find rectangle that covers the rotated image; to do that, - // rotate the four corners - - const wxRealPoint p0(centre_of_rotation.x, centre_of_rotation.y); - - wxRealPoint p1 = wxRotatePoint (0, 0, cos_angle, sin_angle, p0); - wxRealPoint p2 = wxRotatePoint (0, h, cos_angle, sin_angle, p0); - wxRealPoint p3 = wxRotatePoint (w, 0, cos_angle, sin_angle, p0); - wxRealPoint p4 = wxRotatePoint (w, h, cos_angle, sin_angle, p0); - - int x1a = (int) floor (wxMin (wxMin(p1.x, p2.x), wxMin(p3.x, p4.x))); - int y1a = (int) floor (wxMin (wxMin(p1.y, p2.y), wxMin(p3.y, p4.y))); - int x2a = (int) ceil (wxMax (wxMax(p1.x, p2.x), wxMax(p3.x, p4.x))); - int y2a = (int) ceil (wxMax (wxMax(p1.y, p2.y), wxMax(p3.y, p4.y))); - - // Create rotated image - wxImage rotated (x2a - x1a + 1, y2a - y1a + 1, false); - // With alpha channel - if (has_alpha) - rotated.SetAlpha(); - - if (offset_after_rotation != NULL) - { - *offset_after_rotation = wxPoint (x1a, y1a); - } - - // GRG: The rotated (destination) image is always accessed - // sequentially, so there is no need for a pointer-based - // array here (and in fact it would be slower). - // - unsigned char * dst = rotated.GetData(); - - unsigned char * alpha_dst = NULL; - if (has_alpha) - alpha_dst = rotated.GetAlpha(); - - // GRG: if the original image has a mask, use its RGB values - // as the blank pixel, else, fall back to default (black). - // - unsigned char blank_r = 0; - unsigned char blank_g = 0; - unsigned char blank_b = 0; - - if (HasMask()) - { - blank_r = GetMaskRed(); - blank_g = GetMaskGreen(); - blank_b = GetMaskBlue(); - rotated.SetMaskColour( blank_r, blank_g, blank_b ); - } - - // Now, for each point of the rotated image, find where it came from, by - // performing an inverse rotation (a rotation of -angle) and getting the - // pixel at those coordinates - - const int rH = rotated.GetHeight(); - const int rW = rotated.GetWidth(); - - // GRG: I've taken the (interpolating) test out of the loops, so that - // it is done only once, instead of repeating it for each pixel. - - if (interpolating) - { - for (int y = 0; y < rH; y++) - { - for (int x = 0; x < rW; x++) - { - wxRealPoint src = wxRotatePoint (x + x1a, y + y1a, cos_angle, -sin_angle, p0); - - if (-0.25 < src.x && src.x < w - 0.75 && - -0.25 < src.y && src.y < h - 0.75) - { - // interpolate using the 4 enclosing grid-points. Those - // points can be obtained using floor and ceiling of the - // exact coordinates of the point - int x1, y1, x2, y2; - - if (0 < src.x && src.x < w - 1) - { - x1 = wxRound(floor(src.x)); - x2 = wxRound(ceil(src.x)); - } - else // else means that x is near one of the borders (0 or width-1) - { - x1 = x2 = wxRound (src.x); - } - - if (0 < src.y && src.y < h - 1) - { - y1 = wxRound(floor(src.y)); - y2 = wxRound(ceil(src.y)); - } - else - { - y1 = y2 = wxRound (src.y); - } - - // get four points and the distances (square of the distance, - // for efficiency reasons) for the interpolation formula - - // GRG: Do not calculate the points until they are - // really needed -- this way we can calculate - // just one, instead of four, if d1, d2, d3 - // or d4 are < wxROTATE_EPSILON - - const double d1 = (src.x - x1) * (src.x - x1) + (src.y - y1) * (src.y - y1); - const double d2 = (src.x - x2) * (src.x - x2) + (src.y - y1) * (src.y - y1); - const double d3 = (src.x - x2) * (src.x - x2) + (src.y - y2) * (src.y - y2); - const double d4 = (src.x - x1) * (src.x - x1) + (src.y - y2) * (src.y - y2); - - // Now interpolate as a weighted average of the four surrounding - // points, where the weights are the distances to each of those points - - // If the point is exactly at one point of the grid of the source - // image, then don't interpolate -- just assign the pixel - - // d1,d2,d3,d4 are positive -- no need for abs() - if (d1 < wxROTATE_EPSILON) - { - unsigned char *p = data[y1] + (3 * x1); - *(dst++) = *(p++); - *(dst++) = *(p++); - *(dst++) = *p; - - if (has_alpha) - *(alpha_dst++) = *(alpha[y1] + x1); - } - else if (d2 < wxROTATE_EPSILON) - { - unsigned char *p = data[y1] + (3 * x2); - *(dst++) = *(p++); - *(dst++) = *(p++); - *(dst++) = *p; - - if (has_alpha) - *(alpha_dst++) = *(alpha[y1] + x2); - } - else if (d3 < wxROTATE_EPSILON) - { - unsigned char *p = data[y2] + (3 * x2); - *(dst++) = *(p++); - *(dst++) = *(p++); - *(dst++) = *p; - - if (has_alpha) - *(alpha_dst++) = *(alpha[y2] + x2); - } - else if (d4 < wxROTATE_EPSILON) - { - unsigned char *p = data[y2] + (3 * x1); - *(dst++) = *(p++); - *(dst++) = *(p++); - *(dst++) = *p; - - if (has_alpha) - *(alpha_dst++) = *(alpha[y2] + x1); - } - else - { - // weights for the weighted average are proportional to the inverse of the distance - unsigned char *v1 = data[y1] + (3 * x1); - unsigned char *v2 = data[y1] + (3 * x2); - unsigned char *v3 = data[y2] + (3 * x2); - unsigned char *v4 = data[y2] + (3 * x1); - - const double w1 = 1/d1, w2 = 1/d2, w3 = 1/d3, w4 = 1/d4; - - // GRG: Unrolled. - - *(dst++) = (unsigned char) - ( (w1 * *(v1++) + w2 * *(v2++) + - w3 * *(v3++) + w4 * *(v4++)) / - (w1 + w2 + w3 + w4) ); - *(dst++) = (unsigned char) - ( (w1 * *(v1++) + w2 * *(v2++) + - w3 * *(v3++) + w4 * *(v4++)) / - (w1 + w2 + w3 + w4) ); - *(dst++) = (unsigned char) - ( (w1 * *v1 + w2 * *v2 + - w3 * *v3 + w4 * *v4) / - (w1 + w2 + w3 + w4) ); - - if (has_alpha) - { - v1 = alpha[y1] + (x1); - v2 = alpha[y1] + (x2); - v3 = alpha[y2] + (x2); - v4 = alpha[y2] + (x1); - - *(alpha_dst++) = (unsigned char) - ( (w1 * *v1 + w2 * *v2 + - w3 * *v3 + w4 * *v4) / - (w1 + w2 + w3 + w4) ); - } - } - } - else - { - *(dst++) = blank_r; - *(dst++) = blank_g; - *(dst++) = blank_b; - - if (has_alpha) - *(alpha_dst++) = 0; - } - } - } - } - else // not interpolating - { - for (int y = 0; y < rH; y++) - { - for (int x = 0; x < rW; x++) - { - wxRealPoint src = wxRotatePoint (x + x1a, y + y1a, cos_angle, -sin_angle, p0); - - const int xs = wxRound (src.x); // wxRound rounds to the - const int ys = wxRound (src.y); // closest integer - - if (0 <= xs && xs < w && 0 <= ys && ys < h) - { - unsigned char *p = data[ys] + (3 * xs); - *(dst++) = *(p++); - *(dst++) = *(p++); - *(dst++) = *p; - - if (has_alpha) - *(alpha_dst++) = *(alpha[ys] + (xs)); - } - else - { - *(dst++) = blank_r; - *(dst++) = blank_g; - *(dst++) = blank_b; - - if (has_alpha) - *(alpha_dst++) = 255; - } - } - } - } - - delete [] data; - - if (has_alpha) - delete [] alpha; - - return rotated; -} - - - - - -// A module to allow wxImage initialization/cleanup -// without calling these functions from app.cpp or from -// the user's application. - -class wxImageModule: public wxModule -{ -DECLARE_DYNAMIC_CLASS(wxImageModule) -public: - wxImageModule() {} - bool OnInit() { wxImage::InitStandardHandlers(); return true; } - void OnExit() { wxImage::CleanUpHandlers(); } -}; - -IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule) - - -#endif // wxUSE_IMAGE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/image.cpp +// Purpose: wxImage +// Author: Robert Roebling +// RCS-ID: $Id: image.cpp 59197 2009-02-28 15:44:53Z VZ $ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE + +#include "wx/image.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/hash.h" + #include "wx/utils.h" + #include "wx/math.h" + #include "wx/module.h" + #include "wx/palette.h" + #include "wx/intl.h" +#endif + +#include "wx/filefn.h" +#include "wx/wfstream.h" +#include "wx/xpmdecod.h" + +// For memcpy +#include + +// make the code compile with either wxFile*Stream or wxFFile*Stream: +#define HAS_FILE_STREAMS (wxUSE_STREAMS && (wxUSE_FILE || wxUSE_FFILE)) + +#if HAS_FILE_STREAMS + #if wxUSE_FFILE + typedef wxFFileInputStream wxImageFileInputStream; + typedef wxFFileOutputStream wxImageFileOutputStream; + #elif wxUSE_FILE + typedef wxFileInputStream wxImageFileInputStream; + typedef wxFileOutputStream wxImageFileOutputStream; + #endif // wxUSE_FILE/wxUSE_FFILE +#endif // HAS_FILE_STREAMS + +#if wxUSE_VARIANT +IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxImage,WXDLLEXPORT) +#endif + +//----------------------------------------------------------------------------- +// wxImage +//----------------------------------------------------------------------------- + +class wxImageRefData: public wxObjectRefData +{ +public: + wxImageRefData(); + virtual ~wxImageRefData(); + + int m_width; + int m_height; + unsigned char *m_data; + + bool m_hasMask; + unsigned char m_maskRed,m_maskGreen,m_maskBlue; + + // alpha channel data, may be NULL for the formats without alpha support + unsigned char *m_alpha; + + bool m_ok; + + // if true, m_data is pointer to static data and shouldn't be freed + bool m_static; + + // same as m_static but for m_alpha + bool m_staticAlpha; + +#if wxUSE_PALETTE + wxPalette m_palette; +#endif // wxUSE_PALETTE + + wxArrayString m_optionNames; + wxArrayString m_optionValues; + + DECLARE_NO_COPY_CLASS(wxImageRefData) +}; + +wxImageRefData::wxImageRefData() +{ + m_width = 0; + m_height = 0; + m_data = + m_alpha = (unsigned char *) NULL; + + m_maskRed = 0; + m_maskGreen = 0; + m_maskBlue = 0; + m_hasMask = false; + + m_ok = false; + m_static = + m_staticAlpha = false; +} + +wxImageRefData::~wxImageRefData() +{ + if ( !m_static ) + free( m_data ); + if ( !m_staticAlpha ) + free( m_alpha ); +} + +wxList wxImage::sm_handlers; + +wxImage wxNullImage; + +//----------------------------------------------------------------------------- + +#define M_IMGDATA wx_static_cast(wxImageRefData*, m_refData) + +IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject) + +wxImage::wxImage( int width, int height, bool clear ) +{ + Create( width, height, clear ); +} + +wxImage::wxImage( int width, int height, unsigned char* data, bool static_data ) +{ + Create( width, height, data, static_data ); +} + +wxImage::wxImage( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data ) +{ + Create( width, height, data, alpha, static_data ); +} + +wxImage::wxImage( const wxString& name, long type, int index ) +{ + LoadFile( name, type, index ); +} + +wxImage::wxImage( const wxString& name, const wxString& mimetype, int index ) +{ + LoadFile( name, mimetype, index ); +} + +#if wxUSE_STREAMS +wxImage::wxImage( wxInputStream& stream, long type, int index ) +{ + LoadFile( stream, type, index ); +} + +wxImage::wxImage( wxInputStream& stream, const wxString& mimetype, int index ) +{ + LoadFile( stream, mimetype, index ); +} +#endif // wxUSE_STREAMS + +wxImage::wxImage(const char* const* xpmData) +{ + Create(xpmData); +} + +bool wxImage::Create(const char* const* xpmData) +{ +#if wxUSE_XPM + UnRef(); + + wxXPMDecoder decoder; + (*this) = decoder.ReadData(xpmData); + return Ok(); +#else + return false; +#endif +} + +bool wxImage::Create( int width, int height, bool clear ) +{ + UnRef(); + + m_refData = new wxImageRefData(); + + M_IMGDATA->m_data = (unsigned char *) malloc( width*height*3 ); + if (!M_IMGDATA->m_data) + { + UnRef(); + return false; + } + + if (clear) + memset(M_IMGDATA->m_data, 0, width*height*3); + + M_IMGDATA->m_width = width; + M_IMGDATA->m_height = height; + M_IMGDATA->m_ok = true; + + return true; +} + +bool wxImage::Create( int width, int height, unsigned char* data, bool static_data ) +{ + UnRef(); + + wxCHECK_MSG( data, false, _T("NULL data in wxImage::Create") ); + + m_refData = new wxImageRefData(); + + M_IMGDATA->m_data = data; + M_IMGDATA->m_width = width; + M_IMGDATA->m_height = height; + M_IMGDATA->m_ok = true; + M_IMGDATA->m_static = static_data; + + return true; +} + +bool wxImage::Create( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data ) +{ + UnRef(); + + wxCHECK_MSG( data, false, _T("NULL data in wxImage::Create") ); + + m_refData = new wxImageRefData(); + + M_IMGDATA->m_data = data; + M_IMGDATA->m_alpha = alpha; + M_IMGDATA->m_width = width; + M_IMGDATA->m_height = height; + M_IMGDATA->m_ok = true; + M_IMGDATA->m_static = static_data; + M_IMGDATA->m_staticAlpha = static_data; + + return true; +} + +void wxImage::Destroy() +{ + UnRef(); +} + +wxObjectRefData* wxImage::CreateRefData() const +{ + return new wxImageRefData; +} + +wxObjectRefData* wxImage::CloneRefData(const wxObjectRefData* that) const +{ + const wxImageRefData* refData = wx_static_cast(const wxImageRefData*, that); + wxCHECK_MSG(refData->m_ok, NULL, wxT("invalid image") ); + + wxImageRefData* refData_new = new wxImageRefData; + refData_new->m_width = refData->m_width; + refData_new->m_height = refData->m_height; + refData_new->m_maskRed = refData->m_maskRed; + refData_new->m_maskGreen = refData->m_maskGreen; + refData_new->m_maskBlue = refData->m_maskBlue; + refData_new->m_hasMask = refData->m_hasMask; + refData_new->m_ok = true; + unsigned size = unsigned(refData->m_width) * unsigned(refData->m_height); + if (refData->m_alpha != NULL) + { + refData_new->m_alpha = (unsigned char*)malloc(size); + memcpy(refData_new->m_alpha, refData->m_alpha, size); + } + size *= 3; + refData_new->m_data = (unsigned char*)malloc(size); + memcpy(refData_new->m_data, refData->m_data, size); +#if wxUSE_PALETTE + refData_new->m_palette = refData->m_palette; +#endif + refData_new->m_optionNames = refData->m_optionNames; + refData_new->m_optionValues = refData->m_optionValues; + return refData_new; +} + +wxImage wxImage::Copy() const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + image.m_refData = CloneRefData(m_refData); + + return image; +} + +wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const +{ + if( xFactor == 1 && yFactor == 1 ) + return *this; + + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + // can't scale to/from 0 size + wxCHECK_MSG( (xFactor > 0) && (yFactor > 0), image, + wxT("invalid new image size") ); + + long old_height = M_IMGDATA->m_height, + old_width = M_IMGDATA->m_width; + + wxCHECK_MSG( (old_height > 0) && (old_width > 0), image, + wxT("invalid old image size") ); + + long width = old_width / xFactor ; + long height = old_height / yFactor ; + + image.Create( width, height, false ); + + char unsigned *data = image.GetData(); + + wxCHECK_MSG( data, image, wxT("unable to create image") ); + + bool hasMask = false ; + unsigned char maskRed = 0; + unsigned char maskGreen = 0; + unsigned char maskBlue =0 ; + + unsigned char *source_data = M_IMGDATA->m_data; + unsigned char *target_data = data; + unsigned char *source_alpha = 0 ; + unsigned char *target_alpha = 0 ; + if (M_IMGDATA->m_hasMask) + { + hasMask = true ; + maskRed = M_IMGDATA->m_maskRed; + maskGreen = M_IMGDATA->m_maskGreen; + maskBlue =M_IMGDATA->m_maskBlue ; + + image.SetMaskColour( M_IMGDATA->m_maskRed, + M_IMGDATA->m_maskGreen, + M_IMGDATA->m_maskBlue ); + } + else + { + source_alpha = M_IMGDATA->m_alpha ; + if ( source_alpha ) + { + image.SetAlpha() ; + target_alpha = image.GetAlpha() ; + } + } + + for (long y = 0; y < height; y++) + { + for (long x = 0; x < width; x++) + { + unsigned long avgRed = 0 ; + unsigned long avgGreen = 0; + unsigned long avgBlue = 0; + unsigned long avgAlpha = 0 ; + unsigned long counter = 0 ; + // determine average + for ( int y1 = 0 ; y1 < yFactor ; ++y1 ) + { + long y_offset = (y * yFactor + y1) * old_width; + for ( int x1 = 0 ; x1 < xFactor ; ++x1 ) + { + unsigned char *pixel = source_data + 3 * ( y_offset + x * xFactor + x1 ) ; + unsigned char red = pixel[0] ; + unsigned char green = pixel[1] ; + unsigned char blue = pixel[2] ; + unsigned char alpha = 255 ; + if ( source_alpha ) + alpha = *(source_alpha + y_offset + x * xFactor + x1) ; + if ( !hasMask || red != maskRed || green != maskGreen || blue != maskBlue ) + { + if ( alpha > 0 ) + { + avgRed += red ; + avgGreen += green ; + avgBlue += blue ; + } + avgAlpha += alpha ; + counter++ ; + } + } + } + if ( counter == 0 ) + { + *(target_data++) = M_IMGDATA->m_maskRed ; + *(target_data++) = M_IMGDATA->m_maskGreen ; + *(target_data++) = M_IMGDATA->m_maskBlue ; + } + else + { + if ( source_alpha ) + *(target_alpha++) = (unsigned char)(avgAlpha / counter ) ; + *(target_data++) = (unsigned char)(avgRed / counter); + *(target_data++) = (unsigned char)(avgGreen / counter); + *(target_data++) = (unsigned char)(avgBlue / counter); + } + } + } + + // In case this is a cursor, make sure the hotspot is scaled accordingly: + if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ) + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, + (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X))/xFactor); + if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ) + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, + (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y))/yFactor); + + return image; +} + +wxImage wxImage::Scale( int width, int height, int quality ) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + // can't scale to/from 0 size + wxCHECK_MSG( (width > 0) && (height > 0), image, + wxT("invalid new image size") ); + + long old_height = M_IMGDATA->m_height, + old_width = M_IMGDATA->m_width; + wxCHECK_MSG( (old_height > 0) && (old_width > 0), image, + wxT("invalid old image size") ); + + // If the image's new width and height are the same as the original, no + // need to waste time or CPU cycles + if ( old_width == width && old_height == height ) + return *this; + + // Scale the image (...or more appropriately, resample the image) using + // either the high-quality or normal method as specified + if ( quality == wxIMAGE_QUALITY_HIGH ) + { + // We need to check whether we are downsampling or upsampling the image + if ( width < old_width && height < old_height ) + { + // Downsample the image using the box averaging method for best results + image = ResampleBox(width, height); + } + else + { + // For upsampling or other random/wierd image dimensions we'll use + // a bicubic b-spline scaling method + image = ResampleBicubic(width, height); + } + } + else // Default scaling method == simple pixel replication + { + if ( old_width % width == 0 && old_width >= width && + old_height % height == 0 && old_height >= height ) + { + return ShrinkBy( old_width / width , old_height / height ) ; + } + image.Create( width, height, false ); + + unsigned char *data = image.GetData(); + + wxCHECK_MSG( data, image, wxT("unable to create image") ); + + unsigned char *source_data = M_IMGDATA->m_data; + unsigned char *target_data = data; + unsigned char *source_alpha = 0 ; + unsigned char *target_alpha = 0 ; + + if ( !M_IMGDATA->m_hasMask ) + { + source_alpha = M_IMGDATA->m_alpha ; + if ( source_alpha ) + { + image.SetAlpha() ; + target_alpha = image.GetAlpha() ; + } + } + + long x_delta = (old_width<<16) / width; + long y_delta = (old_height<<16) / height; + + unsigned char* dest_pixel = target_data; + + long y = 0; + for ( long j = 0; j < height; j++ ) + { + unsigned char* src_line = &source_data[(y>>16)*old_width*3]; + unsigned char* src_alpha_line = source_alpha ? &source_alpha[(y>>16)*old_width] : 0 ; + + long x = 0; + for ( long i = 0; i < width; i++ ) + { + unsigned char* src_pixel = &src_line[(x>>16)*3]; + unsigned char* src_alpha_pixel = source_alpha ? &src_alpha_line[(x>>16)] : 0 ; + dest_pixel[0] = src_pixel[0]; + dest_pixel[1] = src_pixel[1]; + dest_pixel[2] = src_pixel[2]; + dest_pixel += 3; + if ( source_alpha ) + *(target_alpha++) = *src_alpha_pixel ; + x += x_delta; + } + + y += y_delta; + } + } + + // If the original image has a mask, apply the mask to the new image + if (M_IMGDATA->m_hasMask) + { + image.SetMaskColour( M_IMGDATA->m_maskRed, + M_IMGDATA->m_maskGreen, + M_IMGDATA->m_maskBlue ); + } + + // In case this is a cursor, make sure the hotspot is scaled accordingly: + if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) ) + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X, + (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X)*width)/old_width); + if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) ) + image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y, + (GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y)*height)/old_height); + + return image; +} + +wxImage wxImage::ResampleBox(int width, int height) const +{ + // This function implements a simple pre-blur/box averaging method for + // downsampling that gives reasonably smooth results To scale the image + // down we will need to gather a grid of pixels of the size of the scale + // factor in each direction and then do an averaging of the pixels. + + wxImage ret_image(width, height, false); + + const double scale_factor_x = double(M_IMGDATA->m_width) / width; + const double scale_factor_y = double(M_IMGDATA->m_height) / height; + + const int scale_factor_x_2 = (int)(scale_factor_x / 2); + const int scale_factor_y_2 = (int)(scale_factor_y / 2); + + unsigned char* src_data = M_IMGDATA->m_data; + unsigned char* src_alpha = M_IMGDATA->m_alpha; + unsigned char* dst_data = ret_image.GetData(); + unsigned char* dst_alpha = NULL; + + if ( src_alpha ) + { + ret_image.SetAlpha(); + dst_alpha = ret_image.GetAlpha(); + } + + int averaged_pixels, src_pixel_index; + double sum_r, sum_g, sum_b, sum_a; + + for ( int y = 0; y < height; y++ ) // Destination image - Y direction + { + // Source pixel in the Y direction + int src_y = (int)(y * scale_factor_y); + + for ( int x = 0; x < width; x++ ) // Destination image - X direction + { + // Source pixel in the X direction + int src_x = (int)(x * scale_factor_x); + + // Box of pixels to average + averaged_pixels = 0; + sum_r = sum_g = sum_b = sum_a = 0.0; + + for ( int j = int(src_y - scale_factor_y/2.0 + 1); + j <= int(src_y + scale_factor_y_2); + j++ ) + { + // We don't care to average pixels that don't exist (edges) + if ( j < 0 || j > M_IMGDATA->m_height - 1 ) + continue; + + for ( int i = int(src_x - scale_factor_x/2.0 + 1); + i <= src_x + scale_factor_x_2; + i++ ) + { + // Don't average edge pixels + if ( i < 0 || i > M_IMGDATA->m_width - 1 ) + continue; + + // Calculate the actual index in our source pixels + src_pixel_index = j * M_IMGDATA->m_width + i; + + sum_r += src_data[src_pixel_index * 3 + 0]; + sum_g += src_data[src_pixel_index * 3 + 1]; + sum_b += src_data[src_pixel_index * 3 + 2]; + if ( src_alpha ) + sum_a += src_alpha[src_pixel_index]; + + averaged_pixels++; + } + } + + // Calculate the average from the sum and number of averaged pixels + dst_data[0] = (unsigned char)(sum_r / averaged_pixels); + dst_data[1] = (unsigned char)(sum_g / averaged_pixels); + dst_data[2] = (unsigned char)(sum_b / averaged_pixels); + dst_data += 3; + if ( src_alpha ) + *dst_alpha++ = (unsigned char)(sum_a / averaged_pixels); + } + } + + return ret_image; +} + +// The following two local functions are for the B-spline weighting of the +// bicubic sampling algorithm +static inline double spline_cube(double value) +{ + return value <= 0.0 ? 0.0 : value * value * value; +} + +static inline double spline_weight(double value) +{ + return (spline_cube(value + 2) - + 4 * spline_cube(value + 1) + + 6 * spline_cube(value) - + 4 * spline_cube(value - 1)) / 6; +} + +// This is the bicubic resampling algorithm +wxImage wxImage::ResampleBicubic(int width, int height) const +{ + // This function implements a Bicubic B-Spline algorithm for resampling. + // This method is certainly a little slower than wxImage's default pixel + // replication method, however for most reasonably sized images not being + // upsampled too much on a fairly average CPU this difference is hardly + // noticeable and the results are far more pleasing to look at. + // + // This particular bicubic algorithm does pixel weighting according to a + // B-Spline that basically implements a Gaussian bell-like weighting + // kernel. Because of this method the results may appear a bit blurry when + // upsampling by large factors. This is basically because a slight + // gaussian blur is being performed to get the smooth look of the upsampled + // image. + + // Edge pixels: 3-4 possible solutions + // - (Wrap/tile) Wrap the image, take the color value from the opposite + // side of the image. + // - (Mirror) Duplicate edge pixels, so that pixel at coordinate (2, n), + // where n is nonpositive, will have the value of (2, 1). + // - (Ignore) Simply ignore the edge pixels and apply the kernel only to + // pixels which do have all neighbours. + // - (Clamp) Choose the nearest pixel along the border. This takes the + // border pixels and extends them out to infinity. + // + // NOTE: below the y_offset and x_offset variables are being set for edge + // pixels using the "Mirror" method mentioned above + + wxImage ret_image; + + ret_image.Create(width, height, false); + + unsigned char* src_data = M_IMGDATA->m_data; + unsigned char* src_alpha = M_IMGDATA->m_alpha; + unsigned char* dst_data = ret_image.GetData(); + unsigned char* dst_alpha = NULL; + + if ( src_alpha ) + { + ret_image.SetAlpha(); + dst_alpha = ret_image.GetAlpha(); + } + + for ( int dsty = 0; dsty < height; dsty++ ) + { + // We need to calculate the source pixel to interpolate from - Y-axis + double srcpixy = double(dsty * M_IMGDATA->m_height) / height; + double dy = srcpixy - (int)srcpixy; + + for ( int dstx = 0; dstx < width; dstx++ ) + { + // X-axis of pixel to interpolate from + double srcpixx = double(dstx * M_IMGDATA->m_width) / width; + double dx = srcpixx - (int)srcpixx; + + // Sums for each color channel + double sum_r = 0, sum_g = 0, sum_b = 0, sum_a = 0; + + // Here we actually determine the RGBA values for the destination pixel + for ( int k = -1; k <= 2; k++ ) + { + // Y offset + int y_offset = srcpixy + k < 0.0 + ? 0 + : srcpixy + k >= M_IMGDATA->m_height + ? M_IMGDATA->m_height - 1 + : (int)(srcpixy + k); + + // Loop across the X axis + for ( int i = -1; i <= 2; i++ ) + { + // X offset + int x_offset = srcpixx + i < 0.0 + ? 0 + : srcpixx + i >= M_IMGDATA->m_width + ? M_IMGDATA->m_width - 1 + : (int)(srcpixx + i); + + // Calculate the exact position where the source data + // should be pulled from based on the x_offset and y_offset + int src_pixel_index = y_offset*M_IMGDATA->m_width + x_offset; + + // Calculate the weight for the specified pixel according + // to the bicubic b-spline kernel we're using for + // interpolation + double + pixel_weight = spline_weight(i - dx)*spline_weight(k - dy); + + // Create a sum of all velues for each color channel + // adjusted for the pixel's calculated weight + sum_r += src_data[src_pixel_index * 3 + 0] * pixel_weight; + sum_g += src_data[src_pixel_index * 3 + 1] * pixel_weight; + sum_b += src_data[src_pixel_index * 3 + 2] * pixel_weight; + if ( src_alpha ) + sum_a += src_alpha[src_pixel_index] * pixel_weight; + } + } + + // Put the data into the destination image. The summed values are + // of double data type and are rounded here for accuracy + dst_data[0] = (unsigned char)(sum_r + 0.5); + dst_data[1] = (unsigned char)(sum_g + 0.5); + dst_data[2] = (unsigned char)(sum_b + 0.5); + dst_data += 3; + + if ( src_alpha ) + *dst_alpha++ = (unsigned char)sum_a; + } + } + + return ret_image; +} + +// Blur in the horizontal direction +wxImage wxImage::BlurHorizontal(int blurRadius) +{ + wxImage ret_image; + ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); + + unsigned char* src_data = M_IMGDATA->m_data; + unsigned char* dst_data = ret_image.GetData(); + unsigned char* src_alpha = M_IMGDATA->m_alpha; + unsigned char* dst_alpha = NULL; + + // Check for a mask or alpha + if ( M_IMGDATA->m_hasMask ) + { + ret_image.SetMaskColour(M_IMGDATA->m_maskRed, + M_IMGDATA->m_maskGreen, + M_IMGDATA->m_maskBlue); + } + else + { + if ( src_alpha ) + { + ret_image.SetAlpha(); + dst_alpha = ret_image.GetAlpha(); + } + } + + // number of pixels we average over + const int blurArea = blurRadius*2 + 1; + + // Horizontal blurring algorithm - average all pixels in the specified blur + // radius in the X or horizontal direction + for ( int y = 0; y < M_IMGDATA->m_height; y++ ) + { + // Variables used in the blurring algorithm + long sum_r = 0, + sum_g = 0, + sum_b = 0, + sum_a = 0; + + long pixel_idx; + const unsigned char *src; + unsigned char *dst; + + // Calculate the average of all pixels in the blur radius for the first + // pixel of the row + for ( int kernel_x = -blurRadius; kernel_x <= blurRadius; kernel_x++ ) + { + // To deal with the pixels at the start of a row so it's not + // grabbing GOK values from memory at negative indices of the + // image's data or grabbing from the previous row + if ( kernel_x < 0 ) + pixel_idx = y * M_IMGDATA->m_width; + else + pixel_idx = kernel_x + y * M_IMGDATA->m_width; + + src = src_data + pixel_idx*3; + sum_r += src[0]; + sum_g += src[1]; + sum_b += src[2]; + if ( src_alpha ) + sum_a += src_alpha[pixel_idx]; + } + + dst = dst_data + y * M_IMGDATA->m_width*3; + dst[0] = (unsigned char)(sum_r / blurArea); + dst[1] = (unsigned char)(sum_g / blurArea); + dst[2] = (unsigned char)(sum_b / blurArea); + if ( src_alpha ) + dst_alpha[y * M_IMGDATA->m_width] = (unsigned char)(sum_a / blurArea); + + // Now average the values of the rest of the pixels by just moving the + // blur radius box along the row + for ( int x = 1; x < M_IMGDATA->m_width; x++ ) + { + // Take care of edge pixels on the left edge by essentially + // duplicating the edge pixel + if ( x - blurRadius - 1 < 0 ) + pixel_idx = y * M_IMGDATA->m_width; + else + pixel_idx = (x - blurRadius - 1) + y * M_IMGDATA->m_width; + + // Subtract the value of the pixel at the left side of the blur + // radius box + src = src_data + pixel_idx*3; + sum_r -= src[0]; + sum_g -= src[1]; + sum_b -= src[2]; + if ( src_alpha ) + sum_a -= src_alpha[pixel_idx]; + + // Take care of edge pixels on the right edge + if ( x + blurRadius > M_IMGDATA->m_width - 1 ) + pixel_idx = M_IMGDATA->m_width - 1 + y * M_IMGDATA->m_width; + else + pixel_idx = x + blurRadius + y * M_IMGDATA->m_width; + + // Add the value of the pixel being added to the end of our box + src = src_data + pixel_idx*3; + sum_r += src[0]; + sum_g += src[1]; + sum_b += src[2]; + if ( src_alpha ) + sum_a += src_alpha[pixel_idx]; + + // Save off the averaged data + dst = dst_data + x*3 + y*M_IMGDATA->m_width*3; + dst[0] = (unsigned char)(sum_r / blurArea); + dst[1] = (unsigned char)(sum_g / blurArea); + dst[2] = (unsigned char)(sum_b / blurArea); + if ( src_alpha ) + dst_alpha[x + y * M_IMGDATA->m_width] = (unsigned char)(sum_a / blurArea); + } + } + + return ret_image; +} + +// Blur in the vertical direction +wxImage wxImage::BlurVertical(int blurRadius) +{ + wxImage ret_image; + ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); + + unsigned char* src_data = M_IMGDATA->m_data; + unsigned char* dst_data = ret_image.GetData(); + unsigned char* src_alpha = M_IMGDATA->m_alpha; + unsigned char* dst_alpha = NULL; + + // Check for a mask or alpha + if ( M_IMGDATA->m_hasMask ) + { + ret_image.SetMaskColour(M_IMGDATA->m_maskRed, + M_IMGDATA->m_maskGreen, + M_IMGDATA->m_maskBlue); + } + else + { + if ( src_alpha ) + { + ret_image.SetAlpha(); + dst_alpha = ret_image.GetAlpha(); + } + } + + // number of pixels we average over + const int blurArea = blurRadius*2 + 1; + + // Vertical blurring algorithm - same as horizontal but switched the + // opposite direction + for ( int x = 0; x < M_IMGDATA->m_width; x++ ) + { + // Variables used in the blurring algorithm + long sum_r = 0, + sum_g = 0, + sum_b = 0, + sum_a = 0; + + long pixel_idx; + const unsigned char *src; + unsigned char *dst; + + // Calculate the average of all pixels in our blur radius box for the + // first pixel of the column + for ( int kernel_y = -blurRadius; kernel_y <= blurRadius; kernel_y++ ) + { + // To deal with the pixels at the start of a column so it's not + // grabbing GOK values from memory at negative indices of the + // image's data or grabbing from the previous column + if ( kernel_y < 0 ) + pixel_idx = x; + else + pixel_idx = x + kernel_y * M_IMGDATA->m_width; + + src = src_data + pixel_idx*3; + sum_r += src[0]; + sum_g += src[1]; + sum_b += src[2]; + if ( src_alpha ) + sum_a += src_alpha[pixel_idx]; + } + + dst = dst_data + x*3; + dst[0] = (unsigned char)(sum_r / blurArea); + dst[1] = (unsigned char)(sum_g / blurArea); + dst[2] = (unsigned char)(sum_b / blurArea); + if ( src_alpha ) + dst_alpha[x] = (unsigned char)(sum_a / blurArea); + + // Now average the values of the rest of the pixels by just moving the + // box along the column from top to bottom + for ( int y = 1; y < M_IMGDATA->m_height; y++ ) + { + // Take care of pixels that would be beyond the top edge by + // duplicating the top edge pixel for the column + if ( y - blurRadius - 1 < 0 ) + pixel_idx = x; + else + pixel_idx = x + (y - blurRadius - 1) * M_IMGDATA->m_width; + + // Subtract the value of the pixel at the top of our blur radius box + src = src_data + pixel_idx*3; + sum_r -= src[0]; + sum_g -= src[1]; + sum_b -= src[2]; + if ( src_alpha ) + sum_a -= src_alpha[pixel_idx]; + + // Take care of the pixels that would be beyond the bottom edge of + // the image similar to the top edge + if ( y + blurRadius > M_IMGDATA->m_height - 1 ) + pixel_idx = x + (M_IMGDATA->m_height - 1) * M_IMGDATA->m_width; + else + pixel_idx = x + (blurRadius + y) * M_IMGDATA->m_width; + + // Add the value of the pixel being added to the end of our box + src = src_data + pixel_idx*3; + sum_r += src[0]; + sum_g += src[1]; + sum_b += src[2]; + if ( src_alpha ) + sum_a += src_alpha[pixel_idx]; + + // Save off the averaged data + dst = dst_data + (x + y * M_IMGDATA->m_width) * 3; + dst[0] = (unsigned char)(sum_r / blurArea); + dst[1] = (unsigned char)(sum_g / blurArea); + dst[2] = (unsigned char)(sum_b / blurArea); + if ( src_alpha ) + dst_alpha[x + y * M_IMGDATA->m_width] = (unsigned char)(sum_a / blurArea); + } + } + + return ret_image; +} + +// The new blur function +wxImage wxImage::Blur(int blurRadius) +{ + wxImage ret_image; + ret_image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); + + // Blur the image in each direction + ret_image = BlurHorizontal(blurRadius); + ret_image = ret_image.BlurVertical(blurRadius); + + return ret_image; +} + +wxImage wxImage::Rotate90( bool clockwise ) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + image.Create( M_IMGDATA->m_height, M_IMGDATA->m_width, false ); + + unsigned char *data = image.GetData(); + + wxCHECK_MSG( data, image, wxT("unable to create image") ); + + unsigned char *source_data = M_IMGDATA->m_data; + unsigned char *target_data; + unsigned char *alpha_data = 0 ; + unsigned char *source_alpha = 0 ; + unsigned char *target_alpha = 0 ; + + if (M_IMGDATA->m_hasMask) + { + image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); + } + else + { + source_alpha = M_IMGDATA->m_alpha ; + if ( source_alpha ) + { + image.SetAlpha() ; + alpha_data = image.GetAlpha() ; + } + } + + long height = M_IMGDATA->m_height; + long width = M_IMGDATA->m_width; + + for (long j = 0; j < height; j++) + { + for (long i = 0; i < width; i++) + { + if (clockwise) + { + target_data = data + (((i+1)*height) - j - 1)*3; + if(source_alpha) + target_alpha = alpha_data + (((i+1)*height) - j - 1); + } + else + { + target_data = data + ((height*(width-1)) + j - (i*height))*3; + if(source_alpha) + target_alpha = alpha_data + ((height*(width-1)) + j - (i*height)); + } + memcpy( target_data, source_data, 3 ); + source_data += 3; + + if(source_alpha) + { + memcpy( target_alpha, source_alpha, 1 ); + source_alpha += 1; + } + } + } + + return image; +} + +wxImage wxImage::Mirror( bool horizontally ) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height, false ); + + unsigned char *data = image.GetData(); + unsigned char *alpha = NULL; + + wxCHECK_MSG( data, image, wxT("unable to create image") ); + + if (M_IMGDATA->m_alpha != NULL) { + image.SetAlpha(); + alpha = image.GetAlpha(); + wxCHECK_MSG( alpha, image, wxT("unable to create alpha channel") ); + } + + if (M_IMGDATA->m_hasMask) + image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); + + long height = M_IMGDATA->m_height; + long width = M_IMGDATA->m_width; + + unsigned char *source_data = M_IMGDATA->m_data; + unsigned char *target_data; + + if (horizontally) + { + for (long j = 0; j < height; j++) + { + data += width*3; + target_data = data-3; + for (long i = 0; i < width; i++) + { + memcpy( target_data, source_data, 3 ); + source_data += 3; + target_data -= 3; + } + } + + if (alpha != NULL) + { + // src_alpha starts at the first pixel and increases by 1 after each step + // (a step here is the copy of the alpha value of one pixel) + const unsigned char *src_alpha = M_IMGDATA->m_alpha; + // dest_alpha starts just beyond the first line, decreases before each step, + // and after each line is finished, increases by 2 widths (skipping the line + // just copied and the line that will be copied next) + unsigned char *dest_alpha = alpha + width; + + for (long jj = 0; jj < height; ++jj) + { + for (long i = 0; i < width; ++i) { + *(--dest_alpha) = *(src_alpha++); // copy one pixel + } + dest_alpha += 2 * width; // advance beyond the end of the next line + } + } + } + else + { + for (long i = 0; i < height; i++) + { + target_data = data + 3*width*(height-1-i); + memcpy( target_data, source_data, (size_t)3*width ); + source_data += 3*width; + } + + if (alpha != NULL) + { + // src_alpha starts at the first pixel and increases by 1 width after each step + // (a step here is the copy of the alpha channel of an entire line) + const unsigned char *src_alpha = M_IMGDATA->m_alpha; + // dest_alpha starts just beyond the last line (beyond the whole image) + // and decreases by 1 width before each step + unsigned char *dest_alpha = alpha + width * height; + + for (long jj = 0; jj < height; ++jj) + { + dest_alpha -= width; + memcpy( dest_alpha, src_alpha, (size_t)width ); + src_alpha += width; + } + } + } + + return image; +} + +wxImage wxImage::GetSubImage( const wxRect &rect ) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + wxCHECK_MSG( (rect.GetLeft()>=0) && (rect.GetTop()>=0) && + (rect.GetRight()<=GetWidth()) && (rect.GetBottom()<=GetHeight()), + image, wxT("invalid subimage size") ); + + const int subwidth = rect.GetWidth(); + const int subheight = rect.GetHeight(); + + image.Create( subwidth, subheight, false ); + + const unsigned char *src_data = GetData(); + const unsigned char *src_alpha = M_IMGDATA->m_alpha; + unsigned char *subdata = image.GetData(); + unsigned char *subalpha = NULL; + + wxCHECK_MSG( subdata, image, wxT("unable to create image") ); + + if (src_alpha != NULL) { + image.SetAlpha(); + subalpha = image.GetAlpha(); + wxCHECK_MSG( subalpha, image, wxT("unable to create alpha channel")); + } + + if (M_IMGDATA->m_hasMask) + image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue ); + + const int width = GetWidth(); + const int pixsoff = rect.GetLeft() + width * rect.GetTop(); + + src_data += 3 * pixsoff; + src_alpha += pixsoff; // won't be used if was NULL, so this is ok + + for (long j = 0; j < subheight; ++j) + { + memcpy( subdata, src_data, 3 * subwidth ); + subdata += 3 * subwidth; + src_data += 3 * width; + if (subalpha != NULL) { + memcpy( subalpha, src_alpha, subwidth ); + subalpha += subwidth; + src_alpha += width; + } + } + + return image; +} + +wxImage wxImage::Size( const wxSize& size, const wxPoint& pos, + int r_, int g_, int b_ ) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + wxCHECK_MSG( (size.GetWidth() > 0) && (size.GetHeight() > 0), image, wxT("invalid size") ); + + int width = GetWidth(), height = GetHeight(); + image.Create(size.GetWidth(), size.GetHeight(), false); + + unsigned char r = (unsigned char)r_; + unsigned char g = (unsigned char)g_; + unsigned char b = (unsigned char)b_; + if ((r_ == -1) && (g_ == -1) && (b_ == -1)) + { + GetOrFindMaskColour( &r, &g, &b ); + image.SetMaskColour(r, g, b); + } + + image.SetRGB(wxRect(), r, g, b); + + wxRect subRect(pos.x, pos.y, width, height); + wxRect finalRect(0, 0, size.GetWidth(), size.GetHeight()); + if (pos.x < 0) + finalRect.width -= pos.x; + if (pos.y < 0) + finalRect.height -= pos.y; + + subRect.Intersect(finalRect); + + if (!subRect.IsEmpty()) + { + if ((subRect.GetWidth() == width) && (subRect.GetHeight() == height)) + image.Paste(*this, pos.x, pos.y); + else + image.Paste(GetSubImage(subRect), pos.x, pos.y); + } + + return image; +} + +void wxImage::Paste( const wxImage &image, int x, int y ) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + wxCHECK_RET( image.Ok(), wxT("invalid image") ); + + AllocExclusive(); + + int xx = 0; + int yy = 0; + int width = image.GetWidth(); + int height = image.GetHeight(); + + if (x < 0) + { + xx = -x; + width += x; + } + if (y < 0) + { + yy = -y; + height += y; + } + + if ((x+xx)+width > M_IMGDATA->m_width) + width = M_IMGDATA->m_width - (x+xx); + if ((y+yy)+height > M_IMGDATA->m_height) + height = M_IMGDATA->m_height - (y+yy); + + if (width < 1) return; + if (height < 1) return; + + if ((!HasMask() && !image.HasMask()) || + (HasMask() && !image.HasMask()) || + ((HasMask() && image.HasMask() && + (GetMaskRed()==image.GetMaskRed()) && + (GetMaskGreen()==image.GetMaskGreen()) && + (GetMaskBlue()==image.GetMaskBlue())))) + { + unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth(); + int source_step = image.GetWidth()*3; + + unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width; + int target_step = M_IMGDATA->m_width*3; + for (int j = 0; j < height; j++) + { + memcpy( target_data, source_data, width*3 ); + source_data += source_step; + target_data += target_step; + } + } + + // Copy over the alpha channel from the original image + if ( image.HasAlpha() ) + { + if ( !HasAlpha() ) + InitAlpha(); + + unsigned char* source_data = image.GetAlpha() + xx + yy*image.GetWidth(); + int source_step = image.GetWidth(); + + unsigned char* target_data = GetAlpha() + (x+xx) + (y+yy)*M_IMGDATA->m_width; + int target_step = M_IMGDATA->m_width; + + for (int j = 0; j < height; j++, + source_data += source_step, + target_data += target_step) + { + memcpy( target_data, source_data, width ); + } + } + + if (!HasMask() && image.HasMask()) + { + unsigned char r = image.GetMaskRed(); + unsigned char g = image.GetMaskGreen(); + unsigned char b = image.GetMaskBlue(); + + unsigned char* source_data = image.GetData() + xx*3 + yy*3*image.GetWidth(); + int source_step = image.GetWidth()*3; + + unsigned char* target_data = GetData() + (x+xx)*3 + (y+yy)*3*M_IMGDATA->m_width; + int target_step = M_IMGDATA->m_width*3; + + for (int j = 0; j < height; j++) + { + for (int i = 0; i < width*3; i+=3) + { + if ((source_data[i] != r) || + (source_data[i+1] != g) || + (source_data[i+2] != b)) + { + memcpy( target_data+i, source_data+i, 3 ); + } + } + source_data += source_step; + target_data += target_step; + } + } +} + +void wxImage::Replace( unsigned char r1, unsigned char g1, unsigned char b1, + unsigned char r2, unsigned char g2, unsigned char b2 ) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + AllocExclusive(); + + unsigned char *data = GetData(); + + const int w = GetWidth(); + const int h = GetHeight(); + + for (int j = 0; j < h; j++) + for (int i = 0; i < w; i++) + { + if ((data[0] == r1) && (data[1] == g1) && (data[2] == b1)) + { + data[0] = r2; + data[1] = g2; + data[2] = b2; + } + data += 3; + } +} + +wxImage wxImage::ConvertToGreyscale( double lr, double lg, double lb ) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + image.Create(M_IMGDATA->m_width, M_IMGDATA->m_height, false); + + unsigned char *dest = image.GetData(); + + wxCHECK_MSG( dest, image, wxT("unable to create image") ); + + unsigned char *src = M_IMGDATA->m_data; + bool hasMask = M_IMGDATA->m_hasMask; + unsigned char maskRed = M_IMGDATA->m_maskRed; + unsigned char maskGreen = M_IMGDATA->m_maskGreen; + unsigned char maskBlue = M_IMGDATA->m_maskBlue; + + if ( hasMask ) + image.SetMaskColour(maskRed, maskGreen, maskBlue); + + const long size = M_IMGDATA->m_width * M_IMGDATA->m_height; + for ( long i = 0; i < size; i++, src += 3, dest += 3 ) + { + // don't modify the mask + if ( hasMask && src[0] == maskRed && src[1] == maskGreen && src[2] == maskBlue ) + { + memcpy(dest, src, 3); + } + else + { + // calculate the luma + double luma = (src[0] * lr + src[1] * lg + src[2] * lb) + 0.5; + dest[0] = dest[1] = dest[2] = wx_static_cast(unsigned char, luma); + } + } + + // copy the alpha channel, if any + if (HasAlpha()) + { + const size_t alphaSize = GetWidth() * GetHeight(); + unsigned char *alpha = (unsigned char*)malloc(alphaSize); + memcpy(alpha, GetAlpha(), alphaSize); + image.InitAlpha(); + image.SetAlpha(alpha); + } + + return image; +} + +wxImage wxImage::ConvertToMono( unsigned char r, unsigned char g, unsigned char b ) const +{ + wxImage image; + + wxCHECK_MSG( Ok(), image, wxT("invalid image") ); + + image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height, false ); + + unsigned char *data = image.GetData(); + + wxCHECK_MSG( data, image, wxT("unable to create image") ); + + if (M_IMGDATA->m_hasMask) + { + if (M_IMGDATA->m_maskRed == r && M_IMGDATA->m_maskGreen == g && + M_IMGDATA->m_maskBlue == b) + image.SetMaskColour( 255, 255, 255 ); + else + image.SetMaskColour( 0, 0, 0 ); + } + + long size = M_IMGDATA->m_height * M_IMGDATA->m_width; + + unsigned char *srcd = M_IMGDATA->m_data; + unsigned char *tard = image.GetData(); + + for ( long i = 0; i < size; i++, srcd += 3, tard += 3 ) + { + if (srcd[0] == r && srcd[1] == g && srcd[2] == b) + tard[0] = tard[1] = tard[2] = 255; + else + tard[0] = tard[1] = tard[2] = 0; + } + + return image; +} + +int wxImage::GetWidth() const +{ + wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); + + return M_IMGDATA->m_width; +} + +int wxImage::GetHeight() const +{ + wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); + + return M_IMGDATA->m_height; +} + +long wxImage::XYToIndex(int x, int y) const +{ + if ( Ok() && + x >= 0 && y >= 0 && + x < M_IMGDATA->m_width && y < M_IMGDATA->m_height ) + { + return y*M_IMGDATA->m_width + x; + } + + return -1; +} + +void wxImage::SetRGB( int x, int y, unsigned char r, unsigned char g, unsigned char b ) +{ + long pos = XYToIndex(x, y); + wxCHECK_RET( pos != -1, wxT("invalid image coordinates") ); + + AllocExclusive(); + + pos *= 3; + + M_IMGDATA->m_data[ pos ] = r; + M_IMGDATA->m_data[ pos+1 ] = g; + M_IMGDATA->m_data[ pos+2 ] = b; +} + +void wxImage::SetRGB( const wxRect& rect_, unsigned char r, unsigned char g, unsigned char b ) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + AllocExclusive(); + + wxRect rect(rect_); + wxRect imageRect(0, 0, GetWidth(), GetHeight()); + if ( rect == wxRect() ) + { + rect = imageRect; + } + else + { + wxCHECK_RET( imageRect.Contains(rect.GetTopLeft()) && + imageRect.Contains(rect.GetBottomRight()), + wxT("invalid bounding rectangle") ); + } + + int x1 = rect.GetLeft(), + y1 = rect.GetTop(), + x2 = rect.GetRight() + 1, + y2 = rect.GetBottom() + 1; + + unsigned char *data wxDUMMY_INITIALIZE(NULL); + int x, y, width = GetWidth(); + for (y = y1; y < y2; y++) + { + data = M_IMGDATA->m_data + (y*width + x1)*3; + for (x = x1; x < x2; x++) + { + *data++ = r; + *data++ = g; + *data++ = b; + } + } +} + +unsigned char wxImage::GetRed( int x, int y ) const +{ + long pos = XYToIndex(x, y); + wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); + + pos *= 3; + + return M_IMGDATA->m_data[pos]; +} + +unsigned char wxImage::GetGreen( int x, int y ) const +{ + long pos = XYToIndex(x, y); + wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); + + pos *= 3; + + return M_IMGDATA->m_data[pos+1]; +} + +unsigned char wxImage::GetBlue( int x, int y ) const +{ + long pos = XYToIndex(x, y); + wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); + + pos *= 3; + + return M_IMGDATA->m_data[pos+2]; +} + +bool wxImage::IsOk() const +{ + // image of 0 width or height can't be considered ok - at least because it + // causes crashes in ConvertToBitmap() if we don't catch it in time + wxImageRefData *data = M_IMGDATA; + return data && data->m_ok && data->m_width && data->m_height; +} + +unsigned char *wxImage::GetData() const +{ + wxCHECK_MSG( Ok(), (unsigned char *)NULL, wxT("invalid image") ); + + return M_IMGDATA->m_data; +} + +void wxImage::SetData( unsigned char *data, bool static_data ) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + wxImageRefData *newRefData = new wxImageRefData(); + + newRefData->m_width = M_IMGDATA->m_width; + newRefData->m_height = M_IMGDATA->m_height; + newRefData->m_data = data; + newRefData->m_ok = true; + newRefData->m_maskRed = M_IMGDATA->m_maskRed; + newRefData->m_maskGreen = M_IMGDATA->m_maskGreen; + newRefData->m_maskBlue = M_IMGDATA->m_maskBlue; + newRefData->m_hasMask = M_IMGDATA->m_hasMask; + newRefData->m_static = static_data; + + UnRef(); + + m_refData = newRefData; +} + +void wxImage::SetData( unsigned char *data, int new_width, int new_height, bool static_data ) +{ + wxImageRefData *newRefData = new wxImageRefData(); + + if (m_refData) + { + newRefData->m_width = new_width; + newRefData->m_height = new_height; + newRefData->m_data = data; + newRefData->m_ok = true; + newRefData->m_maskRed = M_IMGDATA->m_maskRed; + newRefData->m_maskGreen = M_IMGDATA->m_maskGreen; + newRefData->m_maskBlue = M_IMGDATA->m_maskBlue; + newRefData->m_hasMask = M_IMGDATA->m_hasMask; + } + else + { + newRefData->m_width = new_width; + newRefData->m_height = new_height; + newRefData->m_data = data; + newRefData->m_ok = true; + } + newRefData->m_static = static_data; + + UnRef(); + + m_refData = newRefData; +} + +// ---------------------------------------------------------------------------- +// alpha channel support +// ---------------------------------------------------------------------------- + +void wxImage::SetAlpha(int x, int y, unsigned char alpha) +{ + wxCHECK_RET( HasAlpha(), wxT("no alpha channel") ); + + long pos = XYToIndex(x, y); + wxCHECK_RET( pos != -1, wxT("invalid image coordinates") ); + + AllocExclusive(); + + M_IMGDATA->m_alpha[pos] = alpha; +} + +unsigned char wxImage::GetAlpha(int x, int y) const +{ + wxCHECK_MSG( HasAlpha(), 0, wxT("no alpha channel") ); + + long pos = XYToIndex(x, y); + wxCHECK_MSG( pos != -1, 0, wxT("invalid image coordinates") ); + + return M_IMGDATA->m_alpha[pos]; +} + +bool +wxImage::ConvertColourToAlpha(unsigned char r, unsigned char g, unsigned char b) +{ + SetAlpha(NULL); + + const int w = M_IMGDATA->m_width; + const int h = M_IMGDATA->m_height; + + unsigned char *alpha = GetAlpha(); + unsigned char *data = GetData(); + + for ( int y = 0; y < h; y++ ) + { + for ( int x = 0; x < w; x++ ) + { + *alpha++ = *data; + *data++ = r; + *data++ = g; + *data++ = b; + } + } + + return true; +} + +void wxImage::SetAlpha( unsigned char *alpha, bool static_data ) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + AllocExclusive(); + + if ( !alpha ) + { + alpha = (unsigned char *)malloc(M_IMGDATA->m_width*M_IMGDATA->m_height); + } + + if( !M_IMGDATA->m_staticAlpha ) + free(M_IMGDATA->m_alpha); + + M_IMGDATA->m_alpha = alpha; + M_IMGDATA->m_staticAlpha = static_data; +} + +unsigned char *wxImage::GetAlpha() const +{ + wxCHECK_MSG( Ok(), (unsigned char *)NULL, wxT("invalid image") ); + + return M_IMGDATA->m_alpha; +} + +void wxImage::InitAlpha() +{ + wxCHECK_RET( !HasAlpha(), wxT("image already has an alpha channel") ); + + // initialize memory for alpha channel + SetAlpha(); + + unsigned char *alpha = M_IMGDATA->m_alpha; + const size_t lenAlpha = M_IMGDATA->m_width * M_IMGDATA->m_height; + + if ( HasMask() ) + { + // use the mask to initialize the alpha channel. + const unsigned char * const alphaEnd = alpha + lenAlpha; + + const unsigned char mr = M_IMGDATA->m_maskRed; + const unsigned char mg = M_IMGDATA->m_maskGreen; + const unsigned char mb = M_IMGDATA->m_maskBlue; + for ( unsigned char *src = M_IMGDATA->m_data; + alpha < alphaEnd; + src += 3, alpha++ ) + { + *alpha = (src[0] == mr && src[1] == mg && src[2] == mb) + ? wxIMAGE_ALPHA_TRANSPARENT + : wxIMAGE_ALPHA_OPAQUE; + } + + M_IMGDATA->m_hasMask = false; + } + else // no mask + { + // make the image fully opaque + memset(alpha, wxIMAGE_ALPHA_OPAQUE, lenAlpha); + } +} + +// ---------------------------------------------------------------------------- +// mask support +// ---------------------------------------------------------------------------- + +void wxImage::SetMaskColour( unsigned char r, unsigned char g, unsigned char b ) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + AllocExclusive(); + + M_IMGDATA->m_maskRed = r; + M_IMGDATA->m_maskGreen = g; + M_IMGDATA->m_maskBlue = b; + M_IMGDATA->m_hasMask = true; +} + +bool wxImage::GetOrFindMaskColour( unsigned char *r, unsigned char *g, unsigned char *b ) const +{ + wxCHECK_MSG( Ok(), false, wxT("invalid image") ); + + if (M_IMGDATA->m_hasMask) + { + if (r) *r = M_IMGDATA->m_maskRed; + if (g) *g = M_IMGDATA->m_maskGreen; + if (b) *b = M_IMGDATA->m_maskBlue; + return true; + } + else + { + FindFirstUnusedColour(r, g, b); + return false; + } +} + +unsigned char wxImage::GetMaskRed() const +{ + wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); + + return M_IMGDATA->m_maskRed; +} + +unsigned char wxImage::GetMaskGreen() const +{ + wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); + + return M_IMGDATA->m_maskGreen; +} + +unsigned char wxImage::GetMaskBlue() const +{ + wxCHECK_MSG( Ok(), 0, wxT("invalid image") ); + + return M_IMGDATA->m_maskBlue; +} + +void wxImage::SetMask( bool mask ) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + AllocExclusive(); + + M_IMGDATA->m_hasMask = mask; +} + +bool wxImage::HasMask() const +{ + wxCHECK_MSG( Ok(), false, wxT("invalid image") ); + + return M_IMGDATA->m_hasMask; +} + +bool wxImage::IsTransparent(int x, int y, unsigned char threshold) const +{ + long pos = XYToIndex(x, y); + wxCHECK_MSG( pos != -1, false, wxT("invalid image coordinates") ); + + // check mask + if ( M_IMGDATA->m_hasMask ) + { + const unsigned char *p = M_IMGDATA->m_data + 3*pos; + if ( p[0] == M_IMGDATA->m_maskRed && + p[1] == M_IMGDATA->m_maskGreen && + p[2] == M_IMGDATA->m_maskBlue ) + { + return true; + } + } + + // then check alpha + if ( M_IMGDATA->m_alpha ) + { + if ( M_IMGDATA->m_alpha[pos] < threshold ) + { + // transparent enough + return true; + } + } + + // not transparent + return false; +} + +bool wxImage::SetMaskFromImage(const wxImage& mask, + unsigned char mr, unsigned char mg, unsigned char mb) +{ + // check that the images are the same size + if ( (M_IMGDATA->m_height != mask.GetHeight() ) || (M_IMGDATA->m_width != mask.GetWidth () ) ) + { + wxLogError( _("Image and mask have different sizes.") ); + return false; + } + + // find unused colour + unsigned char r,g,b ; + if (!FindFirstUnusedColour(&r, &g, &b)) + { + wxLogError( _("No unused colour in image being masked.") ); + return false ; + } + + AllocExclusive(); + + unsigned char *imgdata = GetData(); + unsigned char *maskdata = mask.GetData(); + + const int w = GetWidth(); + const int h = GetHeight(); + + for (int j = 0; j < h; j++) + { + for (int i = 0; i < w; i++) + { + if ((maskdata[0] == mr) && (maskdata[1] == mg) && (maskdata[2] == mb)) + { + imgdata[0] = r; + imgdata[1] = g; + imgdata[2] = b; + } + imgdata += 3; + maskdata += 3; + } + } + + SetMaskColour(r, g, b); + SetMask(true); + + return true; +} + +bool wxImage::ConvertAlphaToMask(unsigned char threshold) +{ + if (!HasAlpha()) + return true; + + unsigned char mr, mg, mb; + if (!FindFirstUnusedColour(&mr, &mg, &mb)) + { + wxLogError( _("No unused colour in image being masked.") ); + return false; + } + + AllocExclusive(); + + SetMask(true); + SetMaskColour(mr, mg, mb); + + unsigned char *imgdata = GetData(); + unsigned char *alphadata = GetAlpha(); + + int w = GetWidth(); + int h = GetHeight(); + + for (int y = 0; y < h; y++) + { + for (int x = 0; x < w; x++, imgdata += 3, alphadata++) + { + if (*alphadata < threshold) + { + imgdata[0] = mr; + imgdata[1] = mg; + imgdata[2] = mb; + } + } + } + + if( !M_IMGDATA->m_staticAlpha ) + free(M_IMGDATA->m_alpha); + + M_IMGDATA->m_alpha = NULL; + M_IMGDATA->m_staticAlpha = false; + + return true; +} + +// ---------------------------------------------------------------------------- +// Palette functions +// ---------------------------------------------------------------------------- + +#if wxUSE_PALETTE + +bool wxImage::HasPalette() const +{ + if (!Ok()) + return false; + + return M_IMGDATA->m_palette.Ok(); +} + +const wxPalette& wxImage::GetPalette() const +{ + wxCHECK_MSG( Ok(), wxNullPalette, wxT("invalid image") ); + + return M_IMGDATA->m_palette; +} + +void wxImage::SetPalette(const wxPalette& palette) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + AllocExclusive(); + + M_IMGDATA->m_palette = palette; +} + +#endif // wxUSE_PALETTE + +// ---------------------------------------------------------------------------- +// Option functions (arbitrary name/value mapping) +// ---------------------------------------------------------------------------- + +void wxImage::SetOption(const wxString& name, const wxString& value) +{ + wxCHECK_RET( Ok(), wxT("invalid image") ); + + AllocExclusive(); + + int idx = M_IMGDATA->m_optionNames.Index(name, false); + if (idx == wxNOT_FOUND) + { + M_IMGDATA->m_optionNames.Add(name); + M_IMGDATA->m_optionValues.Add(value); + } + else + { + M_IMGDATA->m_optionNames[idx] = name; + M_IMGDATA->m_optionValues[idx] = value; + } +} + +void wxImage::SetOption(const wxString& name, int value) +{ + wxString valStr; + valStr.Printf(wxT("%d"), value); + SetOption(name, valStr); +} + +wxString wxImage::GetOption(const wxString& name) const +{ + wxCHECK_MSG( Ok(), wxEmptyString, wxT("invalid image") ); + + int idx = M_IMGDATA->m_optionNames.Index(name, false); + if (idx == wxNOT_FOUND) + return wxEmptyString; + else + return M_IMGDATA->m_optionValues[idx]; +} + +int wxImage::GetOptionInt(const wxString& name) const +{ + return wxAtoi(GetOption(name)); +} + +bool wxImage::HasOption(const wxString& name) const +{ + wxCHECK_MSG( Ok(), false, wxT("invalid image") ); + + return (M_IMGDATA->m_optionNames.Index(name, false) != wxNOT_FOUND); +} + +// ---------------------------------------------------------------------------- +// image I/O +// ---------------------------------------------------------------------------- + +bool wxImage::LoadFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), + long WXUNUSED_UNLESS_STREAMS(type), + int WXUNUSED_UNLESS_STREAMS(index) ) +{ +#if HAS_FILE_STREAMS + if (wxFileExists(filename)) + { + wxImageFileInputStream stream(filename); + wxBufferedInputStream bstream( stream ); + return LoadFile(bstream, type, index); + } + else + { + wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); + + return false; + } +#else // !HAS_FILE_STREAMS + return false; +#endif // HAS_FILE_STREAMS +} + +bool wxImage::LoadFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), + const wxString& WXUNUSED_UNLESS_STREAMS(mimetype), + int WXUNUSED_UNLESS_STREAMS(index) ) +{ +#if HAS_FILE_STREAMS + if (wxFileExists(filename)) + { + wxImageFileInputStream stream(filename); + wxBufferedInputStream bstream( stream ); + return LoadFile(bstream, mimetype, index); + } + else + { + wxLogError( _("Can't load image from file '%s': file does not exist."), filename.c_str() ); + + return false; + } +#else // !HAS_FILE_STREAMS + return false; +#endif // HAS_FILE_STREAMS +} + + + +bool wxImage::SaveFile( const wxString& filename ) const +{ + wxString ext = filename.AfterLast('.').Lower(); + + wxImageHandler * pHandler = FindHandler(ext, -1); + if (pHandler) + { + return SaveFile(filename, pHandler->GetType()); + } + + wxLogError(_("Can't save image to file '%s': unknown extension."), filename.c_str()); + + return false; +} + +bool wxImage::SaveFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), + int WXUNUSED_UNLESS_STREAMS(type) ) const +{ +#if HAS_FILE_STREAMS + wxCHECK_MSG( Ok(), false, wxT("invalid image") ); + + ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename); + + wxImageFileOutputStream stream(filename); + + if ( stream.IsOk() ) + { + wxBufferedOutputStream bstream( stream ); + return SaveFile(bstream, type); + } +#endif // HAS_FILE_STREAMS + + return false; +} + +bool wxImage::SaveFile( const wxString& WXUNUSED_UNLESS_STREAMS(filename), + const wxString& WXUNUSED_UNLESS_STREAMS(mimetype) ) const +{ +#if HAS_FILE_STREAMS + wxCHECK_MSG( Ok(), false, wxT("invalid image") ); + + ((wxImage*)this)->SetOption(wxIMAGE_OPTION_FILENAME, filename); + + wxImageFileOutputStream stream(filename); + + if ( stream.IsOk() ) + { + wxBufferedOutputStream bstream( stream ); + return SaveFile(bstream, mimetype); + } +#endif // HAS_FILE_STREAMS + + return false; +} + +bool wxImage::CanRead( const wxString& WXUNUSED_UNLESS_STREAMS(name) ) +{ +#if HAS_FILE_STREAMS + wxImageFileInputStream stream(name); + return CanRead(stream); +#else + return false; +#endif +} + +int wxImage::GetImageCount( const wxString& WXUNUSED_UNLESS_STREAMS(name), + long WXUNUSED_UNLESS_STREAMS(type) ) +{ +#if HAS_FILE_STREAMS + wxImageFileInputStream stream(name); + if (stream.Ok()) + return GetImageCount(stream, type); +#endif + + return 0; +} + +#if wxUSE_STREAMS + +bool wxImage::CanRead( wxInputStream &stream ) +{ + const wxList& list = GetHandlers(); + + for ( wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() ) + { + wxImageHandler *handler=(wxImageHandler*)node->GetData(); + if (handler->CanRead( stream )) + return true; + } + + return false; +} + +int wxImage::GetImageCount( wxInputStream &stream, long type ) +{ + wxImageHandler *handler; + + if ( type == wxBITMAP_TYPE_ANY ) + { + wxList &list=GetHandlers(); + + for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext()) + { + handler=(wxImageHandler*)node->GetData(); + if ( handler->CanRead(stream) ) + return handler->GetImageCount(stream); + + } + + wxLogWarning(_("No handler found for image type.")); + return 0; + } + + handler = FindHandler(type); + + if ( !handler ) + { + wxLogWarning(_("No image handler for type %ld defined."), type); + return false; + } + + if ( handler->CanRead(stream) ) + { + return handler->GetImageCount(stream); + } + else + { + wxLogError(_("Image file is not of type %ld."), type); + return 0; + } +} + +bool wxImage::LoadFile( wxInputStream& stream, long type, int index ) +{ + UnRef(); + + m_refData = new wxImageRefData; + + wxImageHandler *handler; + + if ( type == wxBITMAP_TYPE_ANY ) + { + wxList &list=GetHandlers(); + + for ( wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext() ) + { + handler=(wxImageHandler*)node->GetData(); + if ( handler->CanRead(stream) ) + return handler->LoadFile(this, stream, true/*verbose*/, index); + + } + + wxLogWarning( _("No handler found for image type.") ); + return false; + } + + handler = FindHandler(type); + + if (handler == 0) + { + wxLogWarning( _("No image handler for type %ld defined."), type ); + + return false; + } + + if (stream.IsSeekable() && !handler->CanRead(stream)) + { + wxLogError(_("Image file is not of type %ld."), type); + return false; + } + else + return handler->LoadFile(this, stream, true/*verbose*/, index); +} + +bool wxImage::LoadFile( wxInputStream& stream, const wxString& mimetype, int index ) +{ + UnRef(); + + m_refData = new wxImageRefData; + + wxImageHandler *handler = FindHandlerMime(mimetype); + + if (handler == 0) + { + wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() ); + + return false; + } + + if (stream.IsSeekable() && !handler->CanRead(stream)) + { + wxLogError(_("Image file is not of type %s."), (const wxChar*) mimetype); + return false; + } + else + return handler->LoadFile( this, stream, true/*verbose*/, index ); +} + +bool wxImage::SaveFile( wxOutputStream& stream, int type ) const +{ + wxCHECK_MSG( Ok(), false, wxT("invalid image") ); + + wxImageHandler *handler = FindHandler(type); + if ( !handler ) + { + wxLogWarning( _("No image handler for type %d defined."), type ); + + return false; + } + + return handler->SaveFile( (wxImage*)this, stream ); +} + +bool wxImage::SaveFile( wxOutputStream& stream, const wxString& mimetype ) const +{ + wxCHECK_MSG( Ok(), false, wxT("invalid image") ); + + wxImageHandler *handler = FindHandlerMime(mimetype); + if ( !handler ) + { + wxLogWarning( _("No image handler for type %s defined."), mimetype.GetData() ); + + return false; + } + + return handler->SaveFile( (wxImage*)this, stream ); +} +#endif // wxUSE_STREAMS + +// ---------------------------------------------------------------------------- +// image I/O handlers +// ---------------------------------------------------------------------------- + +void wxImage::AddHandler( wxImageHandler *handler ) +{ + // Check for an existing handler of the type being added. + if (FindHandler( handler->GetType() ) == 0) + { + sm_handlers.Append( handler ); + } + else + { + // This is not documented behaviour, merely the simplest 'fix' + // for preventing duplicate additions. If someone ever has + // a good reason to add and remove duplicate handlers (and they + // may) we should probably refcount the duplicates. + // also an issue in InsertHandler below. + + wxLogDebug( _T("Adding duplicate image handler for '%s'"), + handler->GetName().c_str() ); + delete handler; + } +} + +void wxImage::InsertHandler( wxImageHandler *handler ) +{ + // Check for an existing handler of the type being added. + if (FindHandler( handler->GetType() ) == 0) + { + sm_handlers.Insert( handler ); + } + else + { + // see AddHandler for additional comments. + wxLogDebug( _T("Inserting duplicate image handler for '%s'"), + handler->GetName().c_str() ); + delete handler; + } +} + +bool wxImage::RemoveHandler( const wxString& name ) +{ + wxImageHandler *handler = FindHandler(name); + if (handler) + { + sm_handlers.DeleteObject(handler); + delete handler; + return true; + } + else + return false; +} + +wxImageHandler *wxImage::FindHandler( const wxString& name ) +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while (node) + { + wxImageHandler *handler = (wxImageHandler*)node->GetData(); + if (handler->GetName().Cmp(name) == 0) return handler; + + node = node->GetNext(); + } + return 0; +} + +wxImageHandler *wxImage::FindHandler( const wxString& extension, long bitmapType ) +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while (node) + { + wxImageHandler *handler = (wxImageHandler*)node->GetData(); + if ( (handler->GetExtension().Cmp(extension) == 0) && + (bitmapType == -1 || handler->GetType() == bitmapType) ) + return handler; + node = node->GetNext(); + } + return 0; +} + +wxImageHandler *wxImage::FindHandler( long bitmapType ) +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while (node) + { + wxImageHandler *handler = (wxImageHandler *)node->GetData(); + if (handler->GetType() == bitmapType) return handler; + node = node->GetNext(); + } + return 0; +} + +wxImageHandler *wxImage::FindHandlerMime( const wxString& mimetype ) +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while (node) + { + wxImageHandler *handler = (wxImageHandler *)node->GetData(); + if (handler->GetMimeType().IsSameAs(mimetype, false)) return handler; + node = node->GetNext(); + } + return 0; +} + +void wxImage::InitStandardHandlers() +{ +#if wxUSE_STREAMS + AddHandler(new wxBMPHandler); +#endif // wxUSE_STREAMS +} + +void wxImage::CleanUpHandlers() +{ + wxList::compatibility_iterator node = sm_handlers.GetFirst(); + while (node) + { + wxImageHandler *handler = (wxImageHandler *)node->GetData(); + wxList::compatibility_iterator next = node->GetNext(); + delete handler; + node = next; + } + + sm_handlers.Clear(); +} + +wxString wxImage::GetImageExtWildcard() +{ + wxString fmts; + + wxList& Handlers = wxImage::GetHandlers(); + wxList::compatibility_iterator Node = Handlers.GetFirst(); + while ( Node ) + { + wxImageHandler* Handler = (wxImageHandler*)Node->GetData(); + fmts += wxT("*.") + Handler->GetExtension(); + Node = Node->GetNext(); + if ( Node ) fmts += wxT(";"); + } + + return wxT("(") + fmts + wxT(")|") + fmts; +} + +wxImage::HSVValue wxImage::RGBtoHSV(const RGBValue& rgb) +{ + const double red = rgb.red / 255.0, + green = rgb.green / 255.0, + blue = rgb.blue / 255.0; + + // find the min and max intensity (and remember which one was it for the + // latter) + double minimumRGB = red; + if ( green < minimumRGB ) + minimumRGB = green; + if ( blue < minimumRGB ) + minimumRGB = blue; + + enum { RED, GREEN, BLUE } chMax = RED; + double maximumRGB = red; + if ( green > maximumRGB ) + { + chMax = GREEN; + maximumRGB = green; + } + if ( blue > maximumRGB ) + { + chMax = BLUE; + maximumRGB = blue; + } + + const double value = maximumRGB; + + double hue = 0.0, saturation; + const double deltaRGB = maximumRGB - minimumRGB; + if ( wxIsNullDouble(deltaRGB) ) + { + // Gray has no color + hue = 0.0; + saturation = 0.0; + } + else + { + switch ( chMax ) + { + case RED: + hue = (green - blue) / deltaRGB; + break; + + case GREEN: + hue = 2.0 + (blue - red) / deltaRGB; + break; + + case BLUE: + hue = 4.0 + (red - green) / deltaRGB; + break; + + default: + wxFAIL_MSG(wxT("hue not specified")); + break; + } + + hue /= 6.0; + + if ( hue < 0.0 ) + hue += 1.0; + + saturation = deltaRGB / maximumRGB; + } + + return HSVValue(hue, saturation, value); +} + +wxImage::RGBValue wxImage::HSVtoRGB(const HSVValue& hsv) +{ + double red, green, blue; + + if ( wxIsNullDouble(hsv.saturation) ) + { + // Grey + red = hsv.value; + green = hsv.value; + blue = hsv.value; + } + else // not grey + { + double hue = hsv.hue * 6.0; // sector 0 to 5 + int i = (int)floor(hue); + double f = hue - i; // fractional part of h + double p = hsv.value * (1.0 - hsv.saturation); + + switch (i) + { + case 0: + red = hsv.value; + green = hsv.value * (1.0 - hsv.saturation * (1.0 - f)); + blue = p; + break; + + case 1: + red = hsv.value * (1.0 - hsv.saturation * f); + green = hsv.value; + blue = p; + break; + + case 2: + red = p; + green = hsv.value; + blue = hsv.value * (1.0 - hsv.saturation * (1.0 - f)); + break; + + case 3: + red = p; + green = hsv.value * (1.0 - hsv.saturation * f); + blue = hsv.value; + break; + + case 4: + red = hsv.value * (1.0 - hsv.saturation * (1.0 - f)); + green = p; + blue = hsv.value; + break; + + default: // case 5: + red = hsv.value; + green = p; + blue = hsv.value * (1.0 - hsv.saturation * f); + break; + } + } + + return RGBValue((unsigned char)(red * 255.0), + (unsigned char)(green * 255.0), + (unsigned char)(blue * 255.0)); +} + +/* + * Rotates the hue of each pixel of the image. angle is a double in the range + * -1.0..1.0 where -1.0 is -360 degrees and 1.0 is 360 degrees + */ +void wxImage::RotateHue(double angle) +{ + AllocExclusive(); + + unsigned char *srcBytePtr; + unsigned char *dstBytePtr; + unsigned long count; + wxImage::HSVValue hsv; + wxImage::RGBValue rgb; + + wxASSERT (angle >= -1.0 && angle <= 1.0); + count = M_IMGDATA->m_width * M_IMGDATA->m_height; + if ( count > 0 && !wxIsNullDouble(angle) ) + { + srcBytePtr = M_IMGDATA->m_data; + dstBytePtr = srcBytePtr; + do + { + rgb.red = *srcBytePtr++; + rgb.green = *srcBytePtr++; + rgb.blue = *srcBytePtr++; + hsv = RGBtoHSV(rgb); + + hsv.hue = hsv.hue + angle; + if (hsv.hue > 1.0) + hsv.hue = hsv.hue - 1.0; + else if (hsv.hue < 0.0) + hsv.hue = hsv.hue + 1.0; + + rgb = HSVtoRGB(hsv); + *dstBytePtr++ = rgb.red; + *dstBytePtr++ = rgb.green; + *dstBytePtr++ = rgb.blue; + } while (--count != 0); + } +} + +//----------------------------------------------------------------------------- +// wxImageHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxImageHandler,wxObject) + +#if wxUSE_STREAMS +bool wxImageHandler::LoadFile( wxImage *WXUNUSED(image), wxInputStream& WXUNUSED(stream), bool WXUNUSED(verbose), int WXUNUSED(index) ) +{ + return false; +} + +bool wxImageHandler::SaveFile( wxImage *WXUNUSED(image), wxOutputStream& WXUNUSED(stream), bool WXUNUSED(verbose) ) +{ + return false; +} + +int wxImageHandler::GetImageCount( wxInputStream& WXUNUSED(stream) ) +{ + return 1; +} + +bool wxImageHandler::CanRead( const wxString& name ) +{ + if (wxFileExists(name)) + { + wxImageFileInputStream stream(name); + return CanRead(stream); + } + + wxLogError( _("Can't check image format of file '%s': file does not exist."), name.c_str() ); + + return false; +} + +bool wxImageHandler::CallDoCanRead(wxInputStream& stream) +{ + wxFileOffset posOld = stream.TellI(); + if ( posOld == wxInvalidOffset ) + { + // can't test unseekable stream + return false; + } + + bool ok = DoCanRead(stream); + + // restore the old position to be able to test other formats and so on + if ( stream.SeekI(posOld) == wxInvalidOffset ) + { + wxLogDebug(_T("Failed to rewind the stream in wxImageHandler!")); + + // reading would fail anyhow as we're not at the right position + return false; + } + + return ok; +} + +#endif // wxUSE_STREAMS + +// ---------------------------------------------------------------------------- +// image histogram stuff +// ---------------------------------------------------------------------------- + +bool +wxImageHistogram::FindFirstUnusedColour(unsigned char *r, + unsigned char *g, + unsigned char *b, + unsigned char r2, + unsigned char b2, + unsigned char g2) const +{ + unsigned long key = MakeKey(r2, g2, b2); + + while ( find(key) != end() ) + { + // color already used + r2++; + if ( r2 >= 255 ) + { + r2 = 0; + g2++; + if ( g2 >= 255 ) + { + g2 = 0; + b2++; + if ( b2 >= 255 ) + { + wxLogError(_("No unused colour in image.") ); + return false; + } + } + } + + key = MakeKey(r2, g2, b2); + } + + if ( r ) + *r = r2; + if ( g ) + *g = g2; + if ( b ) + *b = b2; + + return true; +} + +bool +wxImage::FindFirstUnusedColour(unsigned char *r, + unsigned char *g, + unsigned char *b, + unsigned char r2, + unsigned char b2, + unsigned char g2) const +{ + wxImageHistogram histogram; + + ComputeHistogram(histogram); + + return histogram.FindFirstUnusedColour(r, g, b, r2, g2, b2); +} + + + +// GRG, Dic/99 +// Counts and returns the number of different colours. Optionally stops +// when it exceeds 'stopafter' different colours. This is useful, for +// example, to see if the image can be saved as 8-bit (256 colour or +// less, in this case it would be invoked as CountColours(256)). Default +// value for stopafter is -1 (don't care). +// +unsigned long wxImage::CountColours( unsigned long stopafter ) const +{ + wxHashTable h; + wxObject dummy; + unsigned char r, g, b; + unsigned char *p; + unsigned long size, nentries, key; + + p = GetData(); + size = GetWidth() * GetHeight(); + nentries = 0; + + for (unsigned long j = 0; (j < size) && (nentries <= stopafter) ; j++) + { + r = *(p++); + g = *(p++); + b = *(p++); + key = wxImageHistogram::MakeKey(r, g, b); + + if (h.Get(key) == NULL) + { + h.Put(key, &dummy); + nentries++; + } + } + + return nentries; +} + + +unsigned long wxImage::ComputeHistogram( wxImageHistogram &h ) const +{ + unsigned char *p = GetData(); + unsigned long nentries = 0; + + h.clear(); + + const unsigned long size = GetWidth() * GetHeight(); + + unsigned char r, g, b; + for ( unsigned long n = 0; n < size; n++ ) + { + r = *p++; + g = *p++; + b = *p++; + + wxImageHistogramEntry& entry = h[wxImageHistogram::MakeKey(r, g, b)]; + + if ( entry.value++ == 0 ) + entry.index = nentries++; + } + + return nentries; +} + +/* + * Rotation code by Carlos Moreno + */ + +static const double wxROTATE_EPSILON = 1e-10; + +// Auxiliary function to rotate a point (x,y) with respect to point p0 +// make it inline and use a straight return to facilitate optimization +// also, the function receives the sine and cosine of the angle to avoid +// repeating the time-consuming calls to these functions -- sin/cos can +// be computed and stored in the calling function. + +static inline wxRealPoint +wxRotatePoint(const wxRealPoint& p, double cos_angle, double sin_angle, + const wxRealPoint& p0) +{ + return wxRealPoint(p0.x + (p.x - p0.x) * cos_angle - (p.y - p0.y) * sin_angle, + p0.y + (p.y - p0.y) * cos_angle + (p.x - p0.x) * sin_angle); +} + +static inline wxRealPoint +wxRotatePoint(double x, double y, double cos_angle, double sin_angle, + const wxRealPoint & p0) +{ + return wxRotatePoint (wxRealPoint(x,y), cos_angle, sin_angle, p0); +} + +wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool interpolating, wxPoint * offset_after_rotation) const +{ + int i; + angle = -angle; // screen coordinates are a mirror image of "real" coordinates + + bool has_alpha = HasAlpha(); + + const int w = GetWidth(), + h = GetHeight(); + + // Create pointer-based array to accelerate access to wxImage's data + unsigned char ** data = new unsigned char * [h]; + data[0] = GetData(); + for (i = 1; i < h; i++) + data[i] = data[i - 1] + (3 * w); + + // Same for alpha channel + unsigned char ** alpha = NULL; + if (has_alpha) + { + alpha = new unsigned char * [h]; + alpha[0] = GetAlpha(); + for (i = 1; i < h; i++) + alpha[i] = alpha[i - 1] + w; + } + + // precompute coefficients for rotation formula + // (sine and cosine of the angle) + const double cos_angle = cos(angle); + const double sin_angle = sin(angle); + + // Create new Image to store the result + // First, find rectangle that covers the rotated image; to do that, + // rotate the four corners + + const wxRealPoint p0(centre_of_rotation.x, centre_of_rotation.y); + + wxRealPoint p1 = wxRotatePoint (0, 0, cos_angle, sin_angle, p0); + wxRealPoint p2 = wxRotatePoint (0, h, cos_angle, sin_angle, p0); + wxRealPoint p3 = wxRotatePoint (w, 0, cos_angle, sin_angle, p0); + wxRealPoint p4 = wxRotatePoint (w, h, cos_angle, sin_angle, p0); + + int x1a = (int) floor (wxMin (wxMin(p1.x, p2.x), wxMin(p3.x, p4.x))); + int y1a = (int) floor (wxMin (wxMin(p1.y, p2.y), wxMin(p3.y, p4.y))); + int x2a = (int) ceil (wxMax (wxMax(p1.x, p2.x), wxMax(p3.x, p4.x))); + int y2a = (int) ceil (wxMax (wxMax(p1.y, p2.y), wxMax(p3.y, p4.y))); + + // Create rotated image + wxImage rotated (x2a - x1a + 1, y2a - y1a + 1, false); + // With alpha channel + if (has_alpha) + rotated.SetAlpha(); + + if (offset_after_rotation != NULL) + { + *offset_after_rotation = wxPoint (x1a, y1a); + } + + // GRG: The rotated (destination) image is always accessed + // sequentially, so there is no need for a pointer-based + // array here (and in fact it would be slower). + // + unsigned char * dst = rotated.GetData(); + + unsigned char * alpha_dst = NULL; + if (has_alpha) + alpha_dst = rotated.GetAlpha(); + + // GRG: if the original image has a mask, use its RGB values + // as the blank pixel, else, fall back to default (black). + // + unsigned char blank_r = 0; + unsigned char blank_g = 0; + unsigned char blank_b = 0; + + if (HasMask()) + { + blank_r = GetMaskRed(); + blank_g = GetMaskGreen(); + blank_b = GetMaskBlue(); + rotated.SetMaskColour( blank_r, blank_g, blank_b ); + } + + // Now, for each point of the rotated image, find where it came from, by + // performing an inverse rotation (a rotation of -angle) and getting the + // pixel at those coordinates + + const int rH = rotated.GetHeight(); + const int rW = rotated.GetWidth(); + + // GRG: I've taken the (interpolating) test out of the loops, so that + // it is done only once, instead of repeating it for each pixel. + + if (interpolating) + { + for (int y = 0; y < rH; y++) + { + for (int x = 0; x < rW; x++) + { + wxRealPoint src = wxRotatePoint (x + x1a, y + y1a, cos_angle, -sin_angle, p0); + + if (-0.25 < src.x && src.x < w - 0.75 && + -0.25 < src.y && src.y < h - 0.75) + { + // interpolate using the 4 enclosing grid-points. Those + // points can be obtained using floor and ceiling of the + // exact coordinates of the point + int x1, y1, x2, y2; + + if (0 < src.x && src.x < w - 1) + { + x1 = wxRound(floor(src.x)); + x2 = wxRound(ceil(src.x)); + } + else // else means that x is near one of the borders (0 or width-1) + { + x1 = x2 = wxRound (src.x); + } + + if (0 < src.y && src.y < h - 1) + { + y1 = wxRound(floor(src.y)); + y2 = wxRound(ceil(src.y)); + } + else + { + y1 = y2 = wxRound (src.y); + } + + // get four points and the distances (square of the distance, + // for efficiency reasons) for the interpolation formula + + // GRG: Do not calculate the points until they are + // really needed -- this way we can calculate + // just one, instead of four, if d1, d2, d3 + // or d4 are < wxROTATE_EPSILON + + const double d1 = (src.x - x1) * (src.x - x1) + (src.y - y1) * (src.y - y1); + const double d2 = (src.x - x2) * (src.x - x2) + (src.y - y1) * (src.y - y1); + const double d3 = (src.x - x2) * (src.x - x2) + (src.y - y2) * (src.y - y2); + const double d4 = (src.x - x1) * (src.x - x1) + (src.y - y2) * (src.y - y2); + + // Now interpolate as a weighted average of the four surrounding + // points, where the weights are the distances to each of those points + + // If the point is exactly at one point of the grid of the source + // image, then don't interpolate -- just assign the pixel + + // d1,d2,d3,d4 are positive -- no need for abs() + if (d1 < wxROTATE_EPSILON) + { + unsigned char *p = data[y1] + (3 * x1); + *(dst++) = *(p++); + *(dst++) = *(p++); + *(dst++) = *p; + + if (has_alpha) + *(alpha_dst++) = *(alpha[y1] + x1); + } + else if (d2 < wxROTATE_EPSILON) + { + unsigned char *p = data[y1] + (3 * x2); + *(dst++) = *(p++); + *(dst++) = *(p++); + *(dst++) = *p; + + if (has_alpha) + *(alpha_dst++) = *(alpha[y1] + x2); + } + else if (d3 < wxROTATE_EPSILON) + { + unsigned char *p = data[y2] + (3 * x2); + *(dst++) = *(p++); + *(dst++) = *(p++); + *(dst++) = *p; + + if (has_alpha) + *(alpha_dst++) = *(alpha[y2] + x2); + } + else if (d4 < wxROTATE_EPSILON) + { + unsigned char *p = data[y2] + (3 * x1); + *(dst++) = *(p++); + *(dst++) = *(p++); + *(dst++) = *p; + + if (has_alpha) + *(alpha_dst++) = *(alpha[y2] + x1); + } + else + { + // weights for the weighted average are proportional to the inverse of the distance + unsigned char *v1 = data[y1] + (3 * x1); + unsigned char *v2 = data[y1] + (3 * x2); + unsigned char *v3 = data[y2] + (3 * x2); + unsigned char *v4 = data[y2] + (3 * x1); + + const double w1 = 1/d1, w2 = 1/d2, w3 = 1/d3, w4 = 1/d4; + + // GRG: Unrolled. + + *(dst++) = (unsigned char) + ( (w1 * *(v1++) + w2 * *(v2++) + + w3 * *(v3++) + w4 * *(v4++)) / + (w1 + w2 + w3 + w4) ); + *(dst++) = (unsigned char) + ( (w1 * *(v1++) + w2 * *(v2++) + + w3 * *(v3++) + w4 * *(v4++)) / + (w1 + w2 + w3 + w4) ); + *(dst++) = (unsigned char) + ( (w1 * *v1 + w2 * *v2 + + w3 * *v3 + w4 * *v4) / + (w1 + w2 + w3 + w4) ); + + if (has_alpha) + { + v1 = alpha[y1] + (x1); + v2 = alpha[y1] + (x2); + v3 = alpha[y2] + (x2); + v4 = alpha[y2] + (x1); + + *(alpha_dst++) = (unsigned char) + ( (w1 * *v1 + w2 * *v2 + + w3 * *v3 + w4 * *v4) / + (w1 + w2 + w3 + w4) ); + } + } + } + else + { + *(dst++) = blank_r; + *(dst++) = blank_g; + *(dst++) = blank_b; + + if (has_alpha) + *(alpha_dst++) = 0; + } + } + } + } + else // not interpolating + { + for (int y = 0; y < rH; y++) + { + for (int x = 0; x < rW; x++) + { + wxRealPoint src = wxRotatePoint (x + x1a, y + y1a, cos_angle, -sin_angle, p0); + + const int xs = wxRound (src.x); // wxRound rounds to the + const int ys = wxRound (src.y); // closest integer + + if (0 <= xs && xs < w && 0 <= ys && ys < h) + { + unsigned char *p = data[ys] + (3 * xs); + *(dst++) = *(p++); + *(dst++) = *(p++); + *(dst++) = *p; + + if (has_alpha) + *(alpha_dst++) = *(alpha[ys] + (xs)); + } + else + { + *(dst++) = blank_r; + *(dst++) = blank_g; + *(dst++) = blank_b; + + if (has_alpha) + *(alpha_dst++) = 255; + } + } + } + } + + delete [] data; + + if (has_alpha) + delete [] alpha; + + return rotated; +} + + + + + +// A module to allow wxImage initialization/cleanup +// without calling these functions from app.cpp or from +// the user's application. + +class wxImageModule: public wxModule +{ +DECLARE_DYNAMIC_CLASS(wxImageModule) +public: + wxImageModule() {} + bool OnInit() { wxImage::InitStandardHandlers(); return true; } + void OnExit() { wxImage::CleanUpHandlers(); } +}; + +IMPLEMENT_DYNAMIC_CLASS(wxImageModule, wxModule) + + +#endif // wxUSE_IMAGE diff --git a/Source/3rd Party/wx/src/common/imagfill.cpp b/Source/3rd Party/wx/src/common/imagfill.cpp index 9c799205e..a784b5058 100644 --- a/Source/3rd Party/wx/src/common/imagfill.cpp +++ b/Source/3rd Party/wx/src/common/imagfill.cpp @@ -1,325 +1,325 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagfill.cpp -// Purpose: FloodFill for wxImage -// Author: Julian Smart -// RCS-ID: $Id: imagfill.cpp 63770 2010-03-28 22:34:12Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && !defined(__WXMSW__) -// we have no use for this code in wxMSW... - -#ifndef WX_PRECOMP - #include "wx/brush.h" - #include "wx/dc.h" - #include "wx/dcmemory.h" - #include "wx/image.h" -#endif - -// DoFloodFill -// Fills with the colour extracted from fillBrush, starting at x,y until either -// a color different from the start pixel is reached (wxFLOOD_SURFACE) -// or fill color is reached (wxFLOOD_BORDER) - -static bool LINKAGEMODE MatchPixel(wxImage *img, int x, int y, int w, int h, const wxColour& c) -{ - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return false; - - unsigned char r = img->GetRed(x,y); - unsigned char g = img->GetGreen(x,y); - unsigned char b = img->GetBlue(x,y); - return c.Red() == r && c.Green() == g && c.Blue() == b ; -} - -static bool LINKAGEMODE MatchBoundaryPixel(wxImage *img, int x, int y, int w, int h, const wxColour & fill, const wxColour& bound) -{ - if ((x<0)||(x>=w)||(y<0)||(y>=h)) return true; - - unsigned char r = img->GetRed(x,y); - unsigned char g = img->GetGreen(x,y); - unsigned char b = img->GetBlue(x,y); - if ( fill.Red() == r && fill.Green() == g && fill.Blue() == b ) - return true; - if ( bound.Red() == r && bound.Green() == g && bound.Blue() == b ) - return true; - return false; -} - - -static void LINKAGEMODE -wxImageFloodFill(wxImage *image, - wxCoord x, wxCoord y, const wxBrush & fillBrush, - const wxColour& testColour, int style, - int WXUNUSED(LogicalFunction)) -{ - /* A diamond flood-fill using a circular queue system. - Each pixel surrounding the current pixel is added to - the queue if it meets the criteria, then is retrieved in - its turn. Code originally based on http://www.drawit.co.nz/Developers.htm, - with explicit permission to use this for wxWidgets granted by Andrew Empson - (no copyright claimed) - */ - - int width = image->GetWidth(); - int height = image->GetHeight(); - - //Draw using a pen made from the current brush colour - //Potentially allows us to use patterned flood fills in future code - wxColour fillColour = fillBrush.GetColour(); - unsigned char r = fillColour.Red(); - unsigned char g = fillColour.Green(); - unsigned char b = fillColour.Blue(); - - //initial test : - if (style == wxFLOOD_SURFACE) - { - //if wxFLOOD_SURFACE, if fill colour is same as required, we don't do anything - if ( image->GetRed(x,y) != r - || image->GetGreen(x,y) != g - || image->GetBlue (x,y) != b ) - { - //prepare memory for queue - //queue save, start, read - size_t *qs, *qst, *qr; - - //queue size (physical) - long qSz= height * width * 2; - qst = new size_t [qSz]; - - //temporary x and y locations - int xt, yt; - - for (int i=0; i < qSz; i++) - qst[i] = 0; - - // start queue - qs=qr=qst; - *qs=xt=x; - qs++; - *qs=yt=y; - qs++; - - image->SetRGB(xt,yt,r,g,b); - - //Main queue loop - while(qr!=qs) - { - //Add new members to queue - //Above current pixel - if(MatchPixel(image,xt,yt-1,width,height,testColour)) - { - *qs=xt; - qs++; - *qs=yt-1; - qs++; - image->SetRGB(xt,yt-1,r,g,b); - - //Loop back to beginning of queue - if(qs>=(qst+qSz)) qs=qst; - } - - //Below current pixel - if(MatchPixel(image,xt,yt+1,width,height,testColour)) - { - *qs=xt; - qs++; - *qs=yt+1; - qs++; - image->SetRGB(xt,yt+1,r,g,b); - if(qs>=(qst+qSz)) qs=qst; - } - - //Left of current pixel - if(MatchPixel(image,xt-1,yt,width,height,testColour)) - { - *qs=xt-1; - qs++; - *qs=yt; - qs++; - image->SetRGB(xt-1,yt,r,g,b); - if(qs>=(qst+qSz)) qs=qst; - } - - //Right of current pixel - if(MatchPixel(image,xt+1,yt,width,height,testColour)) - { - *qs=xt+1; - qs++; - *qs=yt; - qs++; - image->SetRGB(xt+1,yt,r,g,b); - if(qs>=(qst+qSz)) qs=qst; - } - - //Retrieve current queue member - qr+=2; - - //Loop back to the beginning - if(qr>=(qst+qSz)) qr=qst; - xt=*qr; - yt=*(qr+1); - - //Go Back to beginning of loop - } - - delete[] qst; - } - } - else - { - //style is wxFLOOD_BORDER - // fill up to testColor border - if already testColour don't do anything - if ( image->GetRed(x,y) != testColour.Red() - || image->GetGreen(x,y) != testColour.Green() - || image->GetBlue(x,y) != testColour.Blue() ) - { - //prepare memory for queue - //queue save, start, read - size_t *qs, *qst, *qr; - - //queue size (physical) - long qSz= height * width * 2; - qst = new size_t [qSz]; - - //temporary x and y locations - int xt, yt; - - for (int i=0; i < qSz; i++) - qst[i] = 0; - - // start queue - qs=qr=qst; - *qs=xt=x; - qs++; - *qs=yt=y; - qs++; - - image->SetRGB(xt,yt,r,g,b); - - //Main queue loop - while (qr!=qs) - { - //Add new members to queue - //Above current pixel - if(!MatchBoundaryPixel(image,xt,yt-1,width,height,fillColour,testColour)) - { - *qs=xt; - qs++; - *qs=yt-1; - qs++; - image->SetRGB(xt,yt-1,r,g,b); - - //Loop back to beginning of queue - if(qs>=(qst+qSz)) qs=qst; - } - - //Below current pixel - if(!MatchBoundaryPixel(image,xt,yt+1,width,height,fillColour,testColour)) - { - *qs=xt; - qs++; - *qs=yt+1; - qs++; - image->SetRGB(xt,yt+1,r,g,b); - if(qs>=(qst+qSz)) qs=qst; - } - - //Left of current pixel - if(!MatchBoundaryPixel(image,xt-1,yt,width,height,fillColour,testColour)) - { - *qs=xt-1; - qs++; - *qs=yt; - qs++; - image->SetRGB(xt-1,yt,r,g,b); - if(qs>=(qst+qSz)) qs=qst; - } - - //Right of current pixel - if(!MatchBoundaryPixel(image,xt+1,yt,width,height,fillColour,testColour)) - { - *qs=xt+1; - qs++; - *qs=yt; - qs++; - image->SetRGB(xt+1,yt,r,g,b); - if(qs>=(qst+qSz)) qs=qst; - } - - //Retrieve current queue member - qr+=2; - - //Loop back to the beginning - if(qr>=(qst+qSz)) qr=qst; - xt=*qr; - yt=*(qr+1); - - //Go Back to beginning of loop - } - - delete[] qst; - } - } - //all done, -} - - -bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y, - const wxColour& col, int style) -{ - if (dc->GetBrush().GetStyle() == wxTRANSPARENT) - return true; - - int height = 0; - int width = 0; - dc->GetSize(&width, &height); - - //it would be nice to fail if we don't get a sensible size... - wxCHECK_MSG(width >= 1 && height >= 1, false, - wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC")); - - const int x_dev = dc->LogicalToDeviceX(x); - const int y_dev = dc->LogicalToDeviceY(y); - - // if start point is outside dc, can't do anything - if (!wxRect(0, 0, width, height).Contains(x_dev, y_dev)) - return false; - - wxBitmap bitmap(width, height); - wxMemoryDC memdc(bitmap); - // match dc scales - double sx, sy; - dc->GetUserScale(&sx, &sy); - memdc.SetUserScale(sx, sy); - dc->GetLogicalScale(&sx, &sy); - memdc.SetLogicalScale(sx, sy); - - // get logical size and origin - const int w_log = dc->DeviceToLogicalXRel(width); - const int h_log = dc->DeviceToLogicalYRel(height); - const int x0_log = dc->DeviceToLogicalX(0); - const int y0_log = dc->DeviceToLogicalY(0); - - memdc.Blit(0, 0, w_log, h_log, dc, x0_log, y0_log); - memdc.SelectObject(wxNullBitmap); - - wxImage image = bitmap.ConvertToImage(); - wxImageFloodFill(&image, x_dev, y_dev, dc->GetBrush(), col, style, - dc->GetLogicalFunction()); - bitmap = wxBitmap(image); - memdc.SelectObject(bitmap); - dc->Blit(x0_log, y0_log, w_log, h_log, &memdc, 0, 0); - - return true; -} - -#endif // wxUSE_IMAGE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagfill.cpp +// Purpose: FloodFill for wxImage +// Author: Julian Smart +// RCS-ID: $Id: imagfill.cpp 63770 2010-03-28 22:34:12Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && !defined(__WXMSW__) +// we have no use for this code in wxMSW... + +#ifndef WX_PRECOMP + #include "wx/brush.h" + #include "wx/dc.h" + #include "wx/dcmemory.h" + #include "wx/image.h" +#endif + +// DoFloodFill +// Fills with the colour extracted from fillBrush, starting at x,y until either +// a color different from the start pixel is reached (wxFLOOD_SURFACE) +// or fill color is reached (wxFLOOD_BORDER) + +static bool LINKAGEMODE MatchPixel(wxImage *img, int x, int y, int w, int h, const wxColour& c) +{ + if ((x<0)||(x>=w)||(y<0)||(y>=h)) return false; + + unsigned char r = img->GetRed(x,y); + unsigned char g = img->GetGreen(x,y); + unsigned char b = img->GetBlue(x,y); + return c.Red() == r && c.Green() == g && c.Blue() == b ; +} + +static bool LINKAGEMODE MatchBoundaryPixel(wxImage *img, int x, int y, int w, int h, const wxColour & fill, const wxColour& bound) +{ + if ((x<0)||(x>=w)||(y<0)||(y>=h)) return true; + + unsigned char r = img->GetRed(x,y); + unsigned char g = img->GetGreen(x,y); + unsigned char b = img->GetBlue(x,y); + if ( fill.Red() == r && fill.Green() == g && fill.Blue() == b ) + return true; + if ( bound.Red() == r && bound.Green() == g && bound.Blue() == b ) + return true; + return false; +} + + +static void LINKAGEMODE +wxImageFloodFill(wxImage *image, + wxCoord x, wxCoord y, const wxBrush & fillBrush, + const wxColour& testColour, int style, + int WXUNUSED(LogicalFunction)) +{ + /* A diamond flood-fill using a circular queue system. + Each pixel surrounding the current pixel is added to + the queue if it meets the criteria, then is retrieved in + its turn. Code originally based on http://www.drawit.co.nz/Developers.htm, + with explicit permission to use this for wxWidgets granted by Andrew Empson + (no copyright claimed) + */ + + int width = image->GetWidth(); + int height = image->GetHeight(); + + //Draw using a pen made from the current brush colour + //Potentially allows us to use patterned flood fills in future code + wxColour fillColour = fillBrush.GetColour(); + unsigned char r = fillColour.Red(); + unsigned char g = fillColour.Green(); + unsigned char b = fillColour.Blue(); + + //initial test : + if (style == wxFLOOD_SURFACE) + { + //if wxFLOOD_SURFACE, if fill colour is same as required, we don't do anything + if ( image->GetRed(x,y) != r + || image->GetGreen(x,y) != g + || image->GetBlue (x,y) != b ) + { + //prepare memory for queue + //queue save, start, read + size_t *qs, *qst, *qr; + + //queue size (physical) + long qSz= height * width * 2; + qst = new size_t [qSz]; + + //temporary x and y locations + int xt, yt; + + for (int i=0; i < qSz; i++) + qst[i] = 0; + + // start queue + qs=qr=qst; + *qs=xt=x; + qs++; + *qs=yt=y; + qs++; + + image->SetRGB(xt,yt,r,g,b); + + //Main queue loop + while(qr!=qs) + { + //Add new members to queue + //Above current pixel + if(MatchPixel(image,xt,yt-1,width,height,testColour)) + { + *qs=xt; + qs++; + *qs=yt-1; + qs++; + image->SetRGB(xt,yt-1,r,g,b); + + //Loop back to beginning of queue + if(qs>=(qst+qSz)) qs=qst; + } + + //Below current pixel + if(MatchPixel(image,xt,yt+1,width,height,testColour)) + { + *qs=xt; + qs++; + *qs=yt+1; + qs++; + image->SetRGB(xt,yt+1,r,g,b); + if(qs>=(qst+qSz)) qs=qst; + } + + //Left of current pixel + if(MatchPixel(image,xt-1,yt,width,height,testColour)) + { + *qs=xt-1; + qs++; + *qs=yt; + qs++; + image->SetRGB(xt-1,yt,r,g,b); + if(qs>=(qst+qSz)) qs=qst; + } + + //Right of current pixel + if(MatchPixel(image,xt+1,yt,width,height,testColour)) + { + *qs=xt+1; + qs++; + *qs=yt; + qs++; + image->SetRGB(xt+1,yt,r,g,b); + if(qs>=(qst+qSz)) qs=qst; + } + + //Retrieve current queue member + qr+=2; + + //Loop back to the beginning + if(qr>=(qst+qSz)) qr=qst; + xt=*qr; + yt=*(qr+1); + + //Go Back to beginning of loop + } + + delete[] qst; + } + } + else + { + //style is wxFLOOD_BORDER + // fill up to testColor border - if already testColour don't do anything + if ( image->GetRed(x,y) != testColour.Red() + || image->GetGreen(x,y) != testColour.Green() + || image->GetBlue(x,y) != testColour.Blue() ) + { + //prepare memory for queue + //queue save, start, read + size_t *qs, *qst, *qr; + + //queue size (physical) + long qSz= height * width * 2; + qst = new size_t [qSz]; + + //temporary x and y locations + int xt, yt; + + for (int i=0; i < qSz; i++) + qst[i] = 0; + + // start queue + qs=qr=qst; + *qs=xt=x; + qs++; + *qs=yt=y; + qs++; + + image->SetRGB(xt,yt,r,g,b); + + //Main queue loop + while (qr!=qs) + { + //Add new members to queue + //Above current pixel + if(!MatchBoundaryPixel(image,xt,yt-1,width,height,fillColour,testColour)) + { + *qs=xt; + qs++; + *qs=yt-1; + qs++; + image->SetRGB(xt,yt-1,r,g,b); + + //Loop back to beginning of queue + if(qs>=(qst+qSz)) qs=qst; + } + + //Below current pixel + if(!MatchBoundaryPixel(image,xt,yt+1,width,height,fillColour,testColour)) + { + *qs=xt; + qs++; + *qs=yt+1; + qs++; + image->SetRGB(xt,yt+1,r,g,b); + if(qs>=(qst+qSz)) qs=qst; + } + + //Left of current pixel + if(!MatchBoundaryPixel(image,xt-1,yt,width,height,fillColour,testColour)) + { + *qs=xt-1; + qs++; + *qs=yt; + qs++; + image->SetRGB(xt-1,yt,r,g,b); + if(qs>=(qst+qSz)) qs=qst; + } + + //Right of current pixel + if(!MatchBoundaryPixel(image,xt+1,yt,width,height,fillColour,testColour)) + { + *qs=xt+1; + qs++; + *qs=yt; + qs++; + image->SetRGB(xt+1,yt,r,g,b); + if(qs>=(qst+qSz)) qs=qst; + } + + //Retrieve current queue member + qr+=2; + + //Loop back to the beginning + if(qr>=(qst+qSz)) qr=qst; + xt=*qr; + yt=*(qr+1); + + //Go Back to beginning of loop + } + + delete[] qst; + } + } + //all done, +} + + +bool wxDoFloodFill(wxDC *dc, wxCoord x, wxCoord y, + const wxColour& col, int style) +{ + if (dc->GetBrush().GetStyle() == wxTRANSPARENT) + return true; + + int height = 0; + int width = 0; + dc->GetSize(&width, &height); + + //it would be nice to fail if we don't get a sensible size... + wxCHECK_MSG(width >= 1 && height >= 1, false, + wxT("In FloodFill, dc.GetSize routine failed, method not supported by this DC")); + + const int x_dev = dc->LogicalToDeviceX(x); + const int y_dev = dc->LogicalToDeviceY(y); + + // if start point is outside dc, can't do anything + if (!wxRect(0, 0, width, height).Contains(x_dev, y_dev)) + return false; + + wxBitmap bitmap(width, height); + wxMemoryDC memdc(bitmap); + // match dc scales + double sx, sy; + dc->GetUserScale(&sx, &sy); + memdc.SetUserScale(sx, sy); + dc->GetLogicalScale(&sx, &sy); + memdc.SetLogicalScale(sx, sy); + + // get logical size and origin + const int w_log = dc->DeviceToLogicalXRel(width); + const int h_log = dc->DeviceToLogicalYRel(height); + const int x0_log = dc->DeviceToLogicalX(0); + const int y0_log = dc->DeviceToLogicalY(0); + + memdc.Blit(0, 0, w_log, h_log, dc, x0_log, y0_log); + memdc.SelectObject(wxNullBitmap); + + wxImage image = bitmap.ConvertToImage(); + wxImageFloodFill(&image, x_dev, y_dev, dc->GetBrush(), col, style, + dc->GetLogicalFunction()); + bitmap = wxBitmap(image); + memdc.SelectObject(bitmap); + dc->Blit(x0_log, y0_log, w_log, h_log, &memdc, 0, 0); + + return true; +} + +#endif // wxUSE_IMAGE diff --git a/Source/3rd Party/wx/src/common/imaggif.cpp b/Source/3rd Party/wx/src/common/imaggif.cpp index befa52af3..bb49847cf 100644 --- a/Source/3rd Party/wx/src/common/imaggif.cpp +++ b/Source/3rd Party/wx/src/common/imaggif.cpp @@ -1,105 +1,105 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imaggif.cpp -// Purpose: wxGIFHandler -// Author: Vaclav Slavik & Guillermo Rodriguez Garcia -// RCS-ID: $Id: imaggif.cpp 41819 2006-10-09 17:51:07Z VZ $ -// Copyright: (c) 1999 Vaclav Slavik & Guillermo Rodriguez Garcia -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_GIF - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" -#endif - -#include "wx/imaggif.h" -#include "wx/gifdecod.h" -#include "wx/wfstream.h" - -IMPLEMENT_DYNAMIC_CLASS(wxGIFHandler,wxImageHandler) - -//----------------------------------------------------------------------------- -// wxGIFHandler -//----------------------------------------------------------------------------- - -#if wxUSE_STREAMS - -bool wxGIFHandler::LoadFile(wxImage *image, wxInputStream& stream, - bool verbose, int index) -{ - wxGIFDecoder *decod; - wxGIFErrorCode error; - bool ok = true; - -// image->Destroy(); - decod = new wxGIFDecoder(); - error = decod->LoadGIF(stream); - - if ((error != wxGIF_OK) && (error != wxGIF_TRUNCATED)) - { - if (verbose) - { - switch (error) - { - case wxGIF_INVFORMAT: - wxLogError(_("GIF: error in GIF image format.")); - break; - case wxGIF_MEMERR: - wxLogError(_("GIF: not enough memory.")); - break; - default: - wxLogError(_("GIF: unknown error!!!")); - break; - } - } - delete decod; - return false; - } - - if ((error == wxGIF_TRUNCATED) && verbose) - { - wxLogError(_("GIF: data stream seems to be truncated.")); - /* go on; image data is OK */ - } - - if (ok) - { - ok = decod->ConvertToImage(index != -1 ? (size_t)index : 0, image); - } - else - { - wxLogError(_("GIF: Invalid gif index.")); - } - - delete decod; - - return ok; -} - -bool wxGIFHandler::SaveFile( wxImage * WXUNUSED(image), - wxOutputStream& WXUNUSED(stream), bool verbose ) -{ - if (verbose) - wxLogDebug(wxT("GIF: the handler is read-only!!")); - - return false; -} - -bool wxGIFHandler::DoCanRead( wxInputStream& stream ) -{ - wxGIFDecoder decod; - return decod.CanRead(stream); -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_GIF +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imaggif.cpp +// Purpose: wxGIFHandler +// Author: Vaclav Slavik & Guillermo Rodriguez Garcia +// RCS-ID: $Id: imaggif.cpp 41819 2006-10-09 17:51:07Z VZ $ +// Copyright: (c) 1999 Vaclav Slavik & Guillermo Rodriguez Garcia +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_GIF + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" +#endif + +#include "wx/imaggif.h" +#include "wx/gifdecod.h" +#include "wx/wfstream.h" + +IMPLEMENT_DYNAMIC_CLASS(wxGIFHandler,wxImageHandler) + +//----------------------------------------------------------------------------- +// wxGIFHandler +//----------------------------------------------------------------------------- + +#if wxUSE_STREAMS + +bool wxGIFHandler::LoadFile(wxImage *image, wxInputStream& stream, + bool verbose, int index) +{ + wxGIFDecoder *decod; + wxGIFErrorCode error; + bool ok = true; + +// image->Destroy(); + decod = new wxGIFDecoder(); + error = decod->LoadGIF(stream); + + if ((error != wxGIF_OK) && (error != wxGIF_TRUNCATED)) + { + if (verbose) + { + switch (error) + { + case wxGIF_INVFORMAT: + wxLogError(_("GIF: error in GIF image format.")); + break; + case wxGIF_MEMERR: + wxLogError(_("GIF: not enough memory.")); + break; + default: + wxLogError(_("GIF: unknown error!!!")); + break; + } + } + delete decod; + return false; + } + + if ((error == wxGIF_TRUNCATED) && verbose) + { + wxLogError(_("GIF: data stream seems to be truncated.")); + /* go on; image data is OK */ + } + + if (ok) + { + ok = decod->ConvertToImage(index != -1 ? (size_t)index : 0, image); + } + else + { + wxLogError(_("GIF: Invalid gif index.")); + } + + delete decod; + + return ok; +} + +bool wxGIFHandler::SaveFile( wxImage * WXUNUSED(image), + wxOutputStream& WXUNUSED(stream), bool verbose ) +{ + if (verbose) + wxLogDebug(wxT("GIF: the handler is read-only!!")); + + return false; +} + +bool wxGIFHandler::DoCanRead( wxInputStream& stream ) +{ + wxGIFDecoder decod; + return decod.CanRead(stream); +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_GIF diff --git a/Source/3rd Party/wx/src/common/imagiff.cpp b/Source/3rd Party/wx/src/common/imagiff.cpp index 1f00efae8..87ef21445 100644 --- a/Source/3rd Party/wx/src/common/imagiff.cpp +++ b/Source/3rd Party/wx/src/common/imagiff.cpp @@ -1,794 +1,794 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagiff.h -// Purpose: wxImage handler for Amiga IFF images -// Author: Steffen Gutmann, Thomas Meyer -// RCS-ID: $Id: imagiff.cpp 38787 2006-04-18 07:24:35Z ABX $ -// Copyright: (c) Steffen Gutmann, 2002 -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// Parts of this source are based on the iff loading algorithm found -// in xviff.c. Permission by the original author, Thomas Meyer, and -// by the author of xv, John Bradley for using the iff loading part -// in wxWidgets has been gratefully given. - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_IFF - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/intl.h" -#endif - -#include "wx/imagiff.h" -#include "wx/wfstream.h" - -#if wxUSE_PALETTE - #include "wx/palette.h" -#endif // wxUSE_PALETTE - -#include -#include - - -// -------------------------------------------------------------------------- -// Constants -// -------------------------------------------------------------------------- - -// Error codes: -// Note that the error code wxIFF_TRUNCATED means that the image itself -// is most probably OK, but the decoder didn't reach the end of the data -// stream; this means that if it was not reading directly from file, -// the stream will not be correctly positioned. -// - -enum -{ - wxIFF_OK = 0, /* everything was OK */ - wxIFF_INVFORMAT, /* error in iff header */ - wxIFF_MEMERR, /* error allocating memory */ - wxIFF_TRUNCATED /* file appears to be truncated */ -}; - -// -------------------------------------------------------------------------- -// wxIFFDecoder class -// -------------------------------------------------------------------------- - -// internal class for storing IFF image data -class IFFImage -{ -public: - unsigned int w; /* width */ - unsigned int h; /* height */ - int transparent; /* transparent color (-1 = none) */ - int colors; /* number of colors */ - unsigned char *p; /* bitmap */ - unsigned char *pal; /* palette */ - - IFFImage() : w(0), h(0), colors(0), p(0), pal(0) {} - ~IFFImage() { delete [] p; delete [] pal; } -}; - -class WXDLLEXPORT wxIFFDecoder -{ -private: - IFFImage *m_image; // image data - wxInputStream *m_f; // input stream - unsigned char *databuf; - unsigned char *picptr; - unsigned char *decomp_mem; - - void Destroy(); - -public: - // get data of current frame - unsigned char* GetData() const; - unsigned char* GetPalette() const; - int GetNumColors() const; - unsigned int GetWidth() const; - unsigned int GetHeight() const; - int GetTransparentColour() const; - - // constructor, destructor, etc. - wxIFFDecoder(wxInputStream *s); - ~wxIFFDecoder() { Destroy(); } - bool CanRead(); - int ReadIFF(); - bool ConvertToImage(wxImage *image) const; -}; - - -//--------------------------------------------------------------------------- -// wxIFFDecoder constructor and destructor -//--------------------------------------------------------------------------- - -wxIFFDecoder::wxIFFDecoder(wxInputStream *s) -{ - m_f = s; - m_image = 0; - databuf = 0; - decomp_mem = 0; -} - -void wxIFFDecoder::Destroy() -{ - delete m_image; - m_image = 0; - delete [] databuf; - databuf = 0; - delete [] decomp_mem; - decomp_mem = 0; -} - -//--------------------------------------------------------------------------- -// Convert this image to a wxImage object -//--------------------------------------------------------------------------- - -// This function was designed by Vaclav Slavik - -bool wxIFFDecoder::ConvertToImage(wxImage *image) const -{ - // just in case... - image->Destroy(); - - // create the image - image->Create(GetWidth(), GetHeight()); - - if (!image->Ok()) - return false; - - unsigned char *pal = GetPalette(); - unsigned char *src = GetData(); - unsigned char *dst = image->GetData(); - int colors = GetNumColors(); - int transparent = GetTransparentColour(); - long i; - - // set transparent colour mask - if (transparent != -1) - { - for (i = 0; i < colors; i++) - { - if ((pal[3 * i + 0] == 255) && - (pal[3 * i + 1] == 0) && - (pal[3 * i + 2] == 255)) - { - pal[3 * i + 2] = 254; - } - } - - pal[3 * transparent + 0] = 255, - pal[3 * transparent + 1] = 0, - pal[3 * transparent + 2] = 255; - - image->SetMaskColour(255, 0, 255); - } - else - image->SetMask(false); - -#if wxUSE_PALETTE - if (pal && colors > 0) - { - unsigned char* r = new unsigned char[colors]; - unsigned char* g = new unsigned char[colors]; - unsigned char* b = new unsigned char[colors]; - - for (i = 0; i < colors; i++) - { - r[i] = pal[3*i + 0]; - g[i] = pal[3*i + 1]; - b[i] = pal[3*i + 2]; - } - - image->SetPalette(wxPalette(colors, r, g, b)); - - delete [] r; - delete [] g; - delete [] b; - } -#endif // wxUSE_PALETTE - - // copy image data - for (i = 0; i < (long)(GetWidth() * GetHeight()); i++, src += 3, dst += 3) - { - dst[0] = src[0]; - dst[1] = src[1]; - dst[2] = src[2]; - } - - return true; -} - - -//--------------------------------------------------------------------------- -// Data accessors -//--------------------------------------------------------------------------- - -// Get data for current frame - -unsigned char* wxIFFDecoder::GetData() const { return (m_image->p); } -unsigned char* wxIFFDecoder::GetPalette() const { return (m_image->pal); } -int wxIFFDecoder::GetNumColors() const { return m_image->colors; } -unsigned int wxIFFDecoder::GetWidth() const { return (m_image->w); } -unsigned int wxIFFDecoder::GetHeight() const { return (m_image->h); } -int wxIFFDecoder::GetTransparentColour() const { return m_image->transparent; } - -//--------------------------------------------------------------------------- -// IFF reading and decoding -//--------------------------------------------------------------------------- - -// -// CanRead: -// Returns true if the file looks like a valid IFF, false otherwise. -// -bool wxIFFDecoder::CanRead() -{ - unsigned char buf[12]; - - if ( !m_f->Read(buf, WXSIZEOF(buf)) ) - return false; - - m_f->SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent); - - return (memcmp(buf, "FORM", 4) == 0) && (memcmp(buf+8, "ILBM", 4) == 0); -} - - -// ReadIFF: -// Based on xv source code by Thomas Meyer -// Permission for use in wxWidgets has been gratefully given. - -typedef unsigned char byte; -#define IFFDEBUG 0 - -/************************************************************************* - void decomprle(source, destination, source length, buffer size) - - Decompress run-length encoded data from source to destination. Terminates - when source is decoded completely or destination buffer is full. - - The decruncher is as optimized as I could make it, without risking - safety in case of corrupt BODY chunks. -**************************************************************************/ - -static void decomprle(const byte *sptr, byte *dptr, long slen, long dlen) -{ - byte codeByte, dataByte; - - while ((slen > 0) && (dlen > 0)) { - // read control byte - codeByte = *sptr++; - - if (codeByte < 0x80) { - codeByte++; - if ((slen > (long) codeByte) && (dlen >= (long) codeByte)) { - slen -= codeByte + 1; - dlen -= codeByte; - while (codeByte > 0) { - *dptr++ = *sptr++; - codeByte--; - } - } - else slen = 0; - } - - else if (codeByte > 0x80) { - codeByte = 0x81 - (codeByte & 0x7f); - if ((slen > (long) 0) && (dlen >= (long) codeByte)) { - dataByte = *sptr++; - slen -= 2; - dlen -= codeByte; - while (codeByte > 0) { - *dptr++ = dataByte; - codeByte--; - } - } - else slen = 0; - } - } -} - -/******************************************/ -static unsigned int iff_getword(const byte *ptr) -{ - unsigned int v; - - v = *ptr++; - v = (v << 8) + *ptr; - return v; -} - -/******************************************/ -static unsigned long iff_getlong(const byte *ptr) -{ - unsigned long l; - - l = *ptr++; - l = (l << 8) + *ptr++; - l = (l << 8) + *ptr++; - l = (l << 8) + *ptr; - return l; -} - -// Define internal ILBM types -#define ILBM_NORMAL 0 -#define ILBM_EHB 1 -#define ILBM_HAM 2 -#define ILBM_HAM8 3 -#define ILBM_24BIT 4 - -int wxIFFDecoder::ReadIFF() -{ - Destroy(); - - m_image = new IFFImage(); - if (m_image == 0) { - Destroy(); - return wxIFF_MEMERR; - } - - // compute file length - wxFileOffset currentPos = m_f->TellI(); - m_f->SeekI(0, wxFromEnd); - long filesize = m_f->TellI(); - m_f->SeekI(currentPos, wxFromStart); - - // allocate memory for complete file - if ((databuf = new byte[filesize]) == 0) { - Destroy(); - return wxIFF_MEMERR; - } - - m_f->Read(databuf, filesize); - const byte *dataend = databuf + filesize; - - // initialize work pointer. used to trace the buffer for IFF chunks - const byte *dataptr = databuf; - - // check for minmal size - if (dataptr + 12 > dataend) { - Destroy(); - return wxIFF_INVFORMAT; - } - - // check if we really got an IFF file - if (strncmp((char *)dataptr, "FORM", 4) != 0) { - Destroy(); - return wxIFF_INVFORMAT; - } - - dataptr = dataptr + 8; // skip ID and length of FORM - - // check if the IFF file is an ILBM (picture) file - if (strncmp((char *) dataptr, "ILBM", 4) != 0) { - Destroy(); - return wxIFF_INVFORMAT; - } - - wxLogTrace(_T("iff"), _T("IFF ILBM file recognized")); - - dataptr = dataptr + 4; // skip ID - - // - // main decoding loop. searches IFF chunks and handles them. - // terminates when BODY chunk was found or dataptr ran over end of file - // - bool BMHDok = false, CMAPok = false, CAMGok = false; - int bmhd_width = 0, bmhd_height = 0, bmhd_bitplanes = 0, bmhd_transcol = -1; - byte bmhd_masking = 0, bmhd_compression = 0; - long camg_viewmode = 0; - int colors = 0; - while (dataptr + 8 <= dataend) { - // get chunk length and make even - size_t chunkLen = (iff_getlong(dataptr + 4) + 1) & 0xfffffffe; -#ifdef __VMS - // Silence compiler warning - int chunkLen_; - chunkLen_ = chunkLen; - if (chunkLen_ < 0) { // format error? -#else - if (chunkLen < 0) { // format error? -#endif - break; - } - bool truncated = (dataptr + 8 + chunkLen > dataend); - - if (strncmp((char *)dataptr, "BMHD", 4) == 0) { // BMHD chunk? - if (chunkLen < 12 + 2 || truncated) { - break; - } - bmhd_width = iff_getword(dataptr + 8); // width of picture - bmhd_height= iff_getword(dataptr + 8 + 2); // height of picture - bmhd_bitplanes = *(dataptr + 8 + 8); // # of bitplanes - bmhd_masking = *(dataptr + 8 + 9); - bmhd_compression = *(dataptr + 8 + 10); // get compression - bmhd_transcol = iff_getword(dataptr + 8 + 12); - BMHDok = true; // got BMHD - dataptr += 8 + chunkLen; // to next chunk - } - else if (strncmp((char *)dataptr, "CMAP", 4) == 0) { // CMAP ? - if (truncated) { - break; - } - const byte *cmapptr = dataptr + 8; - colors = chunkLen / 3; // calc no of colors - - delete m_image->pal; - m_image->pal = 0; - m_image->colors = colors; - if (colors > 0) { - m_image->pal = new byte[3*colors]; - if (!m_image->pal) { - Destroy(); - return wxIFF_MEMERR; - } - - // copy colors to color map - for (int i=0; i < colors; i++) { - m_image->pal[3*i + 0] = *cmapptr++; - m_image->pal[3*i + 1] = *cmapptr++; - m_image->pal[3*i + 2] = *cmapptr++; - } - } - - wxLogTrace(_T("iff"), _T("Read %d colors from IFF file."), - colors); - - CMAPok = true; // got CMAP - dataptr += 8 + chunkLen; // to next chunk - } else if (strncmp((char *)dataptr, "CAMG", 4) == 0) { // CAMG ? - if (chunkLen < 4 || truncated) { - break; - } - camg_viewmode = iff_getlong(dataptr + 8); // get viewmodes - CAMGok = true; // got CAMG - dataptr += 8 + chunkLen; // to next chunk - } - else if (strncmp((char *)dataptr, "BODY", 4) == 0) { // BODY ? - if (!BMHDok) { // BMHD found? - break; - } - const byte *bodyptr = dataptr + 8; // -> BODY data - - if (truncated) { - chunkLen = dataend - dataptr; - } - - // - // if BODY is compressed, allocate buffer for decrunched BODY - // and decompress it (run length encoding) - // - if (bmhd_compression == 1) { - // calc size of decrunch buffer - (size of the actual pic. - // decompressed in interleaved Amiga bitplane format) - - size_t decomp_bufsize = (((bmhd_width + 15) >> 4) << 1) - * bmhd_height * bmhd_bitplanes; - - if ((decomp_mem = new byte[decomp_bufsize]) == 0) { - Destroy(); - return wxIFF_MEMERR; - } - - decomprle(bodyptr, decomp_mem, chunkLen, decomp_bufsize); - bodyptr = decomp_mem; // -> uncompressed BODY - chunkLen = decomp_bufsize; - delete [] databuf; - databuf = 0; - } - - // the following determines the type of the ILBM file. - // it's either NORMAL, EHB, HAM, HAM8 or 24BIT - - int fmt = ILBM_NORMAL; // assume normal ILBM - if (bmhd_bitplanes == 24) { - fmt = ILBM_24BIT; - } else if (bmhd_bitplanes == 8) { - if (CAMGok && (camg_viewmode & 0x800)) { - fmt = ILBM_HAM8; - } - } else if ((bmhd_bitplanes > 5) && CAMGok) { - if (camg_viewmode & 0x80) { - fmt = ILBM_EHB; - } else if (camg_viewmode & 0x800) { - fmt = ILBM_HAM; - } - } - - wxLogTrace(_T("iff"), - _T("LoadIFF: %s %dx%d, planes=%d (%d cols), comp=%d"), - (fmt==ILBM_NORMAL) ? "Normal ILBM" : - (fmt==ILBM_HAM) ? "HAM ILBM" : - (fmt==ILBM_HAM8) ? "HAM8 ILBM" : - (fmt==ILBM_EHB) ? "EHB ILBM" : - (fmt==ILBM_24BIT) ? "24BIT ILBM" : "unknown ILBM", - bmhd_width, bmhd_height, bmhd_bitplanes, - 1< m_image->colors) { - byte *pal = new byte[colors*3]; - if (!pal) { - Destroy(); - return wxIFF_MEMERR; - } - int i; - for (i = 0; i < m_image->colors; i++) { - pal[3*i + 0] = m_image->pal[3*i + 0]; - pal[3*i + 1] = m_image->pal[3*i + 1]; - pal[3*i + 2] = m_image->pal[3*i + 2]; - } - for (; i < colors; i++) { - pal[3*i + 0] = 0; - pal[3*i + 1] = 0; - pal[3*i + 2] = 0; - } - delete m_image->pal; - m_image->pal = pal; - m_image->colors = colors; - } - - for (int i=0; i < colors; i++) { - m_image->pal[3*i + 0] = (m_image->pal[3*i + 0] >> 4) * 17; - m_image->pal[3*i + 1] = (m_image->pal[3*i + 1] >> 4) * 17; - m_image->pal[3*i + 2] = (m_image->pal[3*i + 2] >> 4) * 17; - } - } - - m_image->p = new byte[bmhd_width * bmhd_height * 3]; - byte *picptr = m_image->p; - if (!picptr) { - Destroy(); - return wxIFF_MEMERR; - } - - byte *pal = m_image->pal; - int lineskip = ((bmhd_width + 15) >> 4) << 1; - int height = chunkLen / (lineskip * bmhd_bitplanes); - - if (bmhd_height < height) { - height = bmhd_height; - } - - if (fmt == ILBM_HAM || fmt == ILBM_HAM8 || fmt == ILBM_24BIT) { - byte *pic = picptr; - const byte *workptr = bodyptr; - - for (int i=0; i < height; i++) { - byte bitmsk = 0x80; - const byte *workptr2 = workptr; - - // at start of each line, init RGB values to background - byte rval = pal[0]; - byte gval = pal[1]; - byte bval = pal[2]; - - for (int j=0; j < bmhd_width; j++) { - long col = 0; - long colbit = 1; - const byte *workptr3 = workptr2; - for (int k=0; k < bmhd_bitplanes; k++) { - if (*workptr3 & bitmsk) { - col += colbit; - } - workptr3 += lineskip; - colbit <<= 1; - } - - if (fmt==ILBM_HAM) { - int c = (col & 0x0f); - switch (col & 0x30) { - case 0x00: if (c >= 0 && c < colors) { - rval = pal[3*c + 0]; - gval = pal[3*c + 1]; - bval = pal[3*c + 2]; - } - break; - - case 0x10: bval = c * 17; - break; - - case 0x20: rval = c * 17; - break; - - case 0x30: gval = c * 17; - break; - } - } else if (fmt == ILBM_HAM8) { - int c = (col & 0x3f); - switch(col & 0xc0) { - case 0x00: if (c >= 0 && c < colors) { - rval = pal[3*c + 0]; - gval = pal[3*c + 1]; - bval = pal[3*c + 2]; - } - break; - - case 0x40: bval = (bval & 3) | (c << 2); - break; - - case 0x80: rval = (rval & 3) | (c << 2); - break; - - case 0xc0: gval = (rval & 3) | (c << 2); - } - } else { - rval = col & 0xff; - gval = (col >> 8) & 0xff; - bval = (col >> 16) & 0xff; - } - - *pic++ = rval; - *pic++ = gval; - *pic++ = bval; - - bitmsk = bitmsk >> 1; - if (bitmsk == 0) { - bitmsk = 0x80; - workptr2++; - } - } - workptr += lineskip * bmhd_bitplanes; - } - } else if ((fmt == ILBM_NORMAL) || (fmt == ILBM_EHB)) { - if (fmt == ILBM_EHB) { - wxLogTrace(_T("iff"), _T("Doubling CMAP for EHB mode")); - - for (int i=0; i<32; i++) { - pal[3*(i + 32) + 0] = pal[3*i + 0] >> 1; - pal[3*(i + 32) + 1] = pal[3*i + 1] >> 1; - pal[3*(i + 32) + 2] = pal[3*i + 2] >> 1; - } - } - - byte *pic = picptr; // ptr to buffer - const byte *workptr = bodyptr; // ptr to pic, planar format - - if (bmhd_height < height) { - height = bmhd_height; - } - - for (int i=0; i < height; i++) { - byte bitmsk = 0x80; // left most bit (mask) - const byte *workptr2 = workptr; // work ptr to source - for (int j=0; j < bmhd_width; j++) { - long col = 0; - long colbit = 1; - const byte *workptr3 = workptr2; // 1st byte in 1st pln - - for (int k=0; k < bmhd_bitplanes; k++) { - if (*workptr3 & bitmsk) { // if bit set in this pln - col = col + colbit; // add bit to chunky byte - } - workptr3 += lineskip; // go to next line - colbit <<= 1; // shift color bit - } - - if (col >= 0 && col < colors) { - pic[0] = pal[3*col + 0]; - pic[1] = pal[3*col + 1]; - pic[2] = pal[3*col + 2]; - } else { - pic[0] = pic[1] = pic[2] = 0; - } - pic += 3; - bitmsk = bitmsk >> 1; // shift mask to next bit - if (bitmsk == 0) { // if mask is zero - bitmsk = 0x80; // reset mask - workptr2++; // mv ptr to next byte - } - } - - workptr += lineskip * bmhd_bitplanes; // to next line - } - } else { - break; // unknown format - } - - m_image->w = bmhd_width; - m_image->h = height; - m_image->transparent = bmhd_transcol; - - wxLogTrace(_T("iff"), _T("Loaded IFF picture %s"), - truncated? "truncated" : "completely"); - - return (truncated? wxIFF_TRUNCATED : wxIFF_OK); - } else { - wxLogTrace(_T("iff"), _T("Skipping unknown chunk '%c%c%c%c'"), - *dataptr, *(dataptr+1), *(dataptr+2), *(dataptr+3)); - - dataptr = dataptr + 8 + chunkLen; // skip unknown chunk - } - } - - Destroy(); - return wxIFF_INVFORMAT; -} - - - -//----------------------------------------------------------------------------- -// wxIFFHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxIFFHandler, wxImageHandler) - -#if wxUSE_STREAMS - -bool wxIFFHandler::LoadFile(wxImage *image, wxInputStream& stream, - bool verbose, int WXUNUSED(index)) -{ - wxIFFDecoder *decod; - int error; - bool ok; - - decod = new wxIFFDecoder(&stream); - error = decod->ReadIFF(); - - if ((error != wxIFF_OK) && (error != wxIFF_TRUNCATED)) - { - if (verbose) - { - switch (error) - { - case wxIFF_INVFORMAT: - wxLogError(_("IFF: error in IFF image format.")); - break; - case wxIFF_MEMERR: - wxLogError(_("IFF: not enough memory.")); - break; - default: - wxLogError(_("IFF: unknown error!!!")); - break; - } - } - delete decod; - return false; - } - - if ((error == wxIFF_TRUNCATED) && verbose) - { - wxLogError(_("IFF: data stream seems to be truncated.")); - /* go on; image data is OK */ - } - - ok = decod->ConvertToImage(image); - delete decod; - - return ok; -} - -bool wxIFFHandler::SaveFile(wxImage * WXUNUSED(image), - wxOutputStream& WXUNUSED(stream), bool verbose) -{ - if (verbose) - wxLogDebug(wxT("IFF: the handler is read-only!!")); - - return false; -} - -bool wxIFFHandler::DoCanRead(wxInputStream& stream) -{ - wxIFFDecoder decod(&stream); - - return decod.CanRead(); -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_IFF +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagiff.h +// Purpose: wxImage handler for Amiga IFF images +// Author: Steffen Gutmann, Thomas Meyer +// RCS-ID: $Id: imagiff.cpp 38787 2006-04-18 07:24:35Z ABX $ +// Copyright: (c) Steffen Gutmann, 2002 +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// Parts of this source are based on the iff loading algorithm found +// in xviff.c. Permission by the original author, Thomas Meyer, and +// by the author of xv, John Bradley for using the iff loading part +// in wxWidgets has been gratefully given. + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_IFF + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/intl.h" +#endif + +#include "wx/imagiff.h" +#include "wx/wfstream.h" + +#if wxUSE_PALETTE + #include "wx/palette.h" +#endif // wxUSE_PALETTE + +#include +#include + + +// -------------------------------------------------------------------------- +// Constants +// -------------------------------------------------------------------------- + +// Error codes: +// Note that the error code wxIFF_TRUNCATED means that the image itself +// is most probably OK, but the decoder didn't reach the end of the data +// stream; this means that if it was not reading directly from file, +// the stream will not be correctly positioned. +// + +enum +{ + wxIFF_OK = 0, /* everything was OK */ + wxIFF_INVFORMAT, /* error in iff header */ + wxIFF_MEMERR, /* error allocating memory */ + wxIFF_TRUNCATED /* file appears to be truncated */ +}; + +// -------------------------------------------------------------------------- +// wxIFFDecoder class +// -------------------------------------------------------------------------- + +// internal class for storing IFF image data +class IFFImage +{ +public: + unsigned int w; /* width */ + unsigned int h; /* height */ + int transparent; /* transparent color (-1 = none) */ + int colors; /* number of colors */ + unsigned char *p; /* bitmap */ + unsigned char *pal; /* palette */ + + IFFImage() : w(0), h(0), colors(0), p(0), pal(0) {} + ~IFFImage() { delete [] p; delete [] pal; } +}; + +class WXDLLEXPORT wxIFFDecoder +{ +private: + IFFImage *m_image; // image data + wxInputStream *m_f; // input stream + unsigned char *databuf; + unsigned char *picptr; + unsigned char *decomp_mem; + + void Destroy(); + +public: + // get data of current frame + unsigned char* GetData() const; + unsigned char* GetPalette() const; + int GetNumColors() const; + unsigned int GetWidth() const; + unsigned int GetHeight() const; + int GetTransparentColour() const; + + // constructor, destructor, etc. + wxIFFDecoder(wxInputStream *s); + ~wxIFFDecoder() { Destroy(); } + bool CanRead(); + int ReadIFF(); + bool ConvertToImage(wxImage *image) const; +}; + + +//--------------------------------------------------------------------------- +// wxIFFDecoder constructor and destructor +//--------------------------------------------------------------------------- + +wxIFFDecoder::wxIFFDecoder(wxInputStream *s) +{ + m_f = s; + m_image = 0; + databuf = 0; + decomp_mem = 0; +} + +void wxIFFDecoder::Destroy() +{ + delete m_image; + m_image = 0; + delete [] databuf; + databuf = 0; + delete [] decomp_mem; + decomp_mem = 0; +} + +//--------------------------------------------------------------------------- +// Convert this image to a wxImage object +//--------------------------------------------------------------------------- + +// This function was designed by Vaclav Slavik + +bool wxIFFDecoder::ConvertToImage(wxImage *image) const +{ + // just in case... + image->Destroy(); + + // create the image + image->Create(GetWidth(), GetHeight()); + + if (!image->Ok()) + return false; + + unsigned char *pal = GetPalette(); + unsigned char *src = GetData(); + unsigned char *dst = image->GetData(); + int colors = GetNumColors(); + int transparent = GetTransparentColour(); + long i; + + // set transparent colour mask + if (transparent != -1) + { + for (i = 0; i < colors; i++) + { + if ((pal[3 * i + 0] == 255) && + (pal[3 * i + 1] == 0) && + (pal[3 * i + 2] == 255)) + { + pal[3 * i + 2] = 254; + } + } + + pal[3 * transparent + 0] = 255, + pal[3 * transparent + 1] = 0, + pal[3 * transparent + 2] = 255; + + image->SetMaskColour(255, 0, 255); + } + else + image->SetMask(false); + +#if wxUSE_PALETTE + if (pal && colors > 0) + { + unsigned char* r = new unsigned char[colors]; + unsigned char* g = new unsigned char[colors]; + unsigned char* b = new unsigned char[colors]; + + for (i = 0; i < colors; i++) + { + r[i] = pal[3*i + 0]; + g[i] = pal[3*i + 1]; + b[i] = pal[3*i + 2]; + } + + image->SetPalette(wxPalette(colors, r, g, b)); + + delete [] r; + delete [] g; + delete [] b; + } +#endif // wxUSE_PALETTE + + // copy image data + for (i = 0; i < (long)(GetWidth() * GetHeight()); i++, src += 3, dst += 3) + { + dst[0] = src[0]; + dst[1] = src[1]; + dst[2] = src[2]; + } + + return true; +} + + +//--------------------------------------------------------------------------- +// Data accessors +//--------------------------------------------------------------------------- + +// Get data for current frame + +unsigned char* wxIFFDecoder::GetData() const { return (m_image->p); } +unsigned char* wxIFFDecoder::GetPalette() const { return (m_image->pal); } +int wxIFFDecoder::GetNumColors() const { return m_image->colors; } +unsigned int wxIFFDecoder::GetWidth() const { return (m_image->w); } +unsigned int wxIFFDecoder::GetHeight() const { return (m_image->h); } +int wxIFFDecoder::GetTransparentColour() const { return m_image->transparent; } + +//--------------------------------------------------------------------------- +// IFF reading and decoding +//--------------------------------------------------------------------------- + +// +// CanRead: +// Returns true if the file looks like a valid IFF, false otherwise. +// +bool wxIFFDecoder::CanRead() +{ + unsigned char buf[12]; + + if ( !m_f->Read(buf, WXSIZEOF(buf)) ) + return false; + + m_f->SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent); + + return (memcmp(buf, "FORM", 4) == 0) && (memcmp(buf+8, "ILBM", 4) == 0); +} + + +// ReadIFF: +// Based on xv source code by Thomas Meyer +// Permission for use in wxWidgets has been gratefully given. + +typedef unsigned char byte; +#define IFFDEBUG 0 + +/************************************************************************* + void decomprle(source, destination, source length, buffer size) + + Decompress run-length encoded data from source to destination. Terminates + when source is decoded completely or destination buffer is full. + + The decruncher is as optimized as I could make it, without risking + safety in case of corrupt BODY chunks. +**************************************************************************/ + +static void decomprle(const byte *sptr, byte *dptr, long slen, long dlen) +{ + byte codeByte, dataByte; + + while ((slen > 0) && (dlen > 0)) { + // read control byte + codeByte = *sptr++; + + if (codeByte < 0x80) { + codeByte++; + if ((slen > (long) codeByte) && (dlen >= (long) codeByte)) { + slen -= codeByte + 1; + dlen -= codeByte; + while (codeByte > 0) { + *dptr++ = *sptr++; + codeByte--; + } + } + else slen = 0; + } + + else if (codeByte > 0x80) { + codeByte = 0x81 - (codeByte & 0x7f); + if ((slen > (long) 0) && (dlen >= (long) codeByte)) { + dataByte = *sptr++; + slen -= 2; + dlen -= codeByte; + while (codeByte > 0) { + *dptr++ = dataByte; + codeByte--; + } + } + else slen = 0; + } + } +} + +/******************************************/ +static unsigned int iff_getword(const byte *ptr) +{ + unsigned int v; + + v = *ptr++; + v = (v << 8) + *ptr; + return v; +} + +/******************************************/ +static unsigned long iff_getlong(const byte *ptr) +{ + unsigned long l; + + l = *ptr++; + l = (l << 8) + *ptr++; + l = (l << 8) + *ptr++; + l = (l << 8) + *ptr; + return l; +} + +// Define internal ILBM types +#define ILBM_NORMAL 0 +#define ILBM_EHB 1 +#define ILBM_HAM 2 +#define ILBM_HAM8 3 +#define ILBM_24BIT 4 + +int wxIFFDecoder::ReadIFF() +{ + Destroy(); + + m_image = new IFFImage(); + if (m_image == 0) { + Destroy(); + return wxIFF_MEMERR; + } + + // compute file length + wxFileOffset currentPos = m_f->TellI(); + m_f->SeekI(0, wxFromEnd); + long filesize = m_f->TellI(); + m_f->SeekI(currentPos, wxFromStart); + + // allocate memory for complete file + if ((databuf = new byte[filesize]) == 0) { + Destroy(); + return wxIFF_MEMERR; + } + + m_f->Read(databuf, filesize); + const byte *dataend = databuf + filesize; + + // initialize work pointer. used to trace the buffer for IFF chunks + const byte *dataptr = databuf; + + // check for minmal size + if (dataptr + 12 > dataend) { + Destroy(); + return wxIFF_INVFORMAT; + } + + // check if we really got an IFF file + if (strncmp((char *)dataptr, "FORM", 4) != 0) { + Destroy(); + return wxIFF_INVFORMAT; + } + + dataptr = dataptr + 8; // skip ID and length of FORM + + // check if the IFF file is an ILBM (picture) file + if (strncmp((char *) dataptr, "ILBM", 4) != 0) { + Destroy(); + return wxIFF_INVFORMAT; + } + + wxLogTrace(_T("iff"), _T("IFF ILBM file recognized")); + + dataptr = dataptr + 4; // skip ID + + // + // main decoding loop. searches IFF chunks and handles them. + // terminates when BODY chunk was found or dataptr ran over end of file + // + bool BMHDok = false, CMAPok = false, CAMGok = false; + int bmhd_width = 0, bmhd_height = 0, bmhd_bitplanes = 0, bmhd_transcol = -1; + byte bmhd_masking = 0, bmhd_compression = 0; + long camg_viewmode = 0; + int colors = 0; + while (dataptr + 8 <= dataend) { + // get chunk length and make even + size_t chunkLen = (iff_getlong(dataptr + 4) + 1) & 0xfffffffe; +#ifdef __VMS + // Silence compiler warning + int chunkLen_; + chunkLen_ = chunkLen; + if (chunkLen_ < 0) { // format error? +#else + if (chunkLen < 0) { // format error? +#endif + break; + } + bool truncated = (dataptr + 8 + chunkLen > dataend); + + if (strncmp((char *)dataptr, "BMHD", 4) == 0) { // BMHD chunk? + if (chunkLen < 12 + 2 || truncated) { + break; + } + bmhd_width = iff_getword(dataptr + 8); // width of picture + bmhd_height= iff_getword(dataptr + 8 + 2); // height of picture + bmhd_bitplanes = *(dataptr + 8 + 8); // # of bitplanes + bmhd_masking = *(dataptr + 8 + 9); + bmhd_compression = *(dataptr + 8 + 10); // get compression + bmhd_transcol = iff_getword(dataptr + 8 + 12); + BMHDok = true; // got BMHD + dataptr += 8 + chunkLen; // to next chunk + } + else if (strncmp((char *)dataptr, "CMAP", 4) == 0) { // CMAP ? + if (truncated) { + break; + } + const byte *cmapptr = dataptr + 8; + colors = chunkLen / 3; // calc no of colors + + delete m_image->pal; + m_image->pal = 0; + m_image->colors = colors; + if (colors > 0) { + m_image->pal = new byte[3*colors]; + if (!m_image->pal) { + Destroy(); + return wxIFF_MEMERR; + } + + // copy colors to color map + for (int i=0; i < colors; i++) { + m_image->pal[3*i + 0] = *cmapptr++; + m_image->pal[3*i + 1] = *cmapptr++; + m_image->pal[3*i + 2] = *cmapptr++; + } + } + + wxLogTrace(_T("iff"), _T("Read %d colors from IFF file."), + colors); + + CMAPok = true; // got CMAP + dataptr += 8 + chunkLen; // to next chunk + } else if (strncmp((char *)dataptr, "CAMG", 4) == 0) { // CAMG ? + if (chunkLen < 4 || truncated) { + break; + } + camg_viewmode = iff_getlong(dataptr + 8); // get viewmodes + CAMGok = true; // got CAMG + dataptr += 8 + chunkLen; // to next chunk + } + else if (strncmp((char *)dataptr, "BODY", 4) == 0) { // BODY ? + if (!BMHDok) { // BMHD found? + break; + } + const byte *bodyptr = dataptr + 8; // -> BODY data + + if (truncated) { + chunkLen = dataend - dataptr; + } + + // + // if BODY is compressed, allocate buffer for decrunched BODY + // and decompress it (run length encoding) + // + if (bmhd_compression == 1) { + // calc size of decrunch buffer - (size of the actual pic. + // decompressed in interleaved Amiga bitplane format) + + size_t decomp_bufsize = (((bmhd_width + 15) >> 4) << 1) + * bmhd_height * bmhd_bitplanes; + + if ((decomp_mem = new byte[decomp_bufsize]) == 0) { + Destroy(); + return wxIFF_MEMERR; + } + + decomprle(bodyptr, decomp_mem, chunkLen, decomp_bufsize); + bodyptr = decomp_mem; // -> uncompressed BODY + chunkLen = decomp_bufsize; + delete [] databuf; + databuf = 0; + } + + // the following determines the type of the ILBM file. + // it's either NORMAL, EHB, HAM, HAM8 or 24BIT + + int fmt = ILBM_NORMAL; // assume normal ILBM + if (bmhd_bitplanes == 24) { + fmt = ILBM_24BIT; + } else if (bmhd_bitplanes == 8) { + if (CAMGok && (camg_viewmode & 0x800)) { + fmt = ILBM_HAM8; + } + } else if ((bmhd_bitplanes > 5) && CAMGok) { + if (camg_viewmode & 0x80) { + fmt = ILBM_EHB; + } else if (camg_viewmode & 0x800) { + fmt = ILBM_HAM; + } + } + + wxLogTrace(_T("iff"), + _T("LoadIFF: %s %dx%d, planes=%d (%d cols), comp=%d"), + (fmt==ILBM_NORMAL) ? "Normal ILBM" : + (fmt==ILBM_HAM) ? "HAM ILBM" : + (fmt==ILBM_HAM8) ? "HAM8 ILBM" : + (fmt==ILBM_EHB) ? "EHB ILBM" : + (fmt==ILBM_24BIT) ? "24BIT ILBM" : "unknown ILBM", + bmhd_width, bmhd_height, bmhd_bitplanes, + 1< m_image->colors) { + byte *pal = new byte[colors*3]; + if (!pal) { + Destroy(); + return wxIFF_MEMERR; + } + int i; + for (i = 0; i < m_image->colors; i++) { + pal[3*i + 0] = m_image->pal[3*i + 0]; + pal[3*i + 1] = m_image->pal[3*i + 1]; + pal[3*i + 2] = m_image->pal[3*i + 2]; + } + for (; i < colors; i++) { + pal[3*i + 0] = 0; + pal[3*i + 1] = 0; + pal[3*i + 2] = 0; + } + delete m_image->pal; + m_image->pal = pal; + m_image->colors = colors; + } + + for (int i=0; i < colors; i++) { + m_image->pal[3*i + 0] = (m_image->pal[3*i + 0] >> 4) * 17; + m_image->pal[3*i + 1] = (m_image->pal[3*i + 1] >> 4) * 17; + m_image->pal[3*i + 2] = (m_image->pal[3*i + 2] >> 4) * 17; + } + } + + m_image->p = new byte[bmhd_width * bmhd_height * 3]; + byte *picptr = m_image->p; + if (!picptr) { + Destroy(); + return wxIFF_MEMERR; + } + + byte *pal = m_image->pal; + int lineskip = ((bmhd_width + 15) >> 4) << 1; + int height = chunkLen / (lineskip * bmhd_bitplanes); + + if (bmhd_height < height) { + height = bmhd_height; + } + + if (fmt == ILBM_HAM || fmt == ILBM_HAM8 || fmt == ILBM_24BIT) { + byte *pic = picptr; + const byte *workptr = bodyptr; + + for (int i=0; i < height; i++) { + byte bitmsk = 0x80; + const byte *workptr2 = workptr; + + // at start of each line, init RGB values to background + byte rval = pal[0]; + byte gval = pal[1]; + byte bval = pal[2]; + + for (int j=0; j < bmhd_width; j++) { + long col = 0; + long colbit = 1; + const byte *workptr3 = workptr2; + for (int k=0; k < bmhd_bitplanes; k++) { + if (*workptr3 & bitmsk) { + col += colbit; + } + workptr3 += lineskip; + colbit <<= 1; + } + + if (fmt==ILBM_HAM) { + int c = (col & 0x0f); + switch (col & 0x30) { + case 0x00: if (c >= 0 && c < colors) { + rval = pal[3*c + 0]; + gval = pal[3*c + 1]; + bval = pal[3*c + 2]; + } + break; + + case 0x10: bval = c * 17; + break; + + case 0x20: rval = c * 17; + break; + + case 0x30: gval = c * 17; + break; + } + } else if (fmt == ILBM_HAM8) { + int c = (col & 0x3f); + switch(col & 0xc0) { + case 0x00: if (c >= 0 && c < colors) { + rval = pal[3*c + 0]; + gval = pal[3*c + 1]; + bval = pal[3*c + 2]; + } + break; + + case 0x40: bval = (bval & 3) | (c << 2); + break; + + case 0x80: rval = (rval & 3) | (c << 2); + break; + + case 0xc0: gval = (rval & 3) | (c << 2); + } + } else { + rval = col & 0xff; + gval = (col >> 8) & 0xff; + bval = (col >> 16) & 0xff; + } + + *pic++ = rval; + *pic++ = gval; + *pic++ = bval; + + bitmsk = bitmsk >> 1; + if (bitmsk == 0) { + bitmsk = 0x80; + workptr2++; + } + } + workptr += lineskip * bmhd_bitplanes; + } + } else if ((fmt == ILBM_NORMAL) || (fmt == ILBM_EHB)) { + if (fmt == ILBM_EHB) { + wxLogTrace(_T("iff"), _T("Doubling CMAP for EHB mode")); + + for (int i=0; i<32; i++) { + pal[3*(i + 32) + 0] = pal[3*i + 0] >> 1; + pal[3*(i + 32) + 1] = pal[3*i + 1] >> 1; + pal[3*(i + 32) + 2] = pal[3*i + 2] >> 1; + } + } + + byte *pic = picptr; // ptr to buffer + const byte *workptr = bodyptr; // ptr to pic, planar format + + if (bmhd_height < height) { + height = bmhd_height; + } + + for (int i=0; i < height; i++) { + byte bitmsk = 0x80; // left most bit (mask) + const byte *workptr2 = workptr; // work ptr to source + for (int j=0; j < bmhd_width; j++) { + long col = 0; + long colbit = 1; + const byte *workptr3 = workptr2; // 1st byte in 1st pln + + for (int k=0; k < bmhd_bitplanes; k++) { + if (*workptr3 & bitmsk) { // if bit set in this pln + col = col + colbit; // add bit to chunky byte + } + workptr3 += lineskip; // go to next line + colbit <<= 1; // shift color bit + } + + if (col >= 0 && col < colors) { + pic[0] = pal[3*col + 0]; + pic[1] = pal[3*col + 1]; + pic[2] = pal[3*col + 2]; + } else { + pic[0] = pic[1] = pic[2] = 0; + } + pic += 3; + bitmsk = bitmsk >> 1; // shift mask to next bit + if (bitmsk == 0) { // if mask is zero + bitmsk = 0x80; // reset mask + workptr2++; // mv ptr to next byte + } + } + + workptr += lineskip * bmhd_bitplanes; // to next line + } + } else { + break; // unknown format + } + + m_image->w = bmhd_width; + m_image->h = height; + m_image->transparent = bmhd_transcol; + + wxLogTrace(_T("iff"), _T("Loaded IFF picture %s"), + truncated? "truncated" : "completely"); + + return (truncated? wxIFF_TRUNCATED : wxIFF_OK); + } else { + wxLogTrace(_T("iff"), _T("Skipping unknown chunk '%c%c%c%c'"), + *dataptr, *(dataptr+1), *(dataptr+2), *(dataptr+3)); + + dataptr = dataptr + 8 + chunkLen; // skip unknown chunk + } + } + + Destroy(); + return wxIFF_INVFORMAT; +} + + + +//----------------------------------------------------------------------------- +// wxIFFHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxIFFHandler, wxImageHandler) + +#if wxUSE_STREAMS + +bool wxIFFHandler::LoadFile(wxImage *image, wxInputStream& stream, + bool verbose, int WXUNUSED(index)) +{ + wxIFFDecoder *decod; + int error; + bool ok; + + decod = new wxIFFDecoder(&stream); + error = decod->ReadIFF(); + + if ((error != wxIFF_OK) && (error != wxIFF_TRUNCATED)) + { + if (verbose) + { + switch (error) + { + case wxIFF_INVFORMAT: + wxLogError(_("IFF: error in IFF image format.")); + break; + case wxIFF_MEMERR: + wxLogError(_("IFF: not enough memory.")); + break; + default: + wxLogError(_("IFF: unknown error!!!")); + break; + } + } + delete decod; + return false; + } + + if ((error == wxIFF_TRUNCATED) && verbose) + { + wxLogError(_("IFF: data stream seems to be truncated.")); + /* go on; image data is OK */ + } + + ok = decod->ConvertToImage(image); + delete decod; + + return ok; +} + +bool wxIFFHandler::SaveFile(wxImage * WXUNUSED(image), + wxOutputStream& WXUNUSED(stream), bool verbose) +{ + if (verbose) + wxLogDebug(wxT("IFF: the handler is read-only!!")); + + return false; +} + +bool wxIFFHandler::DoCanRead(wxInputStream& stream) +{ + wxIFFDecoder decod(&stream); + + return decod.CanRead(); +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_IFF diff --git a/Source/3rd Party/wx/src/common/imagjpeg.cpp b/Source/3rd Party/wx/src/common/imagjpeg.cpp index a247d7091..9fb2d4e69 100644 --- a/Source/3rd Party/wx/src/common/imagjpeg.cpp +++ b/Source/3rd Party/wx/src/common/imagjpeg.cpp @@ -1,480 +1,480 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagjpeg.cpp -// Purpose: wxImage JPEG handler -// Author: Vaclav Slavik -// RCS-ID: $Id: imagjpeg.cpp 43781 2006-12-03 21:59:47Z MW $ -// Copyright: (c) Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_LIBJPEG - -#include "wx/imagjpeg.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/app.h" - #include "wx/intl.h" - #include "wx/bitmap.h" - #include "wx/module.h" -#endif - -// A hack based on one from tif_jpeg.c to overcome the problem on Windows -// of rpcndr.h defining boolean with a different type to the jpeg headers. -// -// This hack is only necessary for an external jpeg library, the builtin one -// usually used on Windows doesn't use the type boolean, so always works. -// -#ifdef wxHACK_BOOLEAN - #define HAVE_BOOLEAN - #define boolean wxHACK_BOOLEAN -#endif - -extern "C" -{ - #if defined(__WXMSW__) - #define XMD_H - #endif - #include "jpeglib.h" -} - -#ifndef HAVE_WXJPEG_BOOLEAN -typedef boolean wxjpeg_boolean; -#endif - -#include "wx/filefn.h" -#include "wx/wfstream.h" - -// For memcpy -#include -// For JPEG library error handling -#include - -#ifdef __SALFORDC__ -#undef FAR -#endif - -// ---------------------------------------------------------------------------- -// types -// ---------------------------------------------------------------------------- - -// the standard definition of METHODDEF(type) from jmorecfg.h is "static type" -// which means that we can't declare the method functions as extern "C" - the -// compiler (rightfully) complains about the multiple storage classes in -// declaration -// -// so we only add extern "C" when using our own, modified, jmorecfg.h - and use -// whatever we have in the system headers if this is what we use hoping that it -// should be ok (can't do anything else) -#ifdef JPEG_METHOD_LINKAGE - #define CPP_METHODDEF(type) extern "C" METHODDEF(type) -#else // not using our jmorecfg.h header - #define CPP_METHODDEF(type) METHODDEF(type) -#endif - -//----------------------------------------------------------------------------- -// wxJPEGHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxJPEGHandler,wxImageHandler) - -#if wxUSE_STREAMS - -//------------- JPEG Data Source Manager - -#define JPEG_IO_BUFFER_SIZE 2048 - -typedef struct { - struct jpeg_source_mgr pub; /* public fields */ - - JOCTET* buffer; /* start of buffer */ - wxInputStream *stream; -} wx_source_mgr; - -typedef wx_source_mgr * wx_src_ptr; - -CPP_METHODDEF(void) wx_init_source ( j_decompress_ptr WXUNUSED(cinfo) ) -{ -} - -CPP_METHODDEF(wxjpeg_boolean) wx_fill_input_buffer ( j_decompress_ptr cinfo ) -{ - wx_src_ptr src = (wx_src_ptr) cinfo->src; - - src->pub.next_input_byte = src->buffer; - src->pub.bytes_in_buffer = src->stream->Read(src->buffer, JPEG_IO_BUFFER_SIZE).LastRead(); - - if (src->pub.bytes_in_buffer == 0) // check for end-of-stream - { - // Insert a fake EOI marker - src->buffer[0] = 0xFF; - src->buffer[1] = JPEG_EOI; - src->pub.bytes_in_buffer = 2; - } - return TRUE; -} - -CPP_METHODDEF(void) wx_skip_input_data ( j_decompress_ptr cinfo, long num_bytes ) -{ - if (num_bytes > 0) - { - wx_src_ptr src = (wx_src_ptr) cinfo->src; - - while (num_bytes > (long)src->pub.bytes_in_buffer) - { - num_bytes -= (long) src->pub.bytes_in_buffer; - src->pub.fill_input_buffer(cinfo); - } - src->pub.next_input_byte += (size_t) num_bytes; - src->pub.bytes_in_buffer -= (size_t) num_bytes; - } -} - -CPP_METHODDEF(void) wx_term_source ( j_decompress_ptr cinfo ) -{ - wx_src_ptr src = (wx_src_ptr) cinfo->src; - - if (src->pub.bytes_in_buffer > 0) - src->stream->SeekI(-(long)src->pub.bytes_in_buffer, wxFromCurrent); - delete[] src->buffer; -} - - -// JPEG error manager: - -struct wx_error_mgr { - struct jpeg_error_mgr pub; /* "public" fields */ - - jmp_buf setjmp_buffer; /* for return to caller */ -}; - -typedef struct wx_error_mgr * wx_error_ptr; - -/* - * Here's the routine that will replace the standard error_exit method: - */ - -CPP_METHODDEF(void) wx_error_exit (j_common_ptr cinfo) -{ - /* cinfo->err really points to a wx_error_mgr struct, so coerce pointer */ - wx_error_ptr myerr = (wx_error_ptr) cinfo->err; - - /* Always display the message. */ - /* We could postpone this until after returning, if we chose. */ - (*cinfo->err->output_message) (cinfo); - - /* Return control to the setjmp point */ - longjmp(myerr->setjmp_buffer, 1); -} - -/* - * This will replace the standard output_message method when the user - * wants us to be silent (verbose==false). We must have such method instead of - * simply using NULL for cinfo->err->output_message because it's called - * unconditionally from within libjpeg when there's "garbage input". - */ -CPP_METHODDEF(void) wx_ignore_message (j_common_ptr WXUNUSED(cinfo)) -{ -} - -void wx_jpeg_io_src( j_decompress_ptr cinfo, wxInputStream& infile ) -{ - wx_src_ptr src; - - if (cinfo->src == NULL) { /* first time for this JPEG object? */ - cinfo->src = (struct jpeg_source_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof(wx_source_mgr)); - } - src = (wx_src_ptr) cinfo->src; - src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ - src->buffer = new JOCTET[JPEG_IO_BUFFER_SIZE]; - src->pub.next_input_byte = NULL; /* until buffer loaded */ - src->stream = &infile; - - src->pub.init_source = wx_init_source; - src->pub.fill_input_buffer = wx_fill_input_buffer; - src->pub.skip_input_data = wx_skip_input_data; - src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ - src->pub.term_source = wx_term_source; -} - -static inline void wx_cmyk_to_rgb(unsigned char* rgb, const unsigned char* cmyk) -{ - register int k = 255 - cmyk[3]; - register int k2 = cmyk[3]; - register int c; - - c = k + k2 * (255 - cmyk[0]) / 255; - rgb[0] = (unsigned char)((c > 255) ? 0 : (255 - c)); - - c = k + k2 * (255 - cmyk[1]) / 255; - rgb[1] = (unsigned char)((c > 255) ? 0 : (255 - c)); - - c = k + k2 * (255 - cmyk[2]) / 255; - rgb[2] = (unsigned char)((c > 255) ? 0 : (255 - c)); -} - -// temporarily disable the warning C4611 (interaction between '_setjmp' and -// C++ object destruction is non-portable) - I don't see any dtors here -#ifdef __VISUALC__ - #pragma warning(disable:4611) -#endif /* VC++ */ - -bool wxJPEGHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) ) -{ - struct jpeg_decompress_struct cinfo; - struct wx_error_mgr jerr; - unsigned char *ptr; - - image->Destroy(); - cinfo.err = jpeg_std_error( &jerr.pub ); - jerr.pub.error_exit = wx_error_exit; - - if (!verbose) - cinfo.err->output_message = wx_ignore_message; - - /* Establish the setjmp return context for wx_error_exit to use. */ - if (setjmp(jerr.setjmp_buffer)) { - /* If we get here, the JPEG code has signaled an error. - * We need to clean up the JPEG object, close the input file, and return. - */ - if (verbose) - wxLogError(_("JPEG: Couldn't load - file is probably corrupted.")); - (cinfo.src->term_source)(&cinfo); - jpeg_destroy_decompress(&cinfo); - if (image->Ok()) image->Destroy(); - return false; - } - - jpeg_create_decompress( &cinfo ); - wx_jpeg_io_src( &cinfo, stream ); - jpeg_read_header( &cinfo, TRUE ); - - int bytesPerPixel; - if ((cinfo.out_color_space == JCS_CMYK) || (cinfo.out_color_space == JCS_YCCK)) - { - cinfo.out_color_space = JCS_CMYK; - bytesPerPixel = 4; - } - else // all the rest is treated as RGB - { - cinfo.out_color_space = JCS_RGB; - bytesPerPixel = 3; - } - - jpeg_start_decompress( &cinfo ); - - image->Create( cinfo.image_width, cinfo.image_height ); - if (!image->Ok()) { - jpeg_finish_decompress( &cinfo ); - jpeg_destroy_decompress( &cinfo ); - return false; - } - image->SetMask( false ); - ptr = image->GetData(); - - unsigned stride = cinfo.output_width * bytesPerPixel; - JSAMPARRAY tempbuf = (*cinfo.mem->alloc_sarray) - ((j_common_ptr) &cinfo, JPOOL_IMAGE, stride, 1 ); - - while ( cinfo.output_scanline < cinfo.output_height ) - { - jpeg_read_scanlines( &cinfo, tempbuf, 1 ); - if (cinfo.out_color_space == JCS_RGB) - { - memcpy( ptr, tempbuf[0], stride ); - ptr += stride; - } - else // CMYK - { - const unsigned char* inptr = (const unsigned char*) tempbuf[0]; - for (size_t i = 0; i < cinfo.output_width; i++) - { - wx_cmyk_to_rgb(ptr, inptr); - ptr += 3; - inptr += 4; - } - } - } - - jpeg_finish_decompress( &cinfo ); - jpeg_destroy_decompress( &cinfo ); - return true; -} - -typedef struct { - struct jpeg_destination_mgr pub; - - wxOutputStream *stream; - JOCTET * buffer; -} wx_destination_mgr; - -typedef wx_destination_mgr * wx_dest_ptr; - -#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ - -CPP_METHODDEF(void) wx_init_destination (j_compress_ptr cinfo) -{ - wx_dest_ptr dest = (wx_dest_ptr) cinfo->dest; - - /* Allocate the output buffer --- it will be released when done with image */ - dest->buffer = (JOCTET *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, - OUTPUT_BUF_SIZE * sizeof(JOCTET)); - dest->pub.next_output_byte = dest->buffer; - dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; -} - -CPP_METHODDEF(wxjpeg_boolean) wx_empty_output_buffer (j_compress_ptr cinfo) -{ - wx_dest_ptr dest = (wx_dest_ptr) cinfo->dest; - - dest->stream->Write(dest->buffer, OUTPUT_BUF_SIZE); - dest->pub.next_output_byte = dest->buffer; - dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; - return TRUE; -} - -CPP_METHODDEF(void) wx_term_destination (j_compress_ptr cinfo) -{ - wx_dest_ptr dest = (wx_dest_ptr) cinfo->dest; - size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; - /* Write any data remaining in the buffer */ - if (datacount > 0) - dest->stream->Write(dest->buffer, datacount); -} - -GLOBAL(void) wx_jpeg_io_dest (j_compress_ptr cinfo, wxOutputStream& outfile) -{ - wx_dest_ptr dest; - - if (cinfo->dest == NULL) { /* first time for this JPEG object? */ - cinfo->dest = (struct jpeg_destination_mgr *) - (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, - sizeof(wx_destination_mgr)); - } - - dest = (wx_dest_ptr) cinfo->dest; - dest->pub.init_destination = wx_init_destination; - dest->pub.empty_output_buffer = wx_empty_output_buffer; - dest->pub.term_destination = wx_term_destination; - dest->stream = &outfile; -} - -bool wxJPEGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) -{ - struct jpeg_compress_struct cinfo; - struct wx_error_mgr jerr; - JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ - JSAMPLE *image_buffer; - int stride; /* physical row width in image buffer */ - - cinfo.err = jpeg_std_error(&jerr.pub); - jerr.pub.error_exit = wx_error_exit; - - if (!verbose) - cinfo.err->output_message = wx_ignore_message; - - /* Establish the setjmp return context for wx_error_exit to use. */ - if (setjmp(jerr.setjmp_buffer)) - { - /* If we get here, the JPEG code has signaled an error. - * We need to clean up the JPEG object, close the input file, and return. - */ - if (verbose) - wxLogError(_("JPEG: Couldn't save image.")); - jpeg_destroy_compress(&cinfo); - return false; - } - - jpeg_create_compress(&cinfo); - wx_jpeg_io_dest(&cinfo, stream); - - cinfo.image_width = image->GetWidth(); - cinfo.image_height = image->GetHeight(); - cinfo.input_components = 3; - cinfo.in_color_space = JCS_RGB; - jpeg_set_defaults(&cinfo); - - // TODO: 3rd parameter is force_baseline, what value should this be? - // Code says: "If force_baseline is TRUE, the computed quantization table entries - // are limited to 1..255 for JPEG baseline compatibility." - // 'Quality' is a number between 0 (terrible) and 100 (very good). - // The default (in jcparam.c, jpeg_set_defaults) is 75, - // and force_baseline is TRUE. - if (image->HasOption(wxIMAGE_OPTION_QUALITY)) - jpeg_set_quality(&cinfo, image->GetOptionInt(wxIMAGE_OPTION_QUALITY), TRUE); - - // set the resolution fields in the output file - UINT16 resX, - resY; - if ( image->HasOption(wxIMAGE_OPTION_RESOLUTIONX) && - image->HasOption(wxIMAGE_OPTION_RESOLUTIONY) ) - { - resX = (UINT16)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX); - resY = (UINT16)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY); - } - else if ( image->HasOption(wxIMAGE_OPTION_RESOLUTION) ) - { - resX = - resY = (UINT16)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTION); - } - else - { - resX = - resY = 0; - } - - if ( resX && resY ) - { - cinfo.X_density = resX; - cinfo.Y_density = resY; - } - - // sets the resolution unit field in the output file - // wxIMAGE_RESOLUTION_INCHES for inches - // wxIMAGE_RESOLUTION_CM for centimeters - if ( image->HasOption(wxIMAGE_OPTION_RESOLUTIONUNIT) ) - { - cinfo.density_unit = (UINT8)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONUNIT); - } - - jpeg_start_compress(&cinfo, TRUE); - - stride = cinfo.image_width * 3; /* JSAMPLEs per row in image_buffer */ - image_buffer = image->GetData(); - while (cinfo.next_scanline < cinfo.image_height) { - row_pointer[0] = &image_buffer[cinfo.next_scanline * stride]; - jpeg_write_scanlines( &cinfo, row_pointer, 1 ); - } - jpeg_finish_compress(&cinfo); - jpeg_destroy_compress(&cinfo); - - return true; -} - -#ifdef __VISUALC__ - #pragma warning(default:4611) -#endif /* VC++ */ - -bool wxJPEGHandler::DoCanRead( wxInputStream& stream ) -{ - unsigned char hdr[2]; - - if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) - return false; - - return hdr[0] == 0xFF && hdr[1] == 0xD8; -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_LIBJPEG +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagjpeg.cpp +// Purpose: wxImage JPEG handler +// Author: Vaclav Slavik +// RCS-ID: $Id: imagjpeg.cpp 43781 2006-12-03 21:59:47Z MW $ +// Copyright: (c) Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_LIBJPEG + +#include "wx/imagjpeg.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/bitmap.h" + #include "wx/module.h" +#endif + +// A hack based on one from tif_jpeg.c to overcome the problem on Windows +// of rpcndr.h defining boolean with a different type to the jpeg headers. +// +// This hack is only necessary for an external jpeg library, the builtin one +// usually used on Windows doesn't use the type boolean, so always works. +// +#ifdef wxHACK_BOOLEAN + #define HAVE_BOOLEAN + #define boolean wxHACK_BOOLEAN +#endif + +extern "C" +{ + #if defined(__WXMSW__) + #define XMD_H + #endif + #include "jpeglib.h" +} + +#ifndef HAVE_WXJPEG_BOOLEAN +typedef boolean wxjpeg_boolean; +#endif + +#include "wx/filefn.h" +#include "wx/wfstream.h" + +// For memcpy +#include +// For JPEG library error handling +#include + +#ifdef __SALFORDC__ +#undef FAR +#endif + +// ---------------------------------------------------------------------------- +// types +// ---------------------------------------------------------------------------- + +// the standard definition of METHODDEF(type) from jmorecfg.h is "static type" +// which means that we can't declare the method functions as extern "C" - the +// compiler (rightfully) complains about the multiple storage classes in +// declaration +// +// so we only add extern "C" when using our own, modified, jmorecfg.h - and use +// whatever we have in the system headers if this is what we use hoping that it +// should be ok (can't do anything else) +#ifdef JPEG_METHOD_LINKAGE + #define CPP_METHODDEF(type) extern "C" METHODDEF(type) +#else // not using our jmorecfg.h header + #define CPP_METHODDEF(type) METHODDEF(type) +#endif + +//----------------------------------------------------------------------------- +// wxJPEGHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxJPEGHandler,wxImageHandler) + +#if wxUSE_STREAMS + +//------------- JPEG Data Source Manager + +#define JPEG_IO_BUFFER_SIZE 2048 + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + + JOCTET* buffer; /* start of buffer */ + wxInputStream *stream; +} wx_source_mgr; + +typedef wx_source_mgr * wx_src_ptr; + +CPP_METHODDEF(void) wx_init_source ( j_decompress_ptr WXUNUSED(cinfo) ) +{ +} + +CPP_METHODDEF(wxjpeg_boolean) wx_fill_input_buffer ( j_decompress_ptr cinfo ) +{ + wx_src_ptr src = (wx_src_ptr) cinfo->src; + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = src->stream->Read(src->buffer, JPEG_IO_BUFFER_SIZE).LastRead(); + + if (src->pub.bytes_in_buffer == 0) // check for end-of-stream + { + // Insert a fake EOI marker + src->buffer[0] = 0xFF; + src->buffer[1] = JPEG_EOI; + src->pub.bytes_in_buffer = 2; + } + return TRUE; +} + +CPP_METHODDEF(void) wx_skip_input_data ( j_decompress_ptr cinfo, long num_bytes ) +{ + if (num_bytes > 0) + { + wx_src_ptr src = (wx_src_ptr) cinfo->src; + + while (num_bytes > (long)src->pub.bytes_in_buffer) + { + num_bytes -= (long) src->pub.bytes_in_buffer; + src->pub.fill_input_buffer(cinfo); + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + +CPP_METHODDEF(void) wx_term_source ( j_decompress_ptr cinfo ) +{ + wx_src_ptr src = (wx_src_ptr) cinfo->src; + + if (src->pub.bytes_in_buffer > 0) + src->stream->SeekI(-(long)src->pub.bytes_in_buffer, wxFromCurrent); + delete[] src->buffer; +} + + +// JPEG error manager: + +struct wx_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + + jmp_buf setjmp_buffer; /* for return to caller */ +}; + +typedef struct wx_error_mgr * wx_error_ptr; + +/* + * Here's the routine that will replace the standard error_exit method: + */ + +CPP_METHODDEF(void) wx_error_exit (j_common_ptr cinfo) +{ + /* cinfo->err really points to a wx_error_mgr struct, so coerce pointer */ + wx_error_ptr myerr = (wx_error_ptr) cinfo->err; + + /* Always display the message. */ + /* We could postpone this until after returning, if we chose. */ + (*cinfo->err->output_message) (cinfo); + + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); +} + +/* + * This will replace the standard output_message method when the user + * wants us to be silent (verbose==false). We must have such method instead of + * simply using NULL for cinfo->err->output_message because it's called + * unconditionally from within libjpeg when there's "garbage input". + */ +CPP_METHODDEF(void) wx_ignore_message (j_common_ptr WXUNUSED(cinfo)) +{ +} + +void wx_jpeg_io_src( j_decompress_ptr cinfo, wxInputStream& infile ) +{ + wx_src_ptr src; + + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(wx_source_mgr)); + } + src = (wx_src_ptr) cinfo->src; + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->buffer = new JOCTET[JPEG_IO_BUFFER_SIZE]; + src->pub.next_input_byte = NULL; /* until buffer loaded */ + src->stream = &infile; + + src->pub.init_source = wx_init_source; + src->pub.fill_input_buffer = wx_fill_input_buffer; + src->pub.skip_input_data = wx_skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = wx_term_source; +} + +static inline void wx_cmyk_to_rgb(unsigned char* rgb, const unsigned char* cmyk) +{ + register int k = 255 - cmyk[3]; + register int k2 = cmyk[3]; + register int c; + + c = k + k2 * (255 - cmyk[0]) / 255; + rgb[0] = (unsigned char)((c > 255) ? 0 : (255 - c)); + + c = k + k2 * (255 - cmyk[1]) / 255; + rgb[1] = (unsigned char)((c > 255) ? 0 : (255 - c)); + + c = k + k2 * (255 - cmyk[2]) / 255; + rgb[2] = (unsigned char)((c > 255) ? 0 : (255 - c)); +} + +// temporarily disable the warning C4611 (interaction between '_setjmp' and +// C++ object destruction is non-portable) - I don't see any dtors here +#ifdef __VISUALC__ + #pragma warning(disable:4611) +#endif /* VC++ */ + +bool wxJPEGHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) ) +{ + struct jpeg_decompress_struct cinfo; + struct wx_error_mgr jerr; + unsigned char *ptr; + + image->Destroy(); + cinfo.err = jpeg_std_error( &jerr.pub ); + jerr.pub.error_exit = wx_error_exit; + + if (!verbose) + cinfo.err->output_message = wx_ignore_message; + + /* Establish the setjmp return context for wx_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + if (verbose) + wxLogError(_("JPEG: Couldn't load - file is probably corrupted.")); + (cinfo.src->term_source)(&cinfo); + jpeg_destroy_decompress(&cinfo); + if (image->Ok()) image->Destroy(); + return false; + } + + jpeg_create_decompress( &cinfo ); + wx_jpeg_io_src( &cinfo, stream ); + jpeg_read_header( &cinfo, TRUE ); + + int bytesPerPixel; + if ((cinfo.out_color_space == JCS_CMYK) || (cinfo.out_color_space == JCS_YCCK)) + { + cinfo.out_color_space = JCS_CMYK; + bytesPerPixel = 4; + } + else // all the rest is treated as RGB + { + cinfo.out_color_space = JCS_RGB; + bytesPerPixel = 3; + } + + jpeg_start_decompress( &cinfo ); + + image->Create( cinfo.image_width, cinfo.image_height ); + if (!image->Ok()) { + jpeg_finish_decompress( &cinfo ); + jpeg_destroy_decompress( &cinfo ); + return false; + } + image->SetMask( false ); + ptr = image->GetData(); + + unsigned stride = cinfo.output_width * bytesPerPixel; + JSAMPARRAY tempbuf = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, stride, 1 ); + + while ( cinfo.output_scanline < cinfo.output_height ) + { + jpeg_read_scanlines( &cinfo, tempbuf, 1 ); + if (cinfo.out_color_space == JCS_RGB) + { + memcpy( ptr, tempbuf[0], stride ); + ptr += stride; + } + else // CMYK + { + const unsigned char* inptr = (const unsigned char*) tempbuf[0]; + for (size_t i = 0; i < cinfo.output_width; i++) + { + wx_cmyk_to_rgb(ptr, inptr); + ptr += 3; + inptr += 4; + } + } + } + + jpeg_finish_decompress( &cinfo ); + jpeg_destroy_decompress( &cinfo ); + return true; +} + +typedef struct { + struct jpeg_destination_mgr pub; + + wxOutputStream *stream; + JOCTET * buffer; +} wx_destination_mgr; + +typedef wx_destination_mgr * wx_dest_ptr; + +#define OUTPUT_BUF_SIZE 4096 /* choose an efficiently fwrite'able size */ + +CPP_METHODDEF(void) wx_init_destination (j_compress_ptr cinfo) +{ + wx_dest_ptr dest = (wx_dest_ptr) cinfo->dest; + + /* Allocate the output buffer --- it will be released when done with image */ + dest->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + OUTPUT_BUF_SIZE * sizeof(JOCTET)); + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; +} + +CPP_METHODDEF(wxjpeg_boolean) wx_empty_output_buffer (j_compress_ptr cinfo) +{ + wx_dest_ptr dest = (wx_dest_ptr) cinfo->dest; + + dest->stream->Write(dest->buffer, OUTPUT_BUF_SIZE); + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = OUTPUT_BUF_SIZE; + return TRUE; +} + +CPP_METHODDEF(void) wx_term_destination (j_compress_ptr cinfo) +{ + wx_dest_ptr dest = (wx_dest_ptr) cinfo->dest; + size_t datacount = OUTPUT_BUF_SIZE - dest->pub.free_in_buffer; + /* Write any data remaining in the buffer */ + if (datacount > 0) + dest->stream->Write(dest->buffer, datacount); +} + +GLOBAL(void) wx_jpeg_io_dest (j_compress_ptr cinfo, wxOutputStream& outfile) +{ + wx_dest_ptr dest; + + if (cinfo->dest == NULL) { /* first time for this JPEG object? */ + cinfo->dest = (struct jpeg_destination_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + sizeof(wx_destination_mgr)); + } + + dest = (wx_dest_ptr) cinfo->dest; + dest->pub.init_destination = wx_init_destination; + dest->pub.empty_output_buffer = wx_empty_output_buffer; + dest->pub.term_destination = wx_term_destination; + dest->stream = &outfile; +} + +bool wxJPEGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) +{ + struct jpeg_compress_struct cinfo; + struct wx_error_mgr jerr; + JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ + JSAMPLE *image_buffer; + int stride; /* physical row width in image buffer */ + + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = wx_error_exit; + + if (!verbose) + cinfo.err->output_message = wx_ignore_message; + + /* Establish the setjmp return context for wx_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) + { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + if (verbose) + wxLogError(_("JPEG: Couldn't save image.")); + jpeg_destroy_compress(&cinfo); + return false; + } + + jpeg_create_compress(&cinfo); + wx_jpeg_io_dest(&cinfo, stream); + + cinfo.image_width = image->GetWidth(); + cinfo.image_height = image->GetHeight(); + cinfo.input_components = 3; + cinfo.in_color_space = JCS_RGB; + jpeg_set_defaults(&cinfo); + + // TODO: 3rd parameter is force_baseline, what value should this be? + // Code says: "If force_baseline is TRUE, the computed quantization table entries + // are limited to 1..255 for JPEG baseline compatibility." + // 'Quality' is a number between 0 (terrible) and 100 (very good). + // The default (in jcparam.c, jpeg_set_defaults) is 75, + // and force_baseline is TRUE. + if (image->HasOption(wxIMAGE_OPTION_QUALITY)) + jpeg_set_quality(&cinfo, image->GetOptionInt(wxIMAGE_OPTION_QUALITY), TRUE); + + // set the resolution fields in the output file + UINT16 resX, + resY; + if ( image->HasOption(wxIMAGE_OPTION_RESOLUTIONX) && + image->HasOption(wxIMAGE_OPTION_RESOLUTIONY) ) + { + resX = (UINT16)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX); + resY = (UINT16)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY); + } + else if ( image->HasOption(wxIMAGE_OPTION_RESOLUTION) ) + { + resX = + resY = (UINT16)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTION); + } + else + { + resX = + resY = 0; + } + + if ( resX && resY ) + { + cinfo.X_density = resX; + cinfo.Y_density = resY; + } + + // sets the resolution unit field in the output file + // wxIMAGE_RESOLUTION_INCHES for inches + // wxIMAGE_RESOLUTION_CM for centimeters + if ( image->HasOption(wxIMAGE_OPTION_RESOLUTIONUNIT) ) + { + cinfo.density_unit = (UINT8)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONUNIT); + } + + jpeg_start_compress(&cinfo, TRUE); + + stride = cinfo.image_width * 3; /* JSAMPLEs per row in image_buffer */ + image_buffer = image->GetData(); + while (cinfo.next_scanline < cinfo.image_height) { + row_pointer[0] = &image_buffer[cinfo.next_scanline * stride]; + jpeg_write_scanlines( &cinfo, row_pointer, 1 ); + } + jpeg_finish_compress(&cinfo); + jpeg_destroy_compress(&cinfo); + + return true; +} + +#ifdef __VISUALC__ + #pragma warning(default:4611) +#endif /* VC++ */ + +bool wxJPEGHandler::DoCanRead( wxInputStream& stream ) +{ + unsigned char hdr[2]; + + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + return hdr[0] == 0xFF && hdr[1] == 0xD8; +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_LIBJPEG diff --git a/Source/3rd Party/wx/src/common/imagpcx.cpp b/Source/3rd Party/wx/src/common/imagpcx.cpp index 2319f6638..d77be9b83 100644 --- a/Source/3rd Party/wx/src/common/imagpcx.cpp +++ b/Source/3rd Party/wx/src/common/imagpcx.cpp @@ -1,500 +1,500 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagpcx.cpp -// Purpose: wxImage PCX handler -// Author: Guillermo Rodriguez Garcia -// Version: 1.1 -// CVS-ID: $Id: imagpcx.cpp 54766 2008-07-22 20:16:03Z VZ $ -// Copyright: (c) 1999 Guillermo Rodriguez Garcia -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_PCX - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/list.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/palette.h" - #include "wx/hash.h" - #include "wx/module.h" -#endif - -#include "wx/imagpcx.h" -#include "wx/wfstream.h" - -//----------------------------------------------------------------------------- -// wxPCXHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxPCXHandler,wxImageHandler) - -#if wxUSE_STREAMS - -//----------------------------------------------------------------------------- -// RLE encoding and decoding -//----------------------------------------------------------------------------- - -void RLEencode(unsigned char *p, unsigned int size, wxOutputStream& s) -{ - unsigned int data, last, cont; - - // Write 'size' bytes. The PCX official specs say there will be - // a decoding break at the end of each scanline, so in order to - // force this decoding break use this function to write, at most, - // _one_ complete scanline at a time. - - last = (unsigned char) *(p++); - cont = 1; - size--; - - while (size-- > 0) - { - data = (unsigned char) *(p++); - - // Up to 63 bytes with the same value can be stored using - // a single { cont, value } pair. - // - if ((data == last) && (cont < 63)) - { - cont++; - } - else - { - // need to write a 'counter' byte? - if ((cont > 1) || ((last & 0xC0) == 0xC0)) - s.PutC((char) (cont | 0xC0)); - - s.PutC((char) last); - last = data; - cont = 1; - } - } - - // write the last one and return; - if ((cont > 1) || ((last & 0xC0) == 0xC0)) - s.PutC((char) (cont | 0xC0)); - - s.PutC((char) last); -} - -void RLEdecode(unsigned char *p, unsigned int size, wxInputStream& s) -{ - // Read 'size' bytes. The PCX official specs say there will be - // a decoding break at the end of each scanline (but not at the - // end of each plane inside a scanline). Only use this function - // to read one or more _complete_ scanlines. Else, more than - // 'size' bytes might be read and the buffer might overflow. - - while (size != 0) - { - unsigned int data = (unsigned char)s.GetC(); - - // If ((data & 0xC0) != 0xC0), then the value read is a data - // byte. Else, it is a counter (cont = val & 0x3F) and the - // next byte is the data byte. - - if ((data & 0xC0) != 0xC0) - { - *(p++) = (unsigned char)data; - size--; - } - else - { - unsigned int cont = data & 0x3F; - if (cont > size) // can happen only if the file is malformed - break; - data = (unsigned char)s.GetC(); - for (unsigned int i = 1; i <= cont; i++) - *(p++) = (unsigned char)data; - size -= cont; - } - } -} - - -//----------------------------------------------------------------------------- -// PCX reading and saving -//----------------------------------------------------------------------------- - -// PCX header -#define HDR_MANUFACTURER 0 -#define HDR_VERSION 1 -#define HDR_ENCODING 2 -#define HDR_BITSPERPIXEL 3 -#define HDR_XMIN 4 -#define HDR_YMIN 6 -#define HDR_XMAX 8 -#define HDR_YMAX 10 -#define HDR_NPLANES 65 -#define HDR_BYTESPERLINE 66 -#define HDR_PALETTEINFO 68 - -// image formats -enum { - wxPCX_8BIT, // 8 bpp, 1 plane (8 bit) - wxPCX_24BIT // 8 bpp, 3 planes (24 bit) -}; - -// error codes -enum { - wxPCX_OK = 0, // everything was OK - wxPCX_INVFORMAT = 1, // error in pcx file format - wxPCX_MEMERR = 2, // error allocating memory - wxPCX_VERERR = 3 // error in pcx version number -}; - - -// ReadPCX: -// Loads a PCX file into the wxImage object pointed by image. -// Returns wxPCX_OK on success, or an error code otherwise -// (see above for error codes) -// -int ReadPCX(wxImage *image, wxInputStream& stream) -{ - unsigned char hdr[128]; // PCX header - unsigned char pal[768]; // palette for 8 bit images - unsigned char *p; // space to store one scanline - unsigned char *dst; // pointer into wxImage data - unsigned int width, height; // size of the image - unsigned int bytesperline; // bytes per line (each plane) - int bitsperpixel; // bits per pixel (each plane) - int nplanes; // number of planes - int encoding; // is the image RLE encoded? - int format; // image format (8 bit, 24 bit) - unsigned int i, j; - - // Read PCX header and check the version number (it must - // be at least 5 or higher for 8 bit and 24 bit images). - - stream.Read(hdr, 128); - - if (hdr[HDR_VERSION] < 5) return wxPCX_VERERR; - - // Extract all image info from the PCX header. - - encoding = hdr[HDR_ENCODING]; - nplanes = hdr[HDR_NPLANES]; - bitsperpixel = hdr[HDR_BITSPERPIXEL]; - bytesperline = hdr[HDR_BYTESPERLINE] + 256 * hdr[HDR_BYTESPERLINE + 1]; - width = (hdr[HDR_XMAX] + 256 * hdr[HDR_XMAX + 1]) - - (hdr[HDR_XMIN] + 256 * hdr[HDR_XMIN + 1]) + 1; - height = (hdr[HDR_YMAX] + 256 * hdr[HDR_YMAX + 1]) - - (hdr[HDR_YMIN] + 256 * hdr[HDR_YMIN + 1]) + 1; - - // Check image format. Currently supported formats are - // 8 bits (8 bpp, 1 plane) and 24 bits (8 bpp, 3 planes). - - if ((nplanes == 3) && (bitsperpixel == 8)) - format = wxPCX_24BIT; - else if ((nplanes == 1) && (bitsperpixel == 8)) - format = wxPCX_8BIT; - else - return wxPCX_INVFORMAT; - - // If the image is of type wxPCX_8BIT, then there is - // a palette at the end of the image data. If we were - // working with a file, we could seek at the end to the - // end (SeekI(-769, wxFromEnd) and read the palette - // before proceeding. Unfortunately, this would prevent - // loading several PCXs in a single stream, so we can't - // do it. Thus, 8-bit images will have to be decoded in - // two passes: one to read and decode the image data, - // and another to replace 'colour indexes' with RGB - // values. - - // Resize the image and allocate memory for a scanline. - - image->Create(width, height); - - if (!image->Ok()) - return wxPCX_MEMERR; - - if ((p = (unsigned char *) malloc(bytesperline * nplanes)) == NULL) - return wxPCX_MEMERR; - - // Now start reading the file, line by line, and store - // the data in the format required by wxImage. - - dst = image->GetData(); - - for (j = height; j; j--) - { - if (encoding) - RLEdecode(p, bytesperline * nplanes, stream); - else - stream.Read(p, bytesperline * nplanes); - - switch (format) - { - case wxPCX_8BIT: - { - for (i = 0; i < width; i++) - { - // first pass, just store the colour index - *dst = p[i]; - dst += 3; - } - break; - } - case wxPCX_24BIT: - { - for (i = 0; i < width; i++) - { - *(dst++) = p[i]; - *(dst++) = p[i + bytesperline]; - *(dst++) = p[i + 2 * bytesperline]; - } - break; - } - } - } - - free(p); - - // For 8 bit images, we read the palette, and then do a second - // pass replacing indexes with their RGB values; - - if (format == wxPCX_8BIT) - { - unsigned char index; - - if (stream.GetC() != 12) - return wxPCX_INVFORMAT; - - stream.Read(pal, 768); - - p = image->GetData(); - for (unsigned long k = height * width; k; k--) - { - index = *p; - *(p++) = pal[3 * index]; - *(p++) = pal[3 * index + 1]; - *(p++) = pal[3 * index + 2]; - } - -#if wxUSE_PALETTE - unsigned char r[256]; - unsigned char g[256]; - unsigned char b[256]; - for (i = 0; i < 256; i++) - { - r[i] = pal[3*i + 0]; - g[i] = pal[3*i + 1]; - b[i] = pal[3*i + 2]; - } - image->SetPalette(wxPalette(256, r, g, b)); -#endif // wxUSE_PALETTE - } - - return wxPCX_OK; -} - -// SavePCX: -// Saves a PCX file into the wxImage object pointed by image. -// Returns wxPCX_OK on success, or an error code otherwise -// (see above for error codes). Will try to save as 8-bit -// PCX if possible, and then fall back to 24-bit if there -// are more than 256 different colours. -// -int SavePCX(wxImage *image, wxOutputStream& stream) -{ - unsigned char hdr[128]; // PCX header - unsigned char pal[768]; // palette for 8 bit images - unsigned char *p; // space to store one scanline - unsigned char *src; // pointer into wxImage data - unsigned int width, height; // size of the image - unsigned int bytesperline; // bytes per line (each plane) - unsigned char nplanes = 3; // number of planes - int format = wxPCX_24BIT; // image format (8 bit, 24 bit) - wxImageHistogram histogram; // image histogram - unsigned long key; // key in the hashtable - unsigned int i; - - // See if we can save as 8 bit. - - if (image->CountColours(256) <= 256) - { - image->ComputeHistogram(histogram); - format = wxPCX_8BIT; - nplanes = 1; - } - - // Get image dimensions, calculate bytesperline (must be even, - // according to PCX specs) and allocate space for one complete - // scanline. - - if (!image->Ok()) - return wxPCX_INVFORMAT; - - width = image->GetWidth(); - height = image->GetHeight(); - bytesperline = width; - if (bytesperline % 2) - bytesperline++; - - if ((p = (unsigned char *) malloc(bytesperline * nplanes)) == NULL) - return wxPCX_MEMERR; - - // Build header data and write it to the stream. Initially, - // set all bytes to zero (most values default to zero). - - memset(hdr, 0, sizeof(hdr)); - - hdr[HDR_MANUFACTURER] = 10; - hdr[HDR_VERSION] = 5; - hdr[HDR_ENCODING] = 1; - hdr[HDR_NPLANES] = nplanes; - hdr[HDR_BITSPERPIXEL] = 8; - hdr[HDR_BYTESPERLINE] = (unsigned char)(bytesperline % 256); - hdr[HDR_BYTESPERLINE + 1] = (unsigned char)(bytesperline / 256); - hdr[HDR_XMAX] = (unsigned char)((width - 1) % 256); - hdr[HDR_XMAX + 1] = (unsigned char)((width - 1) / 256); - hdr[HDR_YMAX] = (unsigned char)((height - 1) % 256); - hdr[HDR_YMAX + 1] = (unsigned char)((height - 1) / 256); - hdr[HDR_PALETTEINFO] = 1; - - stream.Write(hdr, 128); - - // Encode image data line by line and write it to the stream - - src = image->GetData(); - - for (; height; height--) - { - switch (format) - { - case wxPCX_8BIT: - { - unsigned char r, g, b; - - for (i = 0; i < width; i++) - { - r = *(src++); - g = *(src++); - b = *(src++); - key = (r << 16) | (g << 8) | b; - - p[i] = (unsigned char)histogram[key].index; - } - break; - } - case wxPCX_24BIT: - { - for (i = 0; i < width; i++) - { - p[i] = *(src++); - p[i + bytesperline] = *(src++); - p[i + 2 * bytesperline] = *(src++); - } - break; - } - } - - RLEencode(p, bytesperline * nplanes, stream); - } - - free(p); - - // For 8 bit images, build the palette and write it to the stream: - if (format == wxPCX_8BIT) - { - // zero unused colours - memset(pal, 0, sizeof(pal)); - - unsigned long index; - - for (wxImageHistogram::iterator entry = histogram.begin(); - entry != histogram.end(); ++entry ) - { - key = entry->first; - index = entry->second.index; - pal[3 * index] = (unsigned char)(key >> 16); - pal[3 * index + 1] = (unsigned char)(key >> 8); - pal[3 * index + 2] = (unsigned char)(key); - } - - stream.PutC(12); - stream.Write(pal, 768); - } - - return wxPCX_OK; -} - -//----------------------------------------------------------------------------- -// wxPCXHandler -//----------------------------------------------------------------------------- - -bool wxPCXHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) ) -{ - int error; - - if (!CanRead(stream)) - { - if (verbose) - wxLogError(_("PCX: this is not a PCX file.")); - - return false; - } - - image->Destroy(); - - if ((error = ReadPCX(image, stream)) != wxPCX_OK) - { - if (verbose) - { - switch (error) - { - case wxPCX_INVFORMAT: wxLogError(_("PCX: image format unsupported")); break; - case wxPCX_MEMERR: wxLogError(_("PCX: couldn't allocate memory")); break; - case wxPCX_VERERR: wxLogError(_("PCX: version number too low")); break; - default: wxLogError(_("PCX: unknown error !!!")); - } - } - image->Destroy(); - return false; - } - - return true; -} - -bool wxPCXHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) -{ - int error; - - if ((error = SavePCX(image, stream)) != wxPCX_OK) - { - if (verbose) - { - switch (error) - { - case wxPCX_INVFORMAT: wxLogError(_("PCX: invalid image")); break; - case wxPCX_MEMERR: wxLogError(_("PCX: couldn't allocate memory")); break; - default: wxLogError(_("PCX: unknown error !!!")); - } - } - } - - return (error == wxPCX_OK); -} - -bool wxPCXHandler::DoCanRead( wxInputStream& stream ) -{ - unsigned char c = stream.GetC(); - if ( !stream ) - return false; - - // not very safe, but this is all we can get from PCX header :-( - return c == 10; -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_IMAGE && wxUSE_PCX +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagpcx.cpp +// Purpose: wxImage PCX handler +// Author: Guillermo Rodriguez Garcia +// Version: 1.1 +// CVS-ID: $Id: imagpcx.cpp 54766 2008-07-22 20:16:03Z VZ $ +// Copyright: (c) 1999 Guillermo Rodriguez Garcia +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_PCX + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/list.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/palette.h" + #include "wx/hash.h" + #include "wx/module.h" +#endif + +#include "wx/imagpcx.h" +#include "wx/wfstream.h" + +//----------------------------------------------------------------------------- +// wxPCXHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxPCXHandler,wxImageHandler) + +#if wxUSE_STREAMS + +//----------------------------------------------------------------------------- +// RLE encoding and decoding +//----------------------------------------------------------------------------- + +void RLEencode(unsigned char *p, unsigned int size, wxOutputStream& s) +{ + unsigned int data, last, cont; + + // Write 'size' bytes. The PCX official specs say there will be + // a decoding break at the end of each scanline, so in order to + // force this decoding break use this function to write, at most, + // _one_ complete scanline at a time. + + last = (unsigned char) *(p++); + cont = 1; + size--; + + while (size-- > 0) + { + data = (unsigned char) *(p++); + + // Up to 63 bytes with the same value can be stored using + // a single { cont, value } pair. + // + if ((data == last) && (cont < 63)) + { + cont++; + } + else + { + // need to write a 'counter' byte? + if ((cont > 1) || ((last & 0xC0) == 0xC0)) + s.PutC((char) (cont | 0xC0)); + + s.PutC((char) last); + last = data; + cont = 1; + } + } + + // write the last one and return; + if ((cont > 1) || ((last & 0xC0) == 0xC0)) + s.PutC((char) (cont | 0xC0)); + + s.PutC((char) last); +} + +void RLEdecode(unsigned char *p, unsigned int size, wxInputStream& s) +{ + // Read 'size' bytes. The PCX official specs say there will be + // a decoding break at the end of each scanline (but not at the + // end of each plane inside a scanline). Only use this function + // to read one or more _complete_ scanlines. Else, more than + // 'size' bytes might be read and the buffer might overflow. + + while (size != 0) + { + unsigned int data = (unsigned char)s.GetC(); + + // If ((data & 0xC0) != 0xC0), then the value read is a data + // byte. Else, it is a counter (cont = val & 0x3F) and the + // next byte is the data byte. + + if ((data & 0xC0) != 0xC0) + { + *(p++) = (unsigned char)data; + size--; + } + else + { + unsigned int cont = data & 0x3F; + if (cont > size) // can happen only if the file is malformed + break; + data = (unsigned char)s.GetC(); + for (unsigned int i = 1; i <= cont; i++) + *(p++) = (unsigned char)data; + size -= cont; + } + } +} + + +//----------------------------------------------------------------------------- +// PCX reading and saving +//----------------------------------------------------------------------------- + +// PCX header +#define HDR_MANUFACTURER 0 +#define HDR_VERSION 1 +#define HDR_ENCODING 2 +#define HDR_BITSPERPIXEL 3 +#define HDR_XMIN 4 +#define HDR_YMIN 6 +#define HDR_XMAX 8 +#define HDR_YMAX 10 +#define HDR_NPLANES 65 +#define HDR_BYTESPERLINE 66 +#define HDR_PALETTEINFO 68 + +// image formats +enum { + wxPCX_8BIT, // 8 bpp, 1 plane (8 bit) + wxPCX_24BIT // 8 bpp, 3 planes (24 bit) +}; + +// error codes +enum { + wxPCX_OK = 0, // everything was OK + wxPCX_INVFORMAT = 1, // error in pcx file format + wxPCX_MEMERR = 2, // error allocating memory + wxPCX_VERERR = 3 // error in pcx version number +}; + + +// ReadPCX: +// Loads a PCX file into the wxImage object pointed by image. +// Returns wxPCX_OK on success, or an error code otherwise +// (see above for error codes) +// +int ReadPCX(wxImage *image, wxInputStream& stream) +{ + unsigned char hdr[128]; // PCX header + unsigned char pal[768]; // palette for 8 bit images + unsigned char *p; // space to store one scanline + unsigned char *dst; // pointer into wxImage data + unsigned int width, height; // size of the image + unsigned int bytesperline; // bytes per line (each plane) + int bitsperpixel; // bits per pixel (each plane) + int nplanes; // number of planes + int encoding; // is the image RLE encoded? + int format; // image format (8 bit, 24 bit) + unsigned int i, j; + + // Read PCX header and check the version number (it must + // be at least 5 or higher for 8 bit and 24 bit images). + + stream.Read(hdr, 128); + + if (hdr[HDR_VERSION] < 5) return wxPCX_VERERR; + + // Extract all image info from the PCX header. + + encoding = hdr[HDR_ENCODING]; + nplanes = hdr[HDR_NPLANES]; + bitsperpixel = hdr[HDR_BITSPERPIXEL]; + bytesperline = hdr[HDR_BYTESPERLINE] + 256 * hdr[HDR_BYTESPERLINE + 1]; + width = (hdr[HDR_XMAX] + 256 * hdr[HDR_XMAX + 1]) - + (hdr[HDR_XMIN] + 256 * hdr[HDR_XMIN + 1]) + 1; + height = (hdr[HDR_YMAX] + 256 * hdr[HDR_YMAX + 1]) - + (hdr[HDR_YMIN] + 256 * hdr[HDR_YMIN + 1]) + 1; + + // Check image format. Currently supported formats are + // 8 bits (8 bpp, 1 plane) and 24 bits (8 bpp, 3 planes). + + if ((nplanes == 3) && (bitsperpixel == 8)) + format = wxPCX_24BIT; + else if ((nplanes == 1) && (bitsperpixel == 8)) + format = wxPCX_8BIT; + else + return wxPCX_INVFORMAT; + + // If the image is of type wxPCX_8BIT, then there is + // a palette at the end of the image data. If we were + // working with a file, we could seek at the end to the + // end (SeekI(-769, wxFromEnd) and read the palette + // before proceeding. Unfortunately, this would prevent + // loading several PCXs in a single stream, so we can't + // do it. Thus, 8-bit images will have to be decoded in + // two passes: one to read and decode the image data, + // and another to replace 'colour indexes' with RGB + // values. + + // Resize the image and allocate memory for a scanline. + + image->Create(width, height); + + if (!image->Ok()) + return wxPCX_MEMERR; + + if ((p = (unsigned char *) malloc(bytesperline * nplanes)) == NULL) + return wxPCX_MEMERR; + + // Now start reading the file, line by line, and store + // the data in the format required by wxImage. + + dst = image->GetData(); + + for (j = height; j; j--) + { + if (encoding) + RLEdecode(p, bytesperline * nplanes, stream); + else + stream.Read(p, bytesperline * nplanes); + + switch (format) + { + case wxPCX_8BIT: + { + for (i = 0; i < width; i++) + { + // first pass, just store the colour index + *dst = p[i]; + dst += 3; + } + break; + } + case wxPCX_24BIT: + { + for (i = 0; i < width; i++) + { + *(dst++) = p[i]; + *(dst++) = p[i + bytesperline]; + *(dst++) = p[i + 2 * bytesperline]; + } + break; + } + } + } + + free(p); + + // For 8 bit images, we read the palette, and then do a second + // pass replacing indexes with their RGB values; + + if (format == wxPCX_8BIT) + { + unsigned char index; + + if (stream.GetC() != 12) + return wxPCX_INVFORMAT; + + stream.Read(pal, 768); + + p = image->GetData(); + for (unsigned long k = height * width; k; k--) + { + index = *p; + *(p++) = pal[3 * index]; + *(p++) = pal[3 * index + 1]; + *(p++) = pal[3 * index + 2]; + } + +#if wxUSE_PALETTE + unsigned char r[256]; + unsigned char g[256]; + unsigned char b[256]; + for (i = 0; i < 256; i++) + { + r[i] = pal[3*i + 0]; + g[i] = pal[3*i + 1]; + b[i] = pal[3*i + 2]; + } + image->SetPalette(wxPalette(256, r, g, b)); +#endif // wxUSE_PALETTE + } + + return wxPCX_OK; +} + +// SavePCX: +// Saves a PCX file into the wxImage object pointed by image. +// Returns wxPCX_OK on success, or an error code otherwise +// (see above for error codes). Will try to save as 8-bit +// PCX if possible, and then fall back to 24-bit if there +// are more than 256 different colours. +// +int SavePCX(wxImage *image, wxOutputStream& stream) +{ + unsigned char hdr[128]; // PCX header + unsigned char pal[768]; // palette for 8 bit images + unsigned char *p; // space to store one scanline + unsigned char *src; // pointer into wxImage data + unsigned int width, height; // size of the image + unsigned int bytesperline; // bytes per line (each plane) + unsigned char nplanes = 3; // number of planes + int format = wxPCX_24BIT; // image format (8 bit, 24 bit) + wxImageHistogram histogram; // image histogram + unsigned long key; // key in the hashtable + unsigned int i; + + // See if we can save as 8 bit. + + if (image->CountColours(256) <= 256) + { + image->ComputeHistogram(histogram); + format = wxPCX_8BIT; + nplanes = 1; + } + + // Get image dimensions, calculate bytesperline (must be even, + // according to PCX specs) and allocate space for one complete + // scanline. + + if (!image->Ok()) + return wxPCX_INVFORMAT; + + width = image->GetWidth(); + height = image->GetHeight(); + bytesperline = width; + if (bytesperline % 2) + bytesperline++; + + if ((p = (unsigned char *) malloc(bytesperline * nplanes)) == NULL) + return wxPCX_MEMERR; + + // Build header data and write it to the stream. Initially, + // set all bytes to zero (most values default to zero). + + memset(hdr, 0, sizeof(hdr)); + + hdr[HDR_MANUFACTURER] = 10; + hdr[HDR_VERSION] = 5; + hdr[HDR_ENCODING] = 1; + hdr[HDR_NPLANES] = nplanes; + hdr[HDR_BITSPERPIXEL] = 8; + hdr[HDR_BYTESPERLINE] = (unsigned char)(bytesperline % 256); + hdr[HDR_BYTESPERLINE + 1] = (unsigned char)(bytesperline / 256); + hdr[HDR_XMAX] = (unsigned char)((width - 1) % 256); + hdr[HDR_XMAX + 1] = (unsigned char)((width - 1) / 256); + hdr[HDR_YMAX] = (unsigned char)((height - 1) % 256); + hdr[HDR_YMAX + 1] = (unsigned char)((height - 1) / 256); + hdr[HDR_PALETTEINFO] = 1; + + stream.Write(hdr, 128); + + // Encode image data line by line and write it to the stream + + src = image->GetData(); + + for (; height; height--) + { + switch (format) + { + case wxPCX_8BIT: + { + unsigned char r, g, b; + + for (i = 0; i < width; i++) + { + r = *(src++); + g = *(src++); + b = *(src++); + key = (r << 16) | (g << 8) | b; + + p[i] = (unsigned char)histogram[key].index; + } + break; + } + case wxPCX_24BIT: + { + for (i = 0; i < width; i++) + { + p[i] = *(src++); + p[i + bytesperline] = *(src++); + p[i + 2 * bytesperline] = *(src++); + } + break; + } + } + + RLEencode(p, bytesperline * nplanes, stream); + } + + free(p); + + // For 8 bit images, build the palette and write it to the stream: + if (format == wxPCX_8BIT) + { + // zero unused colours + memset(pal, 0, sizeof(pal)); + + unsigned long index; + + for (wxImageHistogram::iterator entry = histogram.begin(); + entry != histogram.end(); ++entry ) + { + key = entry->first; + index = entry->second.index; + pal[3 * index] = (unsigned char)(key >> 16); + pal[3 * index + 1] = (unsigned char)(key >> 8); + pal[3 * index + 2] = (unsigned char)(key); + } + + stream.PutC(12); + stream.Write(pal, 768); + } + + return wxPCX_OK; +} + +//----------------------------------------------------------------------------- +// wxPCXHandler +//----------------------------------------------------------------------------- + +bool wxPCXHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) ) +{ + int error; + + if (!CanRead(stream)) + { + if (verbose) + wxLogError(_("PCX: this is not a PCX file.")); + + return false; + } + + image->Destroy(); + + if ((error = ReadPCX(image, stream)) != wxPCX_OK) + { + if (verbose) + { + switch (error) + { + case wxPCX_INVFORMAT: wxLogError(_("PCX: image format unsupported")); break; + case wxPCX_MEMERR: wxLogError(_("PCX: couldn't allocate memory")); break; + case wxPCX_VERERR: wxLogError(_("PCX: version number too low")); break; + default: wxLogError(_("PCX: unknown error !!!")); + } + } + image->Destroy(); + return false; + } + + return true; +} + +bool wxPCXHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) +{ + int error; + + if ((error = SavePCX(image, stream)) != wxPCX_OK) + { + if (verbose) + { + switch (error) + { + case wxPCX_INVFORMAT: wxLogError(_("PCX: invalid image")); break; + case wxPCX_MEMERR: wxLogError(_("PCX: couldn't allocate memory")); break; + default: wxLogError(_("PCX: unknown error !!!")); + } + } + } + + return (error == wxPCX_OK); +} + +bool wxPCXHandler::DoCanRead( wxInputStream& stream ) +{ + unsigned char c = stream.GetC(); + if ( !stream ) + return false; + + // not very safe, but this is all we can get from PCX header :-( + return c == 10; +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_IMAGE && wxUSE_PCX diff --git a/Source/3rd Party/wx/src/common/imagpng.cpp b/Source/3rd Party/wx/src/common/imagpng.cpp index 34ee8ea47..d1bac6597 100644 --- a/Source/3rd Party/wx/src/common/imagpng.cpp +++ b/Source/3rd Party/wx/src/common/imagpng.cpp @@ -1,869 +1,869 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagepng.cpp -// Purpose: wxImage PNG handler -// Author: Robert Roebling -// RCS-ID: $Id: imagpng.cpp 67009 2011-02-24 08:42:57Z JS $ -// Copyright: (c) Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_LIBPNG - -#include "wx/imagpng.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/app.h" - #include "wx/bitmap.h" - #include "wx/module.h" -#endif - -#include "png.h" -#include "wx/filefn.h" -#include "wx/wfstream.h" -#include "wx/intl.h" -#include "wx/palette.h" - -// For memcpy -#include - -#ifdef __SALFORDC__ -#ifdef FAR -#undef FAR -#endif -#endif - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// image can not have any transparent pixels at all, have only 100% opaque -// and/or 100% transparent pixels in which case a simple mask is enough to -// store this information in wxImage or have a real alpha channel in which case -// we need to have it in wxImage as well -enum Transparency -{ - Transparency_None, - Transparency_Mask, - Transparency_Alpha -}; - -// ---------------------------------------------------------------------------- -// local functions -// ---------------------------------------------------------------------------- - -// return the kind of transparency needed for this image assuming that it does -// have transparent pixels, i.e. either Transparency_Alpha or Transparency_Mask -static Transparency -CheckTransparency(unsigned char **lines, - png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h, - size_t numColBytes); - -// init the alpha channel for the image and fill it with 1s up to (x, y) -static unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y); - -// find a free colour for the mask in the PNG data array -static void -FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height, - unsigned char& rMask, unsigned char& gMask, unsigned char& bMask); - -// is the pixel with this value of alpha a fully opaque one? -static inline -bool IsOpaque(unsigned char a) -{ - return a == 0xff; -} - -// is the pixel with this value of alpha a fully transparent one? -static inline -bool IsTransparent(unsigned char a) -{ - return !a; -} - -// ============================================================================ -// wxPNGHandler implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler,wxImageHandler) - -#if wxUSE_STREAMS - -#ifndef PNGLINKAGEMODE - #ifdef PNGAPI - #define PNGLINKAGEMODE PNGAPI - #elif defined(__WATCOMC__) - // we need an explicit cdecl for Watcom, at least according to - // - // http://sf.net/tracker/index.php?func=detail&aid=651492&group_id=9863&atid=109863 - // - // more testing is needed for this however, please remove this comment - // if you can confirm that my fix works with Watcom 11 - #define PNGLINKAGEMODE cdecl - #else - #define PNGLINKAGEMODE LINKAGEMODE - #endif -#endif - - -// VS: wxPNGInfoStruct declared below is a hack that needs some explanation. -// First, let me describe what's the problem: libpng uses jmp_buf in -// its png_struct structure. Unfortunately, this structure is -// compiler-specific and may vary in size, so if you use libpng compiled -// as DLL with another compiler than the main executable, it may not work -// (this is for example the case with wxMGL port and SciTech MGL library -// that provides custom runtime-loadable libpng implementation with jmpbuf -// disabled altogether). Luckily, it is still possible to use setjmp() & -// longjmp() as long as the structure is not part of png_struct. -// -// Sadly, there's no clean way to attach user-defined data to png_struct. -// There is only one customizable place, png_struct.io_ptr, which is meant -// only for I/O routines and is set with png_set_read_fn or -// png_set_write_fn. The hacky part is that we use io_ptr to store -// a pointer to wxPNGInfoStruct that holds I/O structures _and_ jmp_buf. - -struct wxPNGInfoStruct -{ - jmp_buf jmpbuf; - bool verbose; - - union - { - wxInputStream *in; - wxOutputStream *out; - } stream; -}; - -#define WX_PNG_INFO(png_ptr) ((wxPNGInfoStruct*)png_get_io_ptr(png_ptr)) - -// ---------------------------------------------------------------------------- -// helper functions -// ---------------------------------------------------------------------------- - -extern "C" -{ - -void PNGLINKAGEMODE wx_PNG_stream_reader( png_structp png_ptr, png_bytep data, - png_size_t length ) -{ - WX_PNG_INFO(png_ptr)->stream.in->Read(data, length); -} - -void PNGLINKAGEMODE wx_PNG_stream_writer( png_structp png_ptr, png_bytep data, - png_size_t length ) -{ - WX_PNG_INFO(png_ptr)->stream.out->Write(data, length); -} - -void -PNGLINKAGEMODE wx_png_warning(png_structp png_ptr, png_const_charp message) -{ - wxPNGInfoStruct *info = png_ptr ? WX_PNG_INFO(png_ptr) : NULL; - if ( !info || info->verbose ) - wxLogWarning( wxString::FromAscii(message) ); -} - -// from pngerror.c -// so that the libpng doesn't send anything on stderr -void -PNGLINKAGEMODE wx_png_error(png_structp png_ptr, png_const_charp message) -{ - wx_png_warning(NULL, message); - - // we're not using libpng built-in jump buffer (see comment before - // wxPNGInfoStruct above) so we have to return ourselves, otherwise libpng - // would just abort - longjmp(WX_PNG_INFO(png_ptr)->jmpbuf, 1); -} - -} // extern "C" - -// ---------------------------------------------------------------------------- -// LoadFile() helpers -// ---------------------------------------------------------------------------- - -// determine the kind of transparency we need for this image: if the only alpha -// values it has are 0 (transparent) and 0xff (opaque) then we can simply -// create a mask for it, we should be ok with a simple mask but otherwise we -// need a full blown alpha channel in wxImage -// -// parameters: -// lines raw PNG data -// x, y starting position -// w, h size of the image -// numColBytes number of colour bytes (1 for grey scale, 3 for RGB) -// (NB: alpha always follows the colour bytes) -Transparency -CheckTransparency(unsigned char **lines, - png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h, - size_t numColBytes) -{ - // suppose that a mask will suffice and check all the remaining alpha - // values to see if it does - for ( ; y < h; y++ ) - { - // each pixel is numColBytes+1 bytes, offset into the current line by - // the current x position - unsigned const char *ptr = lines[y] + (x * (numColBytes + 1)); - - for ( png_uint_32 x2 = x; x2 < w; x2++ ) - { - // skip the grey or colour byte(s) - ptr += numColBytes; - - unsigned char a2 = *ptr++; - - if ( !IsTransparent(a2) && !IsOpaque(a2) ) - { - // not fully opaque nor fully transparent, hence need alpha - return Transparency_Alpha; - } - } - - // during the next loop iteration check all the pixels in the row - x = 0; - } - - // mask will be enough - return Transparency_Mask; -} - -unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y) -{ - // create alpha channel - image->SetAlpha(); - - unsigned char *alpha = image->GetAlpha(); - - // set alpha for the pixels we had so far - png_uint_32 end = y * image->GetWidth() + x; - for ( png_uint_32 i = 0; i < end; i++ ) - { - // all the previous pixels were opaque - *alpha++ = 0xff; - } - - return alpha; -} - -void -FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height, - unsigned char& rMask, unsigned char& gMask, unsigned char& bMask) -{ - // choosing the colour for the mask is more - // difficult: we need to iterate over the entire - // image for this in order to choose an unused - // colour (this is not very efficient but what else - // can we do?) - wxImageHistogram h; - unsigned nentries = 0; - unsigned char r2, g2, b2; - for ( png_uint_32 y2 = 0; y2 < height; y2++ ) - { - const unsigned char *p = lines[y2]; - for ( png_uint_32 x2 = 0; x2 < width; x2++ ) - { - r2 = *p++; - g2 = *p++; - b2 = *p++; - ++p; // jump over alpha - - wxImageHistogramEntry& - entry = h[wxImageHistogram:: MakeKey(r2, g2, b2)]; - - if ( entry.value++ == 0 ) - entry.index = nentries++; - } - } - - if ( !h.FindFirstUnusedColour(&rMask, &gMask, &bMask) ) - { - wxLogWarning(_("Too many colours in PNG, the image may be slightly blurred.")); - - // use a fixed mask colour and we'll fudge - // the real pixels with this colour (see - // below) - rMask = 0xfe; - gMask = 0; - bMask = 0xff; - } -} - -// ---------------------------------------------------------------------------- -// reading PNGs -// ---------------------------------------------------------------------------- - -bool wxPNGHandler::DoCanRead( wxInputStream& stream ) -{ - unsigned char hdr[4]; - - if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) - return false; - - return memcmp(hdr, "\211PNG", WXSIZEOF(hdr)) == 0; -} - -// convert data from RGB to wxImage format -static -void CopyDataFromPNG(wxImage *image, - unsigned char **lines, - png_uint_32 width, - png_uint_32 height, - int color_type) -{ - Transparency transparency = Transparency_None; - - // only non NULL if transparency == Transparency_Alpha - unsigned char *alpha = NULL; - - // RGB of the mask colour if transparency == Transparency_Mask - // (but init them anyhow to avoid compiler warnings) - unsigned char rMask = 0, - gMask = 0, - bMask = 0; - - unsigned char *ptrDst = image->GetData(); - if ( !(color_type & PNG_COLOR_MASK_COLOR) ) - { - // grey image: GAGAGA... where G == grey component and A == alpha - for ( png_uint_32 y = 0; y < height; y++ ) - { - const unsigned char *ptrSrc = lines[y]; - for ( png_uint_32 x = 0; x < width; x++ ) - { - unsigned char g = *ptrSrc++; - unsigned char a = *ptrSrc++; - - // the first time we encounter a transparent pixel we must - // decide about what to do about them - if ( !IsOpaque(a) && transparency == Transparency_None ) - { - // we'll need at least the mask for this image and - // maybe even full alpha channel info: the former is - // only enough if we have alpha values of 0 and 0xff - // only, otherwisewe need the latter - transparency = CheckTransparency - ( - lines, - x, y, - width, height, - 1 - ); - - if ( transparency == Transparency_Mask ) - { - // let's choose this colour for the mask: this is - // not a problem here as all the other pixels are - // grey, i.e. R == G == B which is not the case for - // this one so no confusion is possible - rMask = 0xff; - gMask = 0; - bMask = 0xff; - } - else // transparency == Transparency_Alpha - { - alpha = InitAlpha(image, x, y); - } - } - - switch ( transparency ) - { - case Transparency_Mask: - if ( IsTransparent(a) ) - { - *ptrDst++ = rMask; - *ptrDst++ = gMask; - *ptrDst++ = bMask; - break; - } - // else: !transparent - - // must be opaque then as otherwise we shouldn't be - // using the mask at all - wxASSERT_MSG( IsOpaque(a), _T("logic error") ); - - // fall through - - case Transparency_Alpha: - if ( alpha ) - *alpha++ = a; - // fall through - - case Transparency_None: - *ptrDst++ = g; - *ptrDst++ = g; - *ptrDst++ = g; - break; - } - } - } - } - else // colour image: RGBRGB... - { - for ( png_uint_32 y = 0; y < height; y++ ) - { - const unsigned char *ptrSrc = lines[y]; - for ( png_uint_32 x = 0; x < width; x++ ) - { - unsigned char r = *ptrSrc++; - unsigned char g = *ptrSrc++; - unsigned char b = *ptrSrc++; - unsigned char a = *ptrSrc++; - - // the logic here is the same as for the grey case except - // where noted - if ( !IsOpaque(a) && transparency == Transparency_None ) - { - transparency = CheckTransparency - ( - lines, - x, y, - width, height, - 3 - ); - - if ( transparency == Transparency_Mask ) - { - FindMaskColour(lines, width, height, - rMask, gMask, bMask); - } - else // transparency == Transparency_Alpha - { - alpha = InitAlpha(image, x, y); - } - - } - - switch ( transparency ) - { - case Transparency_Mask: - if ( IsTransparent(a) ) - { - *ptrDst++ = rMask; - *ptrDst++ = gMask; - *ptrDst++ = bMask; - break; - } - else // !transparent - { - // must be opaque then as otherwise we shouldn't be - // using the mask at all - wxASSERT_MSG( IsOpaque(a), _T("logic error") ); - - // if we couldn't find a unique colour for the - // mask, we can have real pixels with the same - // value as the mask and it's better to slightly - // change their colour than to make them - // transparent - if ( r == rMask && g == gMask && b == bMask ) - { - r++; - } - } - - // fall through - - case Transparency_Alpha: - if ( alpha ) - *alpha++ = a; - // fall through - - case Transparency_None: - *ptrDst++ = r; - *ptrDst++ = g; - *ptrDst++ = b; - break; - } - } - } - } - - if ( transparency == Transparency_Mask ) - { - image->SetMaskColour(rMask, gMask, bMask); - } -} - -// temporarily disable the warning C4611 (interaction between '_setjmp' and -// C++ object destruction is non-portable) - I don't see any dtors here -#ifdef __VISUALC__ - #pragma warning(disable:4611) -#endif /* VC++ */ - -bool -wxPNGHandler::LoadFile(wxImage *image, - wxInputStream& stream, - bool verbose, - int WXUNUSED(index)) -{ - // VZ: as this function uses setjmp() the only fool-proof error handling - // method is to use goto (setjmp is not really C++ dtors friendly...) - - unsigned char **lines = NULL; - png_infop info_ptr = (png_infop) NULL; - wxPNGInfoStruct wxinfo; - - png_uint_32 i, width, height = 0; - int bit_depth, color_type, interlace_type; - - wxinfo.verbose = verbose; - wxinfo.stream.in = &stream; - - image->Destroy(); - - png_structp png_ptr = png_create_read_struct - ( - PNG_LIBPNG_VER_STRING, - NULL, - wx_png_error, - wx_png_warning - ); - if (!png_ptr) - goto error; - - // NB: please see the comment near wxPNGInfoStruct declaration for - // explanation why this line is mandatory - png_set_read_fn( png_ptr, &wxinfo, wx_PNG_stream_reader); - - info_ptr = png_create_info_struct( png_ptr ); - if (!info_ptr) - goto error; - - if (setjmp(wxinfo.jmpbuf)) - goto error; - - png_read_info( png_ptr, info_ptr ); - png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, (int*) NULL, (int*) NULL ); - - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_expand( png_ptr ); - - // Fix for Bug [ 439207 ] Monochrome PNG images come up black - if (bit_depth < 8) - png_set_expand( png_ptr ); - - png_set_strip_16( png_ptr ); - png_set_packing( png_ptr ); - if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS)) - png_set_expand( png_ptr ); - png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER ); - - image->Create((int)width, (int)height, (bool) false /* no need to init pixels */); - - if (!image->Ok()) - goto error; - - // initialize all line pointers to NULL to ensure that they can be safely - // free()d if an error occurs before all of them could be allocated - lines = (unsigned char **)calloc(height, sizeof(unsigned char *)); - if ( !lines ) - goto error; - - for (i = 0; i < height; i++) - { - if ((lines[i] = (unsigned char *)malloc( (size_t)(width * (sizeof(unsigned char) * 4)))) == NULL) - goto error; - } - - png_read_image( png_ptr, lines ); - png_read_end( png_ptr, info_ptr ); - -#if wxUSE_PALETTE - if (color_type == PNG_COLOR_TYPE_PALETTE) - { - int ncolors = 0; - png_colorp palette; - png_get_PLTE( png_ptr, info_ptr, &palette, &ncolors); - unsigned char* r = new unsigned char[ncolors]; - unsigned char* g = new unsigned char[ncolors]; - unsigned char* b = new unsigned char[ncolors]; - int j; - - for (j = 0; j < ncolors; j++) - { - r[j] = palette[j].red; - g[j] = palette[j].green; - b[j] = palette[j].blue; - } - - image->SetPalette(wxPalette(ncolors, r, g, b)); - delete[] r; - delete[] g; - delete[] b; - } -#endif // wxUSE_PALETTE - - png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); - - // loaded successfully, now init wxImage with this data - CopyDataFromPNG(image, lines, width, height, color_type); - - for ( i = 0; i < height; i++ ) - free( lines[i] ); - free( lines ); - - return true; - -error: - if (verbose) - wxLogError(_("Couldn't load a PNG image - file is corrupted or not enough memory.")); - - if ( image->Ok() ) - { - image->Destroy(); - } - - if ( lines ) - { - for ( unsigned int n = 0; n < height; n++ ) - free( lines[n] ); - - free( lines ); - } - - if ( png_ptr ) - { - if ( info_ptr ) - { - png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); - free(info_ptr); - } - else - png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL ); - } - return false; -} - -// ---------------------------------------------------------------------------- -// writing PNGs -// ---------------------------------------------------------------------------- - -bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) -{ - wxPNGInfoStruct wxinfo; - - wxinfo.verbose = verbose; - wxinfo.stream.out = &stream; - - png_structp png_ptr = png_create_write_struct - ( - PNG_LIBPNG_VER_STRING, - NULL, - wx_png_error, - wx_png_warning - ); - if (!png_ptr) - { - if (verbose) - wxLogError(_("Couldn't save PNG image.")); - return false; - } - - png_infop info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) - { - png_destroy_write_struct( &png_ptr, (png_infopp)NULL ); - if (verbose) - wxLogError(_("Couldn't save PNG image.")); - return false; - } - - if (setjmp(wxinfo.jmpbuf)) - { - png_destroy_write_struct( &png_ptr, (png_infopp)NULL ); - if (verbose) - wxLogError(_("Couldn't save PNG image.")); - return false; - } - - // NB: please see the comment near wxPNGInfoStruct declaration for - // explanation why this line is mandatory - png_set_write_fn( png_ptr, &wxinfo, wx_PNG_stream_writer, NULL); - - const int iColorType = image->HasOption(wxIMAGE_OPTION_PNG_FORMAT) - ? image->GetOptionInt(wxIMAGE_OPTION_PNG_FORMAT) - : wxPNG_TYPE_COLOUR; - const int iBitDepth = image->HasOption(wxIMAGE_OPTION_PNG_BITDEPTH) - ? image->GetOptionInt(wxIMAGE_OPTION_PNG_BITDEPTH) - : 8; - - wxASSERT_MSG( iBitDepth == 8 || iBitDepth == 16, - _T("PNG bit depth must be 8 or 16") ); - - bool bHasAlpha = image->HasAlpha(); - bool bHasMask = image->HasMask(); - bool bUseAlpha = bHasAlpha || bHasMask; - - int iPngColorType; - if ( iColorType==wxPNG_TYPE_COLOUR ) - { - iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_RGB_ALPHA - : PNG_COLOR_TYPE_RGB; - } - else - { - iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_GRAY_ALPHA - : PNG_COLOR_TYPE_GRAY; - } - - png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(), - iBitDepth, iPngColorType, - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, - PNG_FILTER_TYPE_BASE); - - int iElements; - png_color_8 sig_bit; - - if ( iPngColorType & PNG_COLOR_MASK_COLOR ) - { - sig_bit.red = - sig_bit.green = - sig_bit.blue = (png_byte)iBitDepth; - iElements = 3; - } - else // grey - { - sig_bit.gray = (png_byte)iBitDepth; - iElements = 1; - } - - if ( iPngColorType & PNG_COLOR_MASK_ALPHA ) - { - sig_bit.alpha = (png_byte)iBitDepth; - iElements++; - } - - if ( iBitDepth == 16 ) - iElements *= 2; - - png_set_sBIT( png_ptr, info_ptr, &sig_bit ); - png_write_info( png_ptr, info_ptr ); - png_set_shift( png_ptr, &sig_bit ); - png_set_packing( png_ptr ); - - unsigned char * - data = (unsigned char *)malloc( image->GetWidth() * iElements ); - if ( !data ) - { - png_destroy_write_struct( &png_ptr, (png_infopp)NULL ); - return false; - } - - unsigned char * - pAlpha = (unsigned char *)(bHasAlpha ? image->GetAlpha() : NULL); - int iHeight = image->GetHeight(); - int iWidth = image->GetWidth(); - - unsigned char uchMaskRed = 0, uchMaskGreen = 0, uchMaskBlue = 0; - - if ( bHasMask ) - { - uchMaskRed = image->GetMaskRed(); - uchMaskGreen = image->GetMaskGreen(); - uchMaskBlue = image->GetMaskBlue(); - } - - unsigned char *pColors = image->GetData(); - - for (int y = 0; y != iHeight; ++y) - { - unsigned char *pData = data; - for (int x = 0; x != iWidth; x++) - { - unsigned char uchRed = *pColors++; - unsigned char uchGreen = *pColors++; - unsigned char uchBlue = *pColors++; - - switch ( iColorType ) - { - default: - wxFAIL_MSG( _T("unknown wxPNG_TYPE_XXX") ); - // fall through - - case wxPNG_TYPE_COLOUR: - *pData++ = uchRed; - if ( iBitDepth == 16 ) - *pData++ = 0; - *pData++ = uchGreen; - if ( iBitDepth == 16 ) - *pData++ = 0; - *pData++ = uchBlue; - if ( iBitDepth == 16 ) - *pData++ = 0; - break; - - case wxPNG_TYPE_GREY: - { - // where do these coefficients come from? maybe we - // should have image options for them as well? - unsigned uiColor = - (unsigned) (76.544*(unsigned)uchRed + - 150.272*(unsigned)uchGreen + - 36.864*(unsigned)uchBlue); - - *pData++ = (unsigned char)((uiColor >> 8) & 0xFF); - if ( iBitDepth == 16 ) - *pData++ = (unsigned char)(uiColor & 0xFF); - } - break; - - case wxPNG_TYPE_GREY_RED: - *pData++ = uchRed; - if ( iBitDepth == 16 ) - *pData++ = 0; - break; - } - - if ( bUseAlpha ) - { - unsigned char uchAlpha = 255; - if ( bHasAlpha ) - uchAlpha = *pAlpha++; - - if ( bHasMask ) - { - if ( (uchRed == uchMaskRed) - && (uchGreen == uchMaskGreen) - && (uchBlue == uchMaskBlue) ) - uchAlpha = 0; - } - - *pData++ = uchAlpha; - if ( iBitDepth == 16 ) - *pData++ = 0; - } - } - - png_bytep row_ptr = data; - png_write_rows( png_ptr, &row_ptr, 1 ); - } - - free(data); - png_write_end( png_ptr, info_ptr ); - png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr ); - - return true; -} - -#ifdef __VISUALC__ - #pragma warning(default:4611) -#endif /* VC++ */ - -#endif // wxUSE_STREAMS - -#endif // wxUSE_LIBPNG +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagepng.cpp +// Purpose: wxImage PNG handler +// Author: Robert Roebling +// RCS-ID: $Id: imagpng.cpp 67009 2011-02-24 08:42:57Z JS $ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_LIBPNG + +#include "wx/imagpng.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/app.h" + #include "wx/bitmap.h" + #include "wx/module.h" +#endif + +#include "png.h" +#include "wx/filefn.h" +#include "wx/wfstream.h" +#include "wx/intl.h" +#include "wx/palette.h" + +// For memcpy +#include + +#ifdef __SALFORDC__ +#ifdef FAR +#undef FAR +#endif +#endif + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// image can not have any transparent pixels at all, have only 100% opaque +// and/or 100% transparent pixels in which case a simple mask is enough to +// store this information in wxImage or have a real alpha channel in which case +// we need to have it in wxImage as well +enum Transparency +{ + Transparency_None, + Transparency_Mask, + Transparency_Alpha +}; + +// ---------------------------------------------------------------------------- +// local functions +// ---------------------------------------------------------------------------- + +// return the kind of transparency needed for this image assuming that it does +// have transparent pixels, i.e. either Transparency_Alpha or Transparency_Mask +static Transparency +CheckTransparency(unsigned char **lines, + png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h, + size_t numColBytes); + +// init the alpha channel for the image and fill it with 1s up to (x, y) +static unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y); + +// find a free colour for the mask in the PNG data array +static void +FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height, + unsigned char& rMask, unsigned char& gMask, unsigned char& bMask); + +// is the pixel with this value of alpha a fully opaque one? +static inline +bool IsOpaque(unsigned char a) +{ + return a == 0xff; +} + +// is the pixel with this value of alpha a fully transparent one? +static inline +bool IsTransparent(unsigned char a) +{ + return !a; +} + +// ============================================================================ +// wxPNGHandler implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxPNGHandler,wxImageHandler) + +#if wxUSE_STREAMS + +#ifndef PNGLINKAGEMODE + #ifdef PNGAPI + #define PNGLINKAGEMODE PNGAPI + #elif defined(__WATCOMC__) + // we need an explicit cdecl for Watcom, at least according to + // + // http://sf.net/tracker/index.php?func=detail&aid=651492&group_id=9863&atid=109863 + // + // more testing is needed for this however, please remove this comment + // if you can confirm that my fix works with Watcom 11 + #define PNGLINKAGEMODE cdecl + #else + #define PNGLINKAGEMODE LINKAGEMODE + #endif +#endif + + +// VS: wxPNGInfoStruct declared below is a hack that needs some explanation. +// First, let me describe what's the problem: libpng uses jmp_buf in +// its png_struct structure. Unfortunately, this structure is +// compiler-specific and may vary in size, so if you use libpng compiled +// as DLL with another compiler than the main executable, it may not work +// (this is for example the case with wxMGL port and SciTech MGL library +// that provides custom runtime-loadable libpng implementation with jmpbuf +// disabled altogether). Luckily, it is still possible to use setjmp() & +// longjmp() as long as the structure is not part of png_struct. +// +// Sadly, there's no clean way to attach user-defined data to png_struct. +// There is only one customizable place, png_struct.io_ptr, which is meant +// only for I/O routines and is set with png_set_read_fn or +// png_set_write_fn. The hacky part is that we use io_ptr to store +// a pointer to wxPNGInfoStruct that holds I/O structures _and_ jmp_buf. + +struct wxPNGInfoStruct +{ + jmp_buf jmpbuf; + bool verbose; + + union + { + wxInputStream *in; + wxOutputStream *out; + } stream; +}; + +#define WX_PNG_INFO(png_ptr) ((wxPNGInfoStruct*)png_get_io_ptr(png_ptr)) + +// ---------------------------------------------------------------------------- +// helper functions +// ---------------------------------------------------------------------------- + +extern "C" +{ + +void PNGLINKAGEMODE wx_PNG_stream_reader( png_structp png_ptr, png_bytep data, + png_size_t length ) +{ + WX_PNG_INFO(png_ptr)->stream.in->Read(data, length); +} + +void PNGLINKAGEMODE wx_PNG_stream_writer( png_structp png_ptr, png_bytep data, + png_size_t length ) +{ + WX_PNG_INFO(png_ptr)->stream.out->Write(data, length); +} + +void +PNGLINKAGEMODE wx_png_warning(png_structp png_ptr, png_const_charp message) +{ + wxPNGInfoStruct *info = png_ptr ? WX_PNG_INFO(png_ptr) : NULL; + if ( !info || info->verbose ) + wxLogWarning( wxString::FromAscii(message) ); +} + +// from pngerror.c +// so that the libpng doesn't send anything on stderr +void +PNGLINKAGEMODE wx_png_error(png_structp png_ptr, png_const_charp message) +{ + wx_png_warning(NULL, message); + + // we're not using libpng built-in jump buffer (see comment before + // wxPNGInfoStruct above) so we have to return ourselves, otherwise libpng + // would just abort + longjmp(WX_PNG_INFO(png_ptr)->jmpbuf, 1); +} + +} // extern "C" + +// ---------------------------------------------------------------------------- +// LoadFile() helpers +// ---------------------------------------------------------------------------- + +// determine the kind of transparency we need for this image: if the only alpha +// values it has are 0 (transparent) and 0xff (opaque) then we can simply +// create a mask for it, we should be ok with a simple mask but otherwise we +// need a full blown alpha channel in wxImage +// +// parameters: +// lines raw PNG data +// x, y starting position +// w, h size of the image +// numColBytes number of colour bytes (1 for grey scale, 3 for RGB) +// (NB: alpha always follows the colour bytes) +Transparency +CheckTransparency(unsigned char **lines, + png_uint_32 x, png_uint_32 y, png_uint_32 w, png_uint_32 h, + size_t numColBytes) +{ + // suppose that a mask will suffice and check all the remaining alpha + // values to see if it does + for ( ; y < h; y++ ) + { + // each pixel is numColBytes+1 bytes, offset into the current line by + // the current x position + unsigned const char *ptr = lines[y] + (x * (numColBytes + 1)); + + for ( png_uint_32 x2 = x; x2 < w; x2++ ) + { + // skip the grey or colour byte(s) + ptr += numColBytes; + + unsigned char a2 = *ptr++; + + if ( !IsTransparent(a2) && !IsOpaque(a2) ) + { + // not fully opaque nor fully transparent, hence need alpha + return Transparency_Alpha; + } + } + + // during the next loop iteration check all the pixels in the row + x = 0; + } + + // mask will be enough + return Transparency_Mask; +} + +unsigned char *InitAlpha(wxImage *image, png_uint_32 x, png_uint_32 y) +{ + // create alpha channel + image->SetAlpha(); + + unsigned char *alpha = image->GetAlpha(); + + // set alpha for the pixels we had so far + png_uint_32 end = y * image->GetWidth() + x; + for ( png_uint_32 i = 0; i < end; i++ ) + { + // all the previous pixels were opaque + *alpha++ = 0xff; + } + + return alpha; +} + +void +FindMaskColour(unsigned char **lines, png_uint_32 width, png_uint_32 height, + unsigned char& rMask, unsigned char& gMask, unsigned char& bMask) +{ + // choosing the colour for the mask is more + // difficult: we need to iterate over the entire + // image for this in order to choose an unused + // colour (this is not very efficient but what else + // can we do?) + wxImageHistogram h; + unsigned nentries = 0; + unsigned char r2, g2, b2; + for ( png_uint_32 y2 = 0; y2 < height; y2++ ) + { + const unsigned char *p = lines[y2]; + for ( png_uint_32 x2 = 0; x2 < width; x2++ ) + { + r2 = *p++; + g2 = *p++; + b2 = *p++; + ++p; // jump over alpha + + wxImageHistogramEntry& + entry = h[wxImageHistogram:: MakeKey(r2, g2, b2)]; + + if ( entry.value++ == 0 ) + entry.index = nentries++; + } + } + + if ( !h.FindFirstUnusedColour(&rMask, &gMask, &bMask) ) + { + wxLogWarning(_("Too many colours in PNG, the image may be slightly blurred.")); + + // use a fixed mask colour and we'll fudge + // the real pixels with this colour (see + // below) + rMask = 0xfe; + gMask = 0; + bMask = 0xff; + } +} + +// ---------------------------------------------------------------------------- +// reading PNGs +// ---------------------------------------------------------------------------- + +bool wxPNGHandler::DoCanRead( wxInputStream& stream ) +{ + unsigned char hdr[4]; + + if ( !stream.Read(hdr, WXSIZEOF(hdr)) ) + return false; + + return memcmp(hdr, "\211PNG", WXSIZEOF(hdr)) == 0; +} + +// convert data from RGB to wxImage format +static +void CopyDataFromPNG(wxImage *image, + unsigned char **lines, + png_uint_32 width, + png_uint_32 height, + int color_type) +{ + Transparency transparency = Transparency_None; + + // only non NULL if transparency == Transparency_Alpha + unsigned char *alpha = NULL; + + // RGB of the mask colour if transparency == Transparency_Mask + // (but init them anyhow to avoid compiler warnings) + unsigned char rMask = 0, + gMask = 0, + bMask = 0; + + unsigned char *ptrDst = image->GetData(); + if ( !(color_type & PNG_COLOR_MASK_COLOR) ) + { + // grey image: GAGAGA... where G == grey component and A == alpha + for ( png_uint_32 y = 0; y < height; y++ ) + { + const unsigned char *ptrSrc = lines[y]; + for ( png_uint_32 x = 0; x < width; x++ ) + { + unsigned char g = *ptrSrc++; + unsigned char a = *ptrSrc++; + + // the first time we encounter a transparent pixel we must + // decide about what to do about them + if ( !IsOpaque(a) && transparency == Transparency_None ) + { + // we'll need at least the mask for this image and + // maybe even full alpha channel info: the former is + // only enough if we have alpha values of 0 and 0xff + // only, otherwisewe need the latter + transparency = CheckTransparency + ( + lines, + x, y, + width, height, + 1 + ); + + if ( transparency == Transparency_Mask ) + { + // let's choose this colour for the mask: this is + // not a problem here as all the other pixels are + // grey, i.e. R == G == B which is not the case for + // this one so no confusion is possible + rMask = 0xff; + gMask = 0; + bMask = 0xff; + } + else // transparency == Transparency_Alpha + { + alpha = InitAlpha(image, x, y); + } + } + + switch ( transparency ) + { + case Transparency_Mask: + if ( IsTransparent(a) ) + { + *ptrDst++ = rMask; + *ptrDst++ = gMask; + *ptrDst++ = bMask; + break; + } + // else: !transparent + + // must be opaque then as otherwise we shouldn't be + // using the mask at all + wxASSERT_MSG( IsOpaque(a), _T("logic error") ); + + // fall through + + case Transparency_Alpha: + if ( alpha ) + *alpha++ = a; + // fall through + + case Transparency_None: + *ptrDst++ = g; + *ptrDst++ = g; + *ptrDst++ = g; + break; + } + } + } + } + else // colour image: RGBRGB... + { + for ( png_uint_32 y = 0; y < height; y++ ) + { + const unsigned char *ptrSrc = lines[y]; + for ( png_uint_32 x = 0; x < width; x++ ) + { + unsigned char r = *ptrSrc++; + unsigned char g = *ptrSrc++; + unsigned char b = *ptrSrc++; + unsigned char a = *ptrSrc++; + + // the logic here is the same as for the grey case except + // where noted + if ( !IsOpaque(a) && transparency == Transparency_None ) + { + transparency = CheckTransparency + ( + lines, + x, y, + width, height, + 3 + ); + + if ( transparency == Transparency_Mask ) + { + FindMaskColour(lines, width, height, + rMask, gMask, bMask); + } + else // transparency == Transparency_Alpha + { + alpha = InitAlpha(image, x, y); + } + + } + + switch ( transparency ) + { + case Transparency_Mask: + if ( IsTransparent(a) ) + { + *ptrDst++ = rMask; + *ptrDst++ = gMask; + *ptrDst++ = bMask; + break; + } + else // !transparent + { + // must be opaque then as otherwise we shouldn't be + // using the mask at all + wxASSERT_MSG( IsOpaque(a), _T("logic error") ); + + // if we couldn't find a unique colour for the + // mask, we can have real pixels with the same + // value as the mask and it's better to slightly + // change their colour than to make them + // transparent + if ( r == rMask && g == gMask && b == bMask ) + { + r++; + } + } + + // fall through + + case Transparency_Alpha: + if ( alpha ) + *alpha++ = a; + // fall through + + case Transparency_None: + *ptrDst++ = r; + *ptrDst++ = g; + *ptrDst++ = b; + break; + } + } + } + } + + if ( transparency == Transparency_Mask ) + { + image->SetMaskColour(rMask, gMask, bMask); + } +} + +// temporarily disable the warning C4611 (interaction between '_setjmp' and +// C++ object destruction is non-portable) - I don't see any dtors here +#ifdef __VISUALC__ + #pragma warning(disable:4611) +#endif /* VC++ */ + +bool +wxPNGHandler::LoadFile(wxImage *image, + wxInputStream& stream, + bool verbose, + int WXUNUSED(index)) +{ + // VZ: as this function uses setjmp() the only fool-proof error handling + // method is to use goto (setjmp is not really C++ dtors friendly...) + + unsigned char **lines = NULL; + png_infop info_ptr = (png_infop) NULL; + wxPNGInfoStruct wxinfo; + + png_uint_32 i, width, height = 0; + int bit_depth, color_type, interlace_type; + + wxinfo.verbose = verbose; + wxinfo.stream.in = &stream; + + image->Destroy(); + + png_structp png_ptr = png_create_read_struct + ( + PNG_LIBPNG_VER_STRING, + NULL, + wx_png_error, + wx_png_warning + ); + if (!png_ptr) + goto error; + + // NB: please see the comment near wxPNGInfoStruct declaration for + // explanation why this line is mandatory + png_set_read_fn( png_ptr, &wxinfo, wx_PNG_stream_reader); + + info_ptr = png_create_info_struct( png_ptr ); + if (!info_ptr) + goto error; + + if (setjmp(wxinfo.jmpbuf)) + goto error; + + png_read_info( png_ptr, info_ptr ); + png_get_IHDR( png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, (int*) NULL, (int*) NULL ); + + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand( png_ptr ); + + // Fix for Bug [ 439207 ] Monochrome PNG images come up black + if (bit_depth < 8) + png_set_expand( png_ptr ); + + png_set_strip_16( png_ptr ); + png_set_packing( png_ptr ); + if (png_get_valid( png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_expand( png_ptr ); + png_set_filler( png_ptr, 0xff, PNG_FILLER_AFTER ); + + image->Create((int)width, (int)height, (bool) false /* no need to init pixels */); + + if (!image->Ok()) + goto error; + + // initialize all line pointers to NULL to ensure that they can be safely + // free()d if an error occurs before all of them could be allocated + lines = (unsigned char **)calloc(height, sizeof(unsigned char *)); + if ( !lines ) + goto error; + + for (i = 0; i < height; i++) + { + if ((lines[i] = (unsigned char *)malloc( (size_t)(width * (sizeof(unsigned char) * 4)))) == NULL) + goto error; + } + + png_read_image( png_ptr, lines ); + png_read_end( png_ptr, info_ptr ); + +#if wxUSE_PALETTE + if (color_type == PNG_COLOR_TYPE_PALETTE) + { + int ncolors = 0; + png_colorp palette; + png_get_PLTE( png_ptr, info_ptr, &palette, &ncolors); + unsigned char* r = new unsigned char[ncolors]; + unsigned char* g = new unsigned char[ncolors]; + unsigned char* b = new unsigned char[ncolors]; + int j; + + for (j = 0; j < ncolors; j++) + { + r[j] = palette[j].red; + g[j] = palette[j].green; + b[j] = palette[j].blue; + } + + image->SetPalette(wxPalette(ncolors, r, g, b)); + delete[] r; + delete[] g; + delete[] b; + } +#endif // wxUSE_PALETTE + + png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); + + // loaded successfully, now init wxImage with this data + CopyDataFromPNG(image, lines, width, height, color_type); + + for ( i = 0; i < height; i++ ) + free( lines[i] ); + free( lines ); + + return true; + +error: + if (verbose) + wxLogError(_("Couldn't load a PNG image - file is corrupted or not enough memory.")); + + if ( image->Ok() ) + { + image->Destroy(); + } + + if ( lines ) + { + for ( unsigned int n = 0; n < height; n++ ) + free( lines[n] ); + + free( lines ); + } + + if ( png_ptr ) + { + if ( info_ptr ) + { + png_destroy_read_struct( &png_ptr, &info_ptr, (png_infopp) NULL ); + free(info_ptr); + } + else + png_destroy_read_struct( &png_ptr, (png_infopp) NULL, (png_infopp) NULL ); + } + return false; +} + +// ---------------------------------------------------------------------------- +// writing PNGs +// ---------------------------------------------------------------------------- + +bool wxPNGHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) +{ + wxPNGInfoStruct wxinfo; + + wxinfo.verbose = verbose; + wxinfo.stream.out = &stream; + + png_structp png_ptr = png_create_write_struct + ( + PNG_LIBPNG_VER_STRING, + NULL, + wx_png_error, + wx_png_warning + ); + if (!png_ptr) + { + if (verbose) + wxLogError(_("Couldn't save PNG image.")); + return false; + } + + png_infop info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) + { + png_destroy_write_struct( &png_ptr, (png_infopp)NULL ); + if (verbose) + wxLogError(_("Couldn't save PNG image.")); + return false; + } + + if (setjmp(wxinfo.jmpbuf)) + { + png_destroy_write_struct( &png_ptr, (png_infopp)NULL ); + if (verbose) + wxLogError(_("Couldn't save PNG image.")); + return false; + } + + // NB: please see the comment near wxPNGInfoStruct declaration for + // explanation why this line is mandatory + png_set_write_fn( png_ptr, &wxinfo, wx_PNG_stream_writer, NULL); + + const int iColorType = image->HasOption(wxIMAGE_OPTION_PNG_FORMAT) + ? image->GetOptionInt(wxIMAGE_OPTION_PNG_FORMAT) + : wxPNG_TYPE_COLOUR; + const int iBitDepth = image->HasOption(wxIMAGE_OPTION_PNG_BITDEPTH) + ? image->GetOptionInt(wxIMAGE_OPTION_PNG_BITDEPTH) + : 8; + + wxASSERT_MSG( iBitDepth == 8 || iBitDepth == 16, + _T("PNG bit depth must be 8 or 16") ); + + bool bHasAlpha = image->HasAlpha(); + bool bHasMask = image->HasMask(); + bool bUseAlpha = bHasAlpha || bHasMask; + + int iPngColorType; + if ( iColorType==wxPNG_TYPE_COLOUR ) + { + iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_RGB_ALPHA + : PNG_COLOR_TYPE_RGB; + } + else + { + iPngColorType = bUseAlpha ? PNG_COLOR_TYPE_GRAY_ALPHA + : PNG_COLOR_TYPE_GRAY; + } + + png_set_IHDR( png_ptr, info_ptr, image->GetWidth(), image->GetHeight(), + iBitDepth, iPngColorType, + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, + PNG_FILTER_TYPE_BASE); + + int iElements; + png_color_8 sig_bit; + + if ( iPngColorType & PNG_COLOR_MASK_COLOR ) + { + sig_bit.red = + sig_bit.green = + sig_bit.blue = (png_byte)iBitDepth; + iElements = 3; + } + else // grey + { + sig_bit.gray = (png_byte)iBitDepth; + iElements = 1; + } + + if ( iPngColorType & PNG_COLOR_MASK_ALPHA ) + { + sig_bit.alpha = (png_byte)iBitDepth; + iElements++; + } + + if ( iBitDepth == 16 ) + iElements *= 2; + + png_set_sBIT( png_ptr, info_ptr, &sig_bit ); + png_write_info( png_ptr, info_ptr ); + png_set_shift( png_ptr, &sig_bit ); + png_set_packing( png_ptr ); + + unsigned char * + data = (unsigned char *)malloc( image->GetWidth() * iElements ); + if ( !data ) + { + png_destroy_write_struct( &png_ptr, (png_infopp)NULL ); + return false; + } + + unsigned char * + pAlpha = (unsigned char *)(bHasAlpha ? image->GetAlpha() : NULL); + int iHeight = image->GetHeight(); + int iWidth = image->GetWidth(); + + unsigned char uchMaskRed = 0, uchMaskGreen = 0, uchMaskBlue = 0; + + if ( bHasMask ) + { + uchMaskRed = image->GetMaskRed(); + uchMaskGreen = image->GetMaskGreen(); + uchMaskBlue = image->GetMaskBlue(); + } + + unsigned char *pColors = image->GetData(); + + for (int y = 0; y != iHeight; ++y) + { + unsigned char *pData = data; + for (int x = 0; x != iWidth; x++) + { + unsigned char uchRed = *pColors++; + unsigned char uchGreen = *pColors++; + unsigned char uchBlue = *pColors++; + + switch ( iColorType ) + { + default: + wxFAIL_MSG( _T("unknown wxPNG_TYPE_XXX") ); + // fall through + + case wxPNG_TYPE_COLOUR: + *pData++ = uchRed; + if ( iBitDepth == 16 ) + *pData++ = 0; + *pData++ = uchGreen; + if ( iBitDepth == 16 ) + *pData++ = 0; + *pData++ = uchBlue; + if ( iBitDepth == 16 ) + *pData++ = 0; + break; + + case wxPNG_TYPE_GREY: + { + // where do these coefficients come from? maybe we + // should have image options for them as well? + unsigned uiColor = + (unsigned) (76.544*(unsigned)uchRed + + 150.272*(unsigned)uchGreen + + 36.864*(unsigned)uchBlue); + + *pData++ = (unsigned char)((uiColor >> 8) & 0xFF); + if ( iBitDepth == 16 ) + *pData++ = (unsigned char)(uiColor & 0xFF); + } + break; + + case wxPNG_TYPE_GREY_RED: + *pData++ = uchRed; + if ( iBitDepth == 16 ) + *pData++ = 0; + break; + } + + if ( bUseAlpha ) + { + unsigned char uchAlpha = 255; + if ( bHasAlpha ) + uchAlpha = *pAlpha++; + + if ( bHasMask ) + { + if ( (uchRed == uchMaskRed) + && (uchGreen == uchMaskGreen) + && (uchBlue == uchMaskBlue) ) + uchAlpha = 0; + } + + *pData++ = uchAlpha; + if ( iBitDepth == 16 ) + *pData++ = 0; + } + } + + png_bytep row_ptr = data; + png_write_rows( png_ptr, &row_ptr, 1 ); + } + + free(data); + png_write_end( png_ptr, info_ptr ); + png_destroy_write_struct( &png_ptr, (png_infopp)&info_ptr ); + + return true; +} + +#ifdef __VISUALC__ + #pragma warning(default:4611) +#endif /* VC++ */ + +#endif // wxUSE_STREAMS + +#endif // wxUSE_LIBPNG diff --git a/Source/3rd Party/wx/src/common/imagpnm.cpp b/Source/3rd Party/wx/src/common/imagpnm.cpp index ba9c5c8bf..3fcc95916 100644 --- a/Source/3rd Party/wx/src/common/imagpnm.cpp +++ b/Source/3rd Party/wx/src/common/imagpnm.cpp @@ -1,201 +1,201 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagpnm.cpp -// Purpose: wxImage PNM handler -// Author: Sylvain Bougnoux -// RCS-ID: $Id: imagpnm.cpp 46311 2007-06-03 22:14:32Z VZ $ -// Copyright: (c) Sylvain Bougnoux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_PNM - -#include "wx/imagpnm.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" -#endif - -#include "wx/txtstrm.h" - -//----------------------------------------------------------------------------- -// wxBMPHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxPNMHandler,wxImageHandler) - -#if wxUSE_STREAMS - -void Skip_Comment(wxInputStream &stream) -{ - wxTextInputStream text_stream(stream); - - if (stream.Peek()==wxT('#')) - { - text_stream.ReadLine(); - Skip_Comment(stream); - } -} - -bool wxPNMHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) ) -{ - wxUint32 width, height; - wxUint16 maxval; - char c(0); - - image->Destroy(); - - /* - * Read the PNM header - */ - - wxBufferedInputStream buf_stream(stream); - wxTextInputStream text_stream(buf_stream); - - Skip_Comment(buf_stream); - if (buf_stream.GetC()==wxT('P')) c=buf_stream.GetC(); - - switch (c) - { - case wxT('2'): // ASCII Grey - case wxT('3'): // ASCII RGB - case wxT('5'): // RAW Grey - case wxT('6'): break; - default: - if (verbose) wxLogError(_("PNM: File format is not recognized.")); - return false; - } - - text_stream.ReadLine(); // for the \n - Skip_Comment(buf_stream); - text_stream >> width >> height ; - Skip_Comment(buf_stream); - text_stream >> maxval; - - //cout << line << " " << width << " " << height << " " << maxval << endl; - image->Create( width, height ); - unsigned char *ptr = image->GetData(); - if (!ptr) - { - if (verbose) - wxLogError( _("PNM: Couldn't allocate memory.") ); - return false; - } - - - if (c=='2') // Ascii GREY - { - wxUint32 value, size=width*height; - for (wxUint32 i=0; iSetMask( false ); - - const wxStreamError err = buf_stream.GetLastError(); - return err == wxSTREAM_NO_ERROR || err == wxSTREAM_EOF; -} - -bool wxPNMHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool WXUNUSED(verbose) ) -{ - wxTextOutputStream text_stream(stream); - - //text_stream << "P6" << endl - //<< image->GetWidth() << " " << image->GetHeight() << endl - //<< "255" << endl; - text_stream << wxT("P6\n") << image->GetWidth() << wxT(" ") << image->GetHeight() << wxT("\n255\n"); - stream.Write(image->GetData(),3*image->GetWidth()*image->GetHeight()); - - return stream.IsOk(); -} - -bool wxPNMHandler::DoCanRead( wxInputStream& stream ) -{ - Skip_Comment(stream); - - if ( stream.GetC() == 'P' ) - { - switch ( stream.GetC() ) - { - case '2': // ASCII Grey - case '3': // ASCII RGB - case '5': // RAW Grey - case '6': // RAW RGB - return true; - } - } - - return false; -} - - -#endif // wxUSE_STREAMS - -#endif // wxUSE_IMAGE && wxUSE_PNM +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagpnm.cpp +// Purpose: wxImage PNM handler +// Author: Sylvain Bougnoux +// RCS-ID: $Id: imagpnm.cpp 46311 2007-06-03 22:14:32Z VZ $ +// Copyright: (c) Sylvain Bougnoux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_PNM + +#include "wx/imagpnm.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" +#endif + +#include "wx/txtstrm.h" + +//----------------------------------------------------------------------------- +// wxBMPHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxPNMHandler,wxImageHandler) + +#if wxUSE_STREAMS + +void Skip_Comment(wxInputStream &stream) +{ + wxTextInputStream text_stream(stream); + + if (stream.Peek()==wxT('#')) + { + text_stream.ReadLine(); + Skip_Comment(stream); + } +} + +bool wxPNMHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int WXUNUSED(index) ) +{ + wxUint32 width, height; + wxUint16 maxval; + char c(0); + + image->Destroy(); + + /* + * Read the PNM header + */ + + wxBufferedInputStream buf_stream(stream); + wxTextInputStream text_stream(buf_stream); + + Skip_Comment(buf_stream); + if (buf_stream.GetC()==wxT('P')) c=buf_stream.GetC(); + + switch (c) + { + case wxT('2'): // ASCII Grey + case wxT('3'): // ASCII RGB + case wxT('5'): // RAW Grey + case wxT('6'): break; + default: + if (verbose) wxLogError(_("PNM: File format is not recognized.")); + return false; + } + + text_stream.ReadLine(); // for the \n + Skip_Comment(buf_stream); + text_stream >> width >> height ; + Skip_Comment(buf_stream); + text_stream >> maxval; + + //cout << line << " " << width << " " << height << " " << maxval << endl; + image->Create( width, height ); + unsigned char *ptr = image->GetData(); + if (!ptr) + { + if (verbose) + wxLogError( _("PNM: Couldn't allocate memory.") ); + return false; + } + + + if (c=='2') // Ascii GREY + { + wxUint32 value, size=width*height; + for (wxUint32 i=0; iSetMask( false ); + + const wxStreamError err = buf_stream.GetLastError(); + return err == wxSTREAM_NO_ERROR || err == wxSTREAM_EOF; +} + +bool wxPNMHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool WXUNUSED(verbose) ) +{ + wxTextOutputStream text_stream(stream); + + //text_stream << "P6" << endl + //<< image->GetWidth() << " " << image->GetHeight() << endl + //<< "255" << endl; + text_stream << wxT("P6\n") << image->GetWidth() << wxT(" ") << image->GetHeight() << wxT("\n255\n"); + stream.Write(image->GetData(),3*image->GetWidth()*image->GetHeight()); + + return stream.IsOk(); +} + +bool wxPNMHandler::DoCanRead( wxInputStream& stream ) +{ + Skip_Comment(stream); + + if ( stream.GetC() == 'P' ) + { + switch ( stream.GetC() ) + { + case '2': // ASCII Grey + case '3': // ASCII RGB + case '5': // RAW Grey + case '6': // RAW RGB + return true; + } + } + + return false; +} + + +#endif // wxUSE_STREAMS + +#endif // wxUSE_IMAGE && wxUSE_PNM diff --git a/Source/3rd Party/wx/src/common/imagtga.cpp b/Source/3rd Party/wx/src/common/imagtga.cpp index 458bc27c7..c9b39dce7 100644 --- a/Source/3rd Party/wx/src/common/imagtga.cpp +++ b/Source/3rd Party/wx/src/common/imagtga.cpp @@ -1,750 +1,750 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: imagtga.cpp -// Purpose: wxImage TGA handler -// Author: Seth Jackson -// CVS-ID: $Id: imagtga.cpp 43681 2006-11-27 15:01:58Z VZ $ -// Copyright: (c) 2005 Seth Jackson -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_TGA - -#ifndef WX_PRECOMP - #include "wx/palette.h" -#endif - -#include "wx/imagtga.h" -#include "wx/log.h" -#include "wx/scopeguard.h" - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// TGA error codes. -enum -{ - wxTGA_OK = 0, - wxTGA_INVFORMAT = 1, - wxTGA_MEMERR = 2 -}; - -// TGA header bytes. -enum -{ - HDR_OFFSET = 0, - HDR_COLORTYPE = 1, - HDR_IMAGETYPE = 2, - HDR_PALETTESTART = 3, - HDR_PALETTELENGTH = 5, - HDR_PALETTEBITS = 7, - HDR_XORIGIN = 8, - HDR_YORIGIN = 10, - HDR_WIDTH = 12, - HDR_HEIGHT = 14, - HDR_BPP = 16, - HDR_ORIENTATION = 17, - HDR_SIZE -}; - -// TGA color types. -enum -{ - wxTGA_UNMAPPED = 0, - wxTGA_MAPPED = 1 -}; - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxTGAHandler, wxImageHandler) - -#if wxUSE_STREAMS - -// ---------------------------------------------------------------------------- -// worker functions -// ---------------------------------------------------------------------------- - -static -void FlipTGA(unsigned char* imageData, int width, int height, short pixelSize) -{ - int lineLength = width * pixelSize; - unsigned char *line1 = imageData; - unsigned char *line2 = &imageData[lineLength * (height - 1)]; - - unsigned char temp; - for ( ; line1 < line2; line2 -= (lineLength * 2)) - { - for (int index = 0; index < lineLength; line1++, line2++, index++) - { - temp = *line1; - *line1 = *line2; - *line2 = temp; - } - } -} - -static -void DecodeRLE(unsigned char* imageData, unsigned long imageSize, - short pixelSize, wxInputStream& stream) -{ - unsigned long index = 0; - unsigned char current; - unsigned int length; - unsigned char buf[4]; - - while (index < imageSize) - { - current = stream.GetC(); - - // RLE packet. - if ( current & 0x80 ) - { - // Get the run length of the packet. - current &= 0x7f; - - current++; - - length = current; - - index += current * pixelSize; - - // Repeat the pixel length times. - stream.Read(buf, pixelSize); - - for (unsigned int i = 0; i < length; i++) - { - memcpy(imageData, buf, pixelSize); - - imageData += pixelSize; - } - } - else // Raw packet. - { - // Get the run length of the packet. - current++; - - length = current * pixelSize; - - index += length; - - // Write the next length pixels directly to the image data. - stream.Read(imageData, length); - - imageData += length; - } - } -} - -static -int ReadTGA(wxImage* image, wxInputStream& stream) -{ - // Read in the TGA header - unsigned char hdr[HDR_SIZE]; - stream.Read(hdr, HDR_SIZE); - - short offset = hdr[HDR_OFFSET] + HDR_SIZE; - short colorType = hdr[HDR_COLORTYPE]; - short imageType = hdr[HDR_IMAGETYPE]; - int paletteLength = hdr[HDR_PALETTELENGTH] + 256 * hdr[HDR_PALETTELENGTH + 1]; - int width = (hdr[HDR_WIDTH] + 256 * hdr[HDR_WIDTH + 1]) - - (hdr[HDR_XORIGIN] + 256 * hdr[HDR_XORIGIN + 1]); - int height = (hdr[HDR_HEIGHT] + 256 * hdr[HDR_HEIGHT + 1]) - - (hdr[HDR_YORIGIN] + 256 * hdr[HDR_YORIGIN + 1]); - short bpp = hdr[HDR_BPP]; - short orientation = hdr[HDR_ORIENTATION] & 0x20; - - image->Create(width, height); - - if (!image->Ok()) - { - return wxTGA_MEMERR; - } - - const short pixelSize = bpp / 8; - - const unsigned long imageSize = width * height * pixelSize; - - unsigned char *imageData = (unsigned char* )malloc(imageSize); - - if (!imageData) - { - return wxTGA_MEMERR; - } - - wxON_BLOCK_EXIT1(free, imageData); - - unsigned char *dst = image->GetData(); - - unsigned char* alpha = NULL; - if (bpp == 16 || bpp == 32) - { - image->SetAlpha(); - - alpha = image->GetAlpha(); - } - - // Seek from the offset we got from the TGA header. - stream.SeekI(offset, wxFromStart); - - // Load a palette if we have one. - if (colorType == wxTGA_MAPPED) - { - unsigned char buf[3]; - - unsigned char* r = new unsigned char[paletteLength]; - unsigned char* g = new unsigned char[paletteLength]; - unsigned char* b = new unsigned char[paletteLength]; - - for (int i = 0; i < paletteLength; i++) - { - stream.Read(buf, 3); - - r[i] = buf[2]; - g[i] = buf[1]; - b[i] = buf[0]; - } - -#if wxUSE_PALETTE - // Set the palette of the image. - image->SetPalette(wxPalette(paletteLength, r, g, b)); -#endif // wxUSE_PALETTE - - delete[] r; - delete[] g; - delete[] b; - } - - // Handle the various TGA formats we support. - - switch (imageType) - { -#if wxUSE_PALETTE - // Raw indexed. - - case 1: - { - const wxPalette& palette = image->GetPalette(); - unsigned char r; - unsigned char g; - unsigned char b; - - // No compression read the data directly to imageData. - - stream.Read(imageData, imageSize); - - // If orientation == 0, then the image is stored upside down. - // We need to store it right side up. - - if (orientation == 0) - { - FlipTGA(imageData, width, height, pixelSize); - } - - // Handle the different pixel depths. - - switch (bpp) - { - // 8 bpp. - - case 8: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - palette.GetRGB(imageData[index], &r, &g, &b); - - *(dst++) = r; - *(dst++) = g; - *(dst++) = b; - } - } - break; - - // 16 bpp. - - case 16: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - palette.GetRGB(imageData[index], &r, &g, &b); - - *(dst++) = r; - *(dst++) = g; - *(dst++) = b; - *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; - } - } - break; - - default: - return wxTGA_INVFORMAT; - } - } - break; -#endif // wxUSE_PALETTE - - // Raw RGB. - - case 2: - { - // No compression read the data directly to imageData. - - stream.Read(imageData, imageSize); - - // If orientation == 0, then the image is stored upside down. - // We need to store it right side up. - - if (orientation == 0) - { - FlipTGA(imageData, width, height, pixelSize); - } - - // Handle the different pixel depths. - - switch (bpp) - { - //16 bpp. - - case 16: - { - unsigned char temp; - - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - temp = (imageData[index + 1] & 0x7c) << 1; - temp |= temp >> 5; - *(dst++) = temp; - - temp = ((imageData[index + 1] & 0x03) << 6) | ((imageData[index] & 0xe0) >> 2); - temp |= temp >> 5; - *(dst++) = temp; - - temp = (imageData[index] & 0x1f) << 3; - temp |= temp >> 5; - *(dst++) = temp; - - *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; - } - } - break; - - // 24 bpp. - - case 24: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index + 2]; - *(dst++) = imageData[index + 1]; - *(dst++) = imageData[index]; - } - } - break; - - // 32 bpp. - - case 32: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index + 2]; - *(dst++) = imageData[index + 1]; - *(dst++) = imageData[index]; - *(alpha++) = imageData[index + 3]; - } - } - break; - - default: - return wxTGA_INVFORMAT; - } - } - break; - - // Raw grayscale. - - case 3: - { - // No compression read the data directly to imageData. - - stream.Read(imageData, imageSize); - - // If orientation == 0, then the image is stored upside down. - // We need to store it right side up. - - if (orientation == 0) - { - FlipTGA(imageData, width, height, pixelSize); - } - - // Handle the different pixel depths. - - switch (bpp) - { - // 8 bpp. - - case 8: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - } - } - break; - - // 16 bpp. - - case 16: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - *(alpha++) = imageData[index + 1]; - } - } - break; - - default: - return wxTGA_INVFORMAT; - } - } - break; - -#if wxUSE_PALETTE - // RLE indexed. - - case 9: - { - const wxPalette& palette = image->GetPalette(); - unsigned char r; - unsigned char g; - unsigned char b; - - // Decode the RLE data. - - DecodeRLE(imageData, imageSize, pixelSize, stream); - - // If orientation == 0, then the image is stored upside down. - // We need to store it right side up. - - if (orientation == 0) - { - FlipTGA(imageData, width, height, pixelSize); - } - - // Handle the different pixel depths. - - switch (bpp) - { - // 8 bpp. - - case 8: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - palette.GetRGB(imageData[index], &r, &g, &b); - - *(dst++) = r; - *(dst++) = g; - *(dst++) = b; - } - } - break; - - // 16 bpp. - - case 16: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - palette.GetRGB(imageData[index], &r, &g, &b); - - *(dst++) = r; - *(dst++) = g; - *(dst++) = b; - *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; - } - } - break; - - default: - return wxTGA_INVFORMAT; - } - } - break; -#endif // wxUSE_PALETTE - - // RLE RGB. - - case 10: - { - // Decode the RLE data. - - DecodeRLE(imageData, imageSize, pixelSize, stream); - - // If orientation == 0, then the image is stored upside down. - // We need to store it right side up. - - if (orientation == 0) - { - FlipTGA(imageData, width, height, pixelSize); - } - - // Handle the different pixel depths. - - switch (bpp) - { - //16 bpp. - - case 16: - { - unsigned char temp; - - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - temp = (imageData[index + 1] & 0x7c) << 1; - temp |= temp >> 5; - *(dst++) = temp; - - temp = ((imageData[index + 1] & 0x03) << 6) | ((imageData[index] & 0xe0) >> 2); - temp |= temp >> 5; - *(dst++) = temp; - - temp = (imageData[index] & 0x1f) << 3; - temp |= temp >> 5; - *(dst++) = temp; - - *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; - } - } - break; - - // 24 bpp. - - case 24: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index + 2]; - *(dst++) = imageData[index + 1]; - *(dst++) = imageData[index]; - } - } - break; - - // 32 bpp. - - case 32: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index + 2]; - *(dst++) = imageData[index + 1]; - *(dst++) = imageData[index]; - *(alpha++) = imageData[index + 3]; - } - } - break; - - default: - return wxTGA_INVFORMAT; - } - } - break; - - // RLE grayscale. - - case 11: - { - // Decode the RLE data. - - DecodeRLE(imageData, imageSize, pixelSize, stream); - - // If orientation == 0, then the image is stored upside down. - // We need to store it right side up. - - if (orientation == 0) - { - FlipTGA(imageData, width, height, pixelSize); - } - - // Handle the different pixel depths. - - switch (bpp) - { - // 8 bpp. - - case 8: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - } - } - break; - - // 16 bpp. - - case 16: - { - for (unsigned long index = 0; index < imageSize; index += pixelSize) - { - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - *(dst++) = imageData[index]; - *(alpha++) = imageData[index + 1]; - } - } - break; - - default: - return wxTGA_INVFORMAT; - } - } - break; - - default: - return wxTGA_INVFORMAT; - } - - return wxTGA_OK; -} - -static -int SaveTGA(wxImage* WXUNUSED(image), wxOutputStream& WXUNUSED(stream)) -{ - wxLogError(wxT("Saving in TGA format is not implemented.")); - - return wxTGA_OK; -} - -// ---------------------------------------------------------------------------- -// wxTGAHandler -// ---------------------------------------------------------------------------- - -bool wxTGAHandler::LoadFile(wxImage* image, - wxInputStream& stream, - bool verbose, - int WXUNUSED(index)) -{ - if ( !CanRead(stream) ) - { - if ( verbose ) - wxLogError(wxT("TGA: this is not a TGA file.")); - - return false; - } - - image->Destroy(); - - int error = ReadTGA(image, stream); - if ( error != wxTGA_OK ) - { - if ( verbose ) - { - switch ( error ) - { - case wxTGA_INVFORMAT: - wxLogError(wxT("TGA: image format unsupported.")); - break; - - case wxTGA_MEMERR: - wxLogError(wxT("TGA: couldn't allocate memory.")); - break; - - default: - wxLogError(wxT("TGA: unknown error!")); - } - } - - image->Destroy(); - - return false; - } - - return true; -} - -bool wxTGAHandler::SaveFile(wxImage* image, wxOutputStream& stream, bool verbose) -{ - int error = SaveTGA(image, stream); - - if ( error != wxTGA_OK ) - { - if ( verbose ) - { - switch ( error ) - { - case wxTGA_INVFORMAT: - wxLogError(wxT("TGA: invalid image.")); - break; - - case wxTGA_MEMERR: - wxLogError(wxT("TGA: couldn't allocate memory.")); - break; - - default: - wxLogError(wxT("TGA: unknown error!")); - } - } - - return false; - } - - return true; -} - -bool wxTGAHandler::DoCanRead(wxInputStream& stream) -{ - // read the fixed-size TGA headers - unsigned char hdr[HDR_SIZE]; - stream.Read(hdr, HDR_SIZE); - - // Check wether we can read the file or not. - - short colorType = hdr[HDR_COLORTYPE]; - if ( colorType != wxTGA_UNMAPPED && colorType != wxTGA_MAPPED ) - { - return false; - } - - short imageType = hdr[HDR_IMAGETYPE]; - if ( imageType == 0 || imageType == 32 || imageType == 33 ) - { - return false; - } - - short bpp = hdr[HDR_BPP]; - if ( bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32 ) - { - return false; - } - - return true; -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_IMAGE && wxUSE_TGA +///////////////////////////////////////////////////////////////////////////// +// Name: imagtga.cpp +// Purpose: wxImage TGA handler +// Author: Seth Jackson +// CVS-ID: $Id: imagtga.cpp 43681 2006-11-27 15:01:58Z VZ $ +// Copyright: (c) 2005 Seth Jackson +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_TGA + +#ifndef WX_PRECOMP + #include "wx/palette.h" +#endif + +#include "wx/imagtga.h" +#include "wx/log.h" +#include "wx/scopeguard.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// TGA error codes. +enum +{ + wxTGA_OK = 0, + wxTGA_INVFORMAT = 1, + wxTGA_MEMERR = 2 +}; + +// TGA header bytes. +enum +{ + HDR_OFFSET = 0, + HDR_COLORTYPE = 1, + HDR_IMAGETYPE = 2, + HDR_PALETTESTART = 3, + HDR_PALETTELENGTH = 5, + HDR_PALETTEBITS = 7, + HDR_XORIGIN = 8, + HDR_YORIGIN = 10, + HDR_WIDTH = 12, + HDR_HEIGHT = 14, + HDR_BPP = 16, + HDR_ORIENTATION = 17, + HDR_SIZE +}; + +// TGA color types. +enum +{ + wxTGA_UNMAPPED = 0, + wxTGA_MAPPED = 1 +}; + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxTGAHandler, wxImageHandler) + +#if wxUSE_STREAMS + +// ---------------------------------------------------------------------------- +// worker functions +// ---------------------------------------------------------------------------- + +static +void FlipTGA(unsigned char* imageData, int width, int height, short pixelSize) +{ + int lineLength = width * pixelSize; + unsigned char *line1 = imageData; + unsigned char *line2 = &imageData[lineLength * (height - 1)]; + + unsigned char temp; + for ( ; line1 < line2; line2 -= (lineLength * 2)) + { + for (int index = 0; index < lineLength; line1++, line2++, index++) + { + temp = *line1; + *line1 = *line2; + *line2 = temp; + } + } +} + +static +void DecodeRLE(unsigned char* imageData, unsigned long imageSize, + short pixelSize, wxInputStream& stream) +{ + unsigned long index = 0; + unsigned char current; + unsigned int length; + unsigned char buf[4]; + + while (index < imageSize) + { + current = stream.GetC(); + + // RLE packet. + if ( current & 0x80 ) + { + // Get the run length of the packet. + current &= 0x7f; + + current++; + + length = current; + + index += current * pixelSize; + + // Repeat the pixel length times. + stream.Read(buf, pixelSize); + + for (unsigned int i = 0; i < length; i++) + { + memcpy(imageData, buf, pixelSize); + + imageData += pixelSize; + } + } + else // Raw packet. + { + // Get the run length of the packet. + current++; + + length = current * pixelSize; + + index += length; + + // Write the next length pixels directly to the image data. + stream.Read(imageData, length); + + imageData += length; + } + } +} + +static +int ReadTGA(wxImage* image, wxInputStream& stream) +{ + // Read in the TGA header + unsigned char hdr[HDR_SIZE]; + stream.Read(hdr, HDR_SIZE); + + short offset = hdr[HDR_OFFSET] + HDR_SIZE; + short colorType = hdr[HDR_COLORTYPE]; + short imageType = hdr[HDR_IMAGETYPE]; + int paletteLength = hdr[HDR_PALETTELENGTH] + 256 * hdr[HDR_PALETTELENGTH + 1]; + int width = (hdr[HDR_WIDTH] + 256 * hdr[HDR_WIDTH + 1]) - + (hdr[HDR_XORIGIN] + 256 * hdr[HDR_XORIGIN + 1]); + int height = (hdr[HDR_HEIGHT] + 256 * hdr[HDR_HEIGHT + 1]) - + (hdr[HDR_YORIGIN] + 256 * hdr[HDR_YORIGIN + 1]); + short bpp = hdr[HDR_BPP]; + short orientation = hdr[HDR_ORIENTATION] & 0x20; + + image->Create(width, height); + + if (!image->Ok()) + { + return wxTGA_MEMERR; + } + + const short pixelSize = bpp / 8; + + const unsigned long imageSize = width * height * pixelSize; + + unsigned char *imageData = (unsigned char* )malloc(imageSize); + + if (!imageData) + { + return wxTGA_MEMERR; + } + + wxON_BLOCK_EXIT1(free, imageData); + + unsigned char *dst = image->GetData(); + + unsigned char* alpha = NULL; + if (bpp == 16 || bpp == 32) + { + image->SetAlpha(); + + alpha = image->GetAlpha(); + } + + // Seek from the offset we got from the TGA header. + stream.SeekI(offset, wxFromStart); + + // Load a palette if we have one. + if (colorType == wxTGA_MAPPED) + { + unsigned char buf[3]; + + unsigned char* r = new unsigned char[paletteLength]; + unsigned char* g = new unsigned char[paletteLength]; + unsigned char* b = new unsigned char[paletteLength]; + + for (int i = 0; i < paletteLength; i++) + { + stream.Read(buf, 3); + + r[i] = buf[2]; + g[i] = buf[1]; + b[i] = buf[0]; + } + +#if wxUSE_PALETTE + // Set the palette of the image. + image->SetPalette(wxPalette(paletteLength, r, g, b)); +#endif // wxUSE_PALETTE + + delete[] r; + delete[] g; + delete[] b; + } + + // Handle the various TGA formats we support. + + switch (imageType) + { +#if wxUSE_PALETTE + // Raw indexed. + + case 1: + { + const wxPalette& palette = image->GetPalette(); + unsigned char r; + unsigned char g; + unsigned char b; + + // No compression read the data directly to imageData. + + stream.Read(imageData, imageSize); + + // If orientation == 0, then the image is stored upside down. + // We need to store it right side up. + + if (orientation == 0) + { + FlipTGA(imageData, width, height, pixelSize); + } + + // Handle the different pixel depths. + + switch (bpp) + { + // 8 bpp. + + case 8: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + palette.GetRGB(imageData[index], &r, &g, &b); + + *(dst++) = r; + *(dst++) = g; + *(dst++) = b; + } + } + break; + + // 16 bpp. + + case 16: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + palette.GetRGB(imageData[index], &r, &g, &b); + + *(dst++) = r; + *(dst++) = g; + *(dst++) = b; + *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; + } + } + break; + + default: + return wxTGA_INVFORMAT; + } + } + break; +#endif // wxUSE_PALETTE + + // Raw RGB. + + case 2: + { + // No compression read the data directly to imageData. + + stream.Read(imageData, imageSize); + + // If orientation == 0, then the image is stored upside down. + // We need to store it right side up. + + if (orientation == 0) + { + FlipTGA(imageData, width, height, pixelSize); + } + + // Handle the different pixel depths. + + switch (bpp) + { + //16 bpp. + + case 16: + { + unsigned char temp; + + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + temp = (imageData[index + 1] & 0x7c) << 1; + temp |= temp >> 5; + *(dst++) = temp; + + temp = ((imageData[index + 1] & 0x03) << 6) | ((imageData[index] & 0xe0) >> 2); + temp |= temp >> 5; + *(dst++) = temp; + + temp = (imageData[index] & 0x1f) << 3; + temp |= temp >> 5; + *(dst++) = temp; + + *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; + } + } + break; + + // 24 bpp. + + case 24: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index + 2]; + *(dst++) = imageData[index + 1]; + *(dst++) = imageData[index]; + } + } + break; + + // 32 bpp. + + case 32: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index + 2]; + *(dst++) = imageData[index + 1]; + *(dst++) = imageData[index]; + *(alpha++) = imageData[index + 3]; + } + } + break; + + default: + return wxTGA_INVFORMAT; + } + } + break; + + // Raw grayscale. + + case 3: + { + // No compression read the data directly to imageData. + + stream.Read(imageData, imageSize); + + // If orientation == 0, then the image is stored upside down. + // We need to store it right side up. + + if (orientation == 0) + { + FlipTGA(imageData, width, height, pixelSize); + } + + // Handle the different pixel depths. + + switch (bpp) + { + // 8 bpp. + + case 8: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + } + } + break; + + // 16 bpp. + + case 16: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + *(alpha++) = imageData[index + 1]; + } + } + break; + + default: + return wxTGA_INVFORMAT; + } + } + break; + +#if wxUSE_PALETTE + // RLE indexed. + + case 9: + { + const wxPalette& palette = image->GetPalette(); + unsigned char r; + unsigned char g; + unsigned char b; + + // Decode the RLE data. + + DecodeRLE(imageData, imageSize, pixelSize, stream); + + // If orientation == 0, then the image is stored upside down. + // We need to store it right side up. + + if (orientation == 0) + { + FlipTGA(imageData, width, height, pixelSize); + } + + // Handle the different pixel depths. + + switch (bpp) + { + // 8 bpp. + + case 8: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + palette.GetRGB(imageData[index], &r, &g, &b); + + *(dst++) = r; + *(dst++) = g; + *(dst++) = b; + } + } + break; + + // 16 bpp. + + case 16: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + palette.GetRGB(imageData[index], &r, &g, &b); + + *(dst++) = r; + *(dst++) = g; + *(dst++) = b; + *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; + } + } + break; + + default: + return wxTGA_INVFORMAT; + } + } + break; +#endif // wxUSE_PALETTE + + // RLE RGB. + + case 10: + { + // Decode the RLE data. + + DecodeRLE(imageData, imageSize, pixelSize, stream); + + // If orientation == 0, then the image is stored upside down. + // We need to store it right side up. + + if (orientation == 0) + { + FlipTGA(imageData, width, height, pixelSize); + } + + // Handle the different pixel depths. + + switch (bpp) + { + //16 bpp. + + case 16: + { + unsigned char temp; + + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + temp = (imageData[index + 1] & 0x7c) << 1; + temp |= temp >> 5; + *(dst++) = temp; + + temp = ((imageData[index + 1] & 0x03) << 6) | ((imageData[index] & 0xe0) >> 2); + temp |= temp >> 5; + *(dst++) = temp; + + temp = (imageData[index] & 0x1f) << 3; + temp |= temp >> 5; + *(dst++) = temp; + + *(alpha++) = (imageData[index + 1] & 0x80) ? 0 : 255; + } + } + break; + + // 24 bpp. + + case 24: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index + 2]; + *(dst++) = imageData[index + 1]; + *(dst++) = imageData[index]; + } + } + break; + + // 32 bpp. + + case 32: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index + 2]; + *(dst++) = imageData[index + 1]; + *(dst++) = imageData[index]; + *(alpha++) = imageData[index + 3]; + } + } + break; + + default: + return wxTGA_INVFORMAT; + } + } + break; + + // RLE grayscale. + + case 11: + { + // Decode the RLE data. + + DecodeRLE(imageData, imageSize, pixelSize, stream); + + // If orientation == 0, then the image is stored upside down. + // We need to store it right side up. + + if (orientation == 0) + { + FlipTGA(imageData, width, height, pixelSize); + } + + // Handle the different pixel depths. + + switch (bpp) + { + // 8 bpp. + + case 8: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + } + } + break; + + // 16 bpp. + + case 16: + { + for (unsigned long index = 0; index < imageSize; index += pixelSize) + { + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + *(dst++) = imageData[index]; + *(alpha++) = imageData[index + 1]; + } + } + break; + + default: + return wxTGA_INVFORMAT; + } + } + break; + + default: + return wxTGA_INVFORMAT; + } + + return wxTGA_OK; +} + +static +int SaveTGA(wxImage* WXUNUSED(image), wxOutputStream& WXUNUSED(stream)) +{ + wxLogError(wxT("Saving in TGA format is not implemented.")); + + return wxTGA_OK; +} + +// ---------------------------------------------------------------------------- +// wxTGAHandler +// ---------------------------------------------------------------------------- + +bool wxTGAHandler::LoadFile(wxImage* image, + wxInputStream& stream, + bool verbose, + int WXUNUSED(index)) +{ + if ( !CanRead(stream) ) + { + if ( verbose ) + wxLogError(wxT("TGA: this is not a TGA file.")); + + return false; + } + + image->Destroy(); + + int error = ReadTGA(image, stream); + if ( error != wxTGA_OK ) + { + if ( verbose ) + { + switch ( error ) + { + case wxTGA_INVFORMAT: + wxLogError(wxT("TGA: image format unsupported.")); + break; + + case wxTGA_MEMERR: + wxLogError(wxT("TGA: couldn't allocate memory.")); + break; + + default: + wxLogError(wxT("TGA: unknown error!")); + } + } + + image->Destroy(); + + return false; + } + + return true; +} + +bool wxTGAHandler::SaveFile(wxImage* image, wxOutputStream& stream, bool verbose) +{ + int error = SaveTGA(image, stream); + + if ( error != wxTGA_OK ) + { + if ( verbose ) + { + switch ( error ) + { + case wxTGA_INVFORMAT: + wxLogError(wxT("TGA: invalid image.")); + break; + + case wxTGA_MEMERR: + wxLogError(wxT("TGA: couldn't allocate memory.")); + break; + + default: + wxLogError(wxT("TGA: unknown error!")); + } + } + + return false; + } + + return true; +} + +bool wxTGAHandler::DoCanRead(wxInputStream& stream) +{ + // read the fixed-size TGA headers + unsigned char hdr[HDR_SIZE]; + stream.Read(hdr, HDR_SIZE); + + // Check wether we can read the file or not. + + short colorType = hdr[HDR_COLORTYPE]; + if ( colorType != wxTGA_UNMAPPED && colorType != wxTGA_MAPPED ) + { + return false; + } + + short imageType = hdr[HDR_IMAGETYPE]; + if ( imageType == 0 || imageType == 32 || imageType == 33 ) + { + return false; + } + + short bpp = hdr[HDR_BPP]; + if ( bpp != 8 && bpp != 16 && bpp != 24 && bpp != 32 ) + { + return false; + } + + return true; +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_IMAGE && wxUSE_TGA diff --git a/Source/3rd Party/wx/src/common/imagtiff.cpp b/Source/3rd Party/wx/src/common/imagtiff.cpp index 4cce98f47..7a48cf51c 100644 --- a/Source/3rd Party/wx/src/common/imagtiff.cpp +++ b/Source/3rd Party/wx/src/common/imagtiff.cpp @@ -1,525 +1,525 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagtiff.cpp -// Purpose: wxImage TIFF handler -// Author: Robert Roebling -// RCS-ID: $Id: imagtiff.cpp 60897 2009-06-04 22:28:48Z VZ $ -// Copyright: (c) Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_LIBTIFF - -#include "wx/imagtiff.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/app.h" - #include "wx/intl.h" - #include "wx/bitmap.h" - #include "wx/module.h" -#endif - -extern "C" -{ - #include "tiff.h" - #include "tiffio.h" -} -#include "wx/filefn.h" -#include "wx/wfstream.h" - -#ifndef TIFFLINKAGEMODE - #if defined(__WATCOMC__) && defined(__WXMGL__) - #define TIFFLINKAGEMODE cdecl - #else - #define TIFFLINKAGEMODE LINKAGEMODE - #endif -#endif - -//----------------------------------------------------------------------------- -// wxTIFFHandler -//----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxTIFFHandler,wxImageHandler) - -#if wxUSE_STREAMS - -// helper to translate our, possibly 64 bit, wxFileOffset to TIFF, always 32 -// bit, toff_t -static toff_t wxFileOffsetToTIFF(wxFileOffset ofs) -{ - if ( ofs == wxInvalidOffset ) - return (toff_t)-1; - - toff_t tofs = wx_truncate_cast(toff_t, ofs); - wxCHECK_MSG( (wxFileOffset)tofs == ofs, (toff_t)-1, - _T("TIFF library doesn't support large files") ); - - return tofs; -} - -// another helper to convert standard seek mode to our -static wxSeekMode wxSeekModeFromTIFF(int whence) -{ - switch ( whence ) - { - case SEEK_SET: - return wxFromStart; - - case SEEK_CUR: - return wxFromCurrent; - - case SEEK_END: - return wxFromEnd; - - default: - return wxFromCurrent; - } -} - -extern "C" -{ - -tsize_t TIFFLINKAGEMODE -wxTIFFNullProc(thandle_t WXUNUSED(handle), - tdata_t WXUNUSED(buf), - tsize_t WXUNUSED(size)) -{ - return (tsize_t) -1; -} - -tsize_t TIFFLINKAGEMODE -wxTIFFReadProc(thandle_t handle, tdata_t buf, tsize_t size) -{ - wxInputStream *stream = (wxInputStream*) handle; - stream->Read( (void*) buf, (size_t) size ); - return wx_truncate_cast(tsize_t, stream->LastRead()); -} - -tsize_t TIFFLINKAGEMODE -wxTIFFWriteProc(thandle_t handle, tdata_t buf, tsize_t size) -{ - wxOutputStream *stream = (wxOutputStream*) handle; - stream->Write( (void*) buf, (size_t) size ); - return wx_truncate_cast(tsize_t, stream->LastWrite()); -} - -toff_t TIFFLINKAGEMODE -wxTIFFSeekIProc(thandle_t handle, toff_t off, int whence) -{ - wxInputStream *stream = (wxInputStream*) handle; - - return wxFileOffsetToTIFF(stream->SeekI((wxFileOffset)off, - wxSeekModeFromTIFF(whence))); -} - -toff_t TIFFLINKAGEMODE -wxTIFFSeekOProc(thandle_t handle, toff_t off, int whence) -{ - wxOutputStream *stream = (wxOutputStream*) handle; - - return wxFileOffsetToTIFF(stream->SeekO((wxFileOffset)off, - wxSeekModeFromTIFF(whence))); -} - -int TIFFLINKAGEMODE -wxTIFFCloseIProc(thandle_t WXUNUSED(handle)) -{ - // there is no need to close the input stream - return 0; -} - -int TIFFLINKAGEMODE -wxTIFFCloseOProc(thandle_t handle) -{ - wxOutputStream *stream = (wxOutputStream*) handle; - - return stream->Close() ? 0 : -1; -} - -toff_t TIFFLINKAGEMODE -wxTIFFSizeProc(thandle_t handle) -{ - wxStreamBase *stream = (wxStreamBase*) handle; - return (toff_t) stream->GetSize(); -} - -int TIFFLINKAGEMODE -wxTIFFMapProc(thandle_t WXUNUSED(handle), - tdata_t* WXUNUSED(pbase), - toff_t* WXUNUSED(psize)) -{ - return 0; -} - -void TIFFLINKAGEMODE -wxTIFFUnmapProc(thandle_t WXUNUSED(handle), - tdata_t WXUNUSED(base), - toff_t WXUNUSED(size)) -{ -} - -static void -TIFFwxWarningHandler(const char* module, - const char* WXUNUSED_IN_UNICODE(fmt), - va_list WXUNUSED_IN_UNICODE(ap)) -{ - if (module != NULL) - wxLogWarning(_("tiff module: %s"), wxString::FromAscii(module).c_str()); - - // FIXME: this is not terrible informative but better than crashing! -#if wxUSE_UNICODE - wxLogWarning(_("TIFF library warning.")); -#else - wxVLogWarning(fmt, ap); -#endif -} - -static void -TIFFwxErrorHandler(const char* module, - const char* WXUNUSED_IN_UNICODE(fmt), - va_list WXUNUSED_IN_UNICODE(ap)) -{ - if (module != NULL) - wxLogError(_("tiff module: %s"), wxString::FromAscii(module).c_str()); - - // FIXME: as above -#if wxUSE_UNICODE - wxLogError(_("TIFF library error.")); -#else - wxVLogError(fmt, ap); -#endif -} - -} // extern "C" - -TIFF* -TIFFwxOpen(wxInputStream &stream, const char* name, const char* mode) -{ - TIFF* tif = TIFFClientOpen(name, mode, - (thandle_t) &stream, - wxTIFFReadProc, wxTIFFNullProc, - wxTIFFSeekIProc, wxTIFFCloseIProc, wxTIFFSizeProc, - wxTIFFMapProc, wxTIFFUnmapProc); - - return tif; -} - -TIFF* -TIFFwxOpen(wxOutputStream &stream, const char* name, const char* mode) -{ - TIFF* tif = TIFFClientOpen(name, mode, - (thandle_t) &stream, - wxTIFFNullProc, wxTIFFWriteProc, - wxTIFFSeekOProc, wxTIFFCloseOProc, wxTIFFSizeProc, - wxTIFFMapProc, wxTIFFUnmapProc); - - return tif; -} - -wxTIFFHandler::wxTIFFHandler() -{ - m_name = wxT("TIFF file"); - m_extension = wxT("tif"); - m_type = wxBITMAP_TYPE_TIF; - m_mime = wxT("image/tiff"); - TIFFSetWarningHandler((TIFFErrorHandler) TIFFwxWarningHandler); - TIFFSetErrorHandler((TIFFErrorHandler) TIFFwxErrorHandler); -} - -bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int index ) -{ - if (index == -1) - index = 0; - - image->Destroy(); - - TIFF *tif = TIFFwxOpen( stream, "image", "r" ); - - if (!tif) - { - if (verbose) - wxLogError( _("TIFF: Error loading image.") ); - - return false; - } - - if (!TIFFSetDirectory( tif, (tdir_t)index )) - { - if (verbose) - wxLogError( _("Invalid TIFF image index.") ); - - TIFFClose( tif ); - - return false; - } - - uint32 w, h; - uint32 *raster; - - TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &w ); - TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &h ); - - uint16 extraSamples; - uint16* samplesInfo; - TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, - &extraSamples, &samplesInfo); - const bool hasAlpha = (extraSamples == 1 && - (samplesInfo[0] == EXTRASAMPLE_ASSOCALPHA || - samplesInfo[0] == EXTRASAMPLE_UNASSALPHA)); - - // guard against integer overflow during multiplication which could result - // in allocating a too small buffer and then overflowing it - const double bytesNeeded = (double)w * (double)h * sizeof(uint32); - if ( bytesNeeded >= 4294967295U /* UINT32_MAX */ ) - { - if ( verbose ) - wxLogError( _("TIFF: Image size is abnormally big.") ); - - TIFFClose(tif); - - return false; - } - - raster = (uint32*) _TIFFmalloc( bytesNeeded ); - - if (!raster) - { - if (verbose) - wxLogError( _("TIFF: Couldn't allocate memory.") ); - - TIFFClose( tif ); - - return false; - } - - image->Create( (int)w, (int)h ); - if (!image->Ok()) - { - if (verbose) - wxLogError( _("TIFF: Couldn't allocate memory.") ); - - _TIFFfree( raster ); - TIFFClose( tif ); - - return false; - } - - if ( hasAlpha ) - image->SetAlpha(); - - if (!TIFFReadRGBAImage( tif, w, h, raster, 0 )) - { - if (verbose) - wxLogError( _("TIFF: Error reading image.") ); - - _TIFFfree( raster ); - image->Destroy(); - TIFFClose( tif ); - - return false; - } - - unsigned char *ptr = image->GetData(); - ptr += w*3*(h-1); - - unsigned char *alpha = hasAlpha ? image->GetAlpha() : NULL; - if ( hasAlpha ) - alpha += w*(h-1); - - uint32 pos = 0; - - for (uint32 i = 0; i < h; i++) - { - for (uint32 j = 0; j < w; j++) - { - *(ptr++) = (unsigned char)TIFFGetR(raster[pos]); - *(ptr++) = (unsigned char)TIFFGetG(raster[pos]); - *(ptr++) = (unsigned char)TIFFGetB(raster[pos]); - if ( hasAlpha ) - *(alpha++) = (unsigned char)TIFFGetA(raster[pos]); - - pos++; - } - - // subtract line we just added plus one line: - ptr -= 2*w*3; - if ( hasAlpha ) - alpha -= 2*w; - } - - _TIFFfree( raster ); - - TIFFClose( tif ); - - return true; -} - -int wxTIFFHandler::GetImageCount( wxInputStream& stream ) -{ - TIFF *tif = TIFFwxOpen( stream, "image", "r" ); - - if (!tif) - return 0; - - int dircount = 0; // according to the libtiff docs, dircount should be set to 1 here??? - do { - dircount++; - } while (TIFFReadDirectory(tif)); - - TIFFClose( tif ); - - return dircount; -} - -bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) -{ - TIFF *tif = TIFFwxOpen( stream, "image", "w" ); - - if (!tif) - { - if (verbose) - wxLogError( _("TIFF: Error saving image.") ); - - return false; - } - - TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32)image->GetWidth()); - TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32)image->GetHeight()); - TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); - TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); - - if ( image->HasOption(wxIMAGE_OPTION_RESOLUTIONX) && - image->HasOption(wxIMAGE_OPTION_RESOLUTIONY) ) - { - TIFFSetField(tif, TIFFTAG_XRESOLUTION, - (float)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX)); - TIFFSetField(tif, TIFFTAG_YRESOLUTION, - (float)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY)); - } - - int spp = image->GetOptionInt(wxIMAGE_OPTION_SAMPLESPERPIXEL); - if ( !spp ) - spp = 3; - - int bpp = image->GetOptionInt(wxIMAGE_OPTION_BITSPERSAMPLE); - if ( !bpp ) - bpp=8; - - int compression = image->GetOptionInt(wxIMAGE_OPTION_COMPRESSION); - if ( !compression ) - { - // we can't use COMPRESSION_LZW because current version of libtiff - // doesn't implement it ("no longer implemented due to Unisys patent - // enforcement") and other compression methods are lossy so we - // shouldn't use them by default -- and the only remaining one is none - compression = COMPRESSION_NONE; - } - - TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, spp); - TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bpp); - TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, spp*bpp == 1 ? PHOTOMETRIC_MINISBLACK - : PHOTOMETRIC_RGB); - TIFFSetField(tif, TIFFTAG_COMPRESSION, compression); - - // scanlinesize if determined by spp and bpp - tsize_t linebytes = (tsize_t)image->GetWidth() * spp * bpp / 8; - - if ( (image->GetWidth() % 8 > 0) && (spp * bpp < 8) ) - linebytes+=1; - - unsigned char *buf; - - if (TIFFScanlineSize(tif) > linebytes || (spp * bpp < 24)) - { - buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif)); - if (!buf) - { - if (verbose) - wxLogError( _("TIFF: Couldn't allocate memory.") ); - - TIFFClose( tif ); - - return false; - } - } - else - { - buf = NULL; - } - - TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,TIFFDefaultStripSize(tif, (uint32) -1)); - - unsigned char *ptr = image->GetData(); - for ( int row = 0; row < image->GetHeight(); row++ ) - { - if ( buf ) - { - if ( spp * bpp > 1 ) - { - // color image - memcpy(buf, ptr, image->GetWidth()); - } - else // black and white image - { - for ( int column = 0; column < linebytes; column++ ) - { - uint8 reverse = 0; - for ( int bp = 0; bp < 8; bp++ ) - { - if ( ptr[column*24 + bp*3] > 0 ) - { - // check only red as this is sufficient - reverse = (uint8)(reverse | 128 >> bp); - } - } - - buf[column] = reverse; - } - } - } - - if ( TIFFWriteScanline(tif, buf ? buf : ptr, (uint32)row, 0) < 0 ) - { - if (verbose) - wxLogError( _("TIFF: Error writing image.") ); - - TIFFClose( tif ); - if (buf) - _TIFFfree(buf); - - return false; - } - - ptr += image->GetWidth()*3; - } - - (void) TIFFClose(tif); - - if (buf) - _TIFFfree(buf); - - return true; -} - -bool wxTIFFHandler::DoCanRead( wxInputStream& stream ) -{ - unsigned char hdr[2]; - - if ( !stream.Read(&hdr[0], WXSIZEOF(hdr)) ) - return false; - - return (hdr[0] == 'I' && hdr[1] == 'I') || - (hdr[0] == 'M' && hdr[1] == 'M'); -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_LIBTIFF +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagtiff.cpp +// Purpose: wxImage TIFF handler +// Author: Robert Roebling +// RCS-ID: $Id: imagtiff.cpp 60897 2009-06-04 22:28:48Z VZ $ +// Copyright: (c) Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_LIBTIFF + +#include "wx/imagtiff.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/bitmap.h" + #include "wx/module.h" +#endif + +extern "C" +{ + #include "tiff.h" + #include "tiffio.h" +} +#include "wx/filefn.h" +#include "wx/wfstream.h" + +#ifndef TIFFLINKAGEMODE + #if defined(__WATCOMC__) && defined(__WXMGL__) + #define TIFFLINKAGEMODE cdecl + #else + #define TIFFLINKAGEMODE LINKAGEMODE + #endif +#endif + +//----------------------------------------------------------------------------- +// wxTIFFHandler +//----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxTIFFHandler,wxImageHandler) + +#if wxUSE_STREAMS + +// helper to translate our, possibly 64 bit, wxFileOffset to TIFF, always 32 +// bit, toff_t +static toff_t wxFileOffsetToTIFF(wxFileOffset ofs) +{ + if ( ofs == wxInvalidOffset ) + return (toff_t)-1; + + toff_t tofs = wx_truncate_cast(toff_t, ofs); + wxCHECK_MSG( (wxFileOffset)tofs == ofs, (toff_t)-1, + _T("TIFF library doesn't support large files") ); + + return tofs; +} + +// another helper to convert standard seek mode to our +static wxSeekMode wxSeekModeFromTIFF(int whence) +{ + switch ( whence ) + { + case SEEK_SET: + return wxFromStart; + + case SEEK_CUR: + return wxFromCurrent; + + case SEEK_END: + return wxFromEnd; + + default: + return wxFromCurrent; + } +} + +extern "C" +{ + +tsize_t TIFFLINKAGEMODE +wxTIFFNullProc(thandle_t WXUNUSED(handle), + tdata_t WXUNUSED(buf), + tsize_t WXUNUSED(size)) +{ + return (tsize_t) -1; +} + +tsize_t TIFFLINKAGEMODE +wxTIFFReadProc(thandle_t handle, tdata_t buf, tsize_t size) +{ + wxInputStream *stream = (wxInputStream*) handle; + stream->Read( (void*) buf, (size_t) size ); + return wx_truncate_cast(tsize_t, stream->LastRead()); +} + +tsize_t TIFFLINKAGEMODE +wxTIFFWriteProc(thandle_t handle, tdata_t buf, tsize_t size) +{ + wxOutputStream *stream = (wxOutputStream*) handle; + stream->Write( (void*) buf, (size_t) size ); + return wx_truncate_cast(tsize_t, stream->LastWrite()); +} + +toff_t TIFFLINKAGEMODE +wxTIFFSeekIProc(thandle_t handle, toff_t off, int whence) +{ + wxInputStream *stream = (wxInputStream*) handle; + + return wxFileOffsetToTIFF(stream->SeekI((wxFileOffset)off, + wxSeekModeFromTIFF(whence))); +} + +toff_t TIFFLINKAGEMODE +wxTIFFSeekOProc(thandle_t handle, toff_t off, int whence) +{ + wxOutputStream *stream = (wxOutputStream*) handle; + + return wxFileOffsetToTIFF(stream->SeekO((wxFileOffset)off, + wxSeekModeFromTIFF(whence))); +} + +int TIFFLINKAGEMODE +wxTIFFCloseIProc(thandle_t WXUNUSED(handle)) +{ + // there is no need to close the input stream + return 0; +} + +int TIFFLINKAGEMODE +wxTIFFCloseOProc(thandle_t handle) +{ + wxOutputStream *stream = (wxOutputStream*) handle; + + return stream->Close() ? 0 : -1; +} + +toff_t TIFFLINKAGEMODE +wxTIFFSizeProc(thandle_t handle) +{ + wxStreamBase *stream = (wxStreamBase*) handle; + return (toff_t) stream->GetSize(); +} + +int TIFFLINKAGEMODE +wxTIFFMapProc(thandle_t WXUNUSED(handle), + tdata_t* WXUNUSED(pbase), + toff_t* WXUNUSED(psize)) +{ + return 0; +} + +void TIFFLINKAGEMODE +wxTIFFUnmapProc(thandle_t WXUNUSED(handle), + tdata_t WXUNUSED(base), + toff_t WXUNUSED(size)) +{ +} + +static void +TIFFwxWarningHandler(const char* module, + const char* WXUNUSED_IN_UNICODE(fmt), + va_list WXUNUSED_IN_UNICODE(ap)) +{ + if (module != NULL) + wxLogWarning(_("tiff module: %s"), wxString::FromAscii(module).c_str()); + + // FIXME: this is not terrible informative but better than crashing! +#if wxUSE_UNICODE + wxLogWarning(_("TIFF library warning.")); +#else + wxVLogWarning(fmt, ap); +#endif +} + +static void +TIFFwxErrorHandler(const char* module, + const char* WXUNUSED_IN_UNICODE(fmt), + va_list WXUNUSED_IN_UNICODE(ap)) +{ + if (module != NULL) + wxLogError(_("tiff module: %s"), wxString::FromAscii(module).c_str()); + + // FIXME: as above +#if wxUSE_UNICODE + wxLogError(_("TIFF library error.")); +#else + wxVLogError(fmt, ap); +#endif +} + +} // extern "C" + +TIFF* +TIFFwxOpen(wxInputStream &stream, const char* name, const char* mode) +{ + TIFF* tif = TIFFClientOpen(name, mode, + (thandle_t) &stream, + wxTIFFReadProc, wxTIFFNullProc, + wxTIFFSeekIProc, wxTIFFCloseIProc, wxTIFFSizeProc, + wxTIFFMapProc, wxTIFFUnmapProc); + + return tif; +} + +TIFF* +TIFFwxOpen(wxOutputStream &stream, const char* name, const char* mode) +{ + TIFF* tif = TIFFClientOpen(name, mode, + (thandle_t) &stream, + wxTIFFNullProc, wxTIFFWriteProc, + wxTIFFSeekOProc, wxTIFFCloseOProc, wxTIFFSizeProc, + wxTIFFMapProc, wxTIFFUnmapProc); + + return tif; +} + +wxTIFFHandler::wxTIFFHandler() +{ + m_name = wxT("TIFF file"); + m_extension = wxT("tif"); + m_type = wxBITMAP_TYPE_TIF; + m_mime = wxT("image/tiff"); + TIFFSetWarningHandler((TIFFErrorHandler) TIFFwxWarningHandler); + TIFFSetErrorHandler((TIFFErrorHandler) TIFFwxErrorHandler); +} + +bool wxTIFFHandler::LoadFile( wxImage *image, wxInputStream& stream, bool verbose, int index ) +{ + if (index == -1) + index = 0; + + image->Destroy(); + + TIFF *tif = TIFFwxOpen( stream, "image", "r" ); + + if (!tif) + { + if (verbose) + wxLogError( _("TIFF: Error loading image.") ); + + return false; + } + + if (!TIFFSetDirectory( tif, (tdir_t)index )) + { + if (verbose) + wxLogError( _("Invalid TIFF image index.") ); + + TIFFClose( tif ); + + return false; + } + + uint32 w, h; + uint32 *raster; + + TIFFGetField( tif, TIFFTAG_IMAGEWIDTH, &w ); + TIFFGetField( tif, TIFFTAG_IMAGELENGTH, &h ); + + uint16 extraSamples; + uint16* samplesInfo; + TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, + &extraSamples, &samplesInfo); + const bool hasAlpha = (extraSamples == 1 && + (samplesInfo[0] == EXTRASAMPLE_ASSOCALPHA || + samplesInfo[0] == EXTRASAMPLE_UNASSALPHA)); + + // guard against integer overflow during multiplication which could result + // in allocating a too small buffer and then overflowing it + const double bytesNeeded = (double)w * (double)h * sizeof(uint32); + if ( bytesNeeded >= 4294967295U /* UINT32_MAX */ ) + { + if ( verbose ) + wxLogError( _("TIFF: Image size is abnormally big.") ); + + TIFFClose(tif); + + return false; + } + + raster = (uint32*) _TIFFmalloc( bytesNeeded ); + + if (!raster) + { + if (verbose) + wxLogError( _("TIFF: Couldn't allocate memory.") ); + + TIFFClose( tif ); + + return false; + } + + image->Create( (int)w, (int)h ); + if (!image->Ok()) + { + if (verbose) + wxLogError( _("TIFF: Couldn't allocate memory.") ); + + _TIFFfree( raster ); + TIFFClose( tif ); + + return false; + } + + if ( hasAlpha ) + image->SetAlpha(); + + if (!TIFFReadRGBAImage( tif, w, h, raster, 0 )) + { + if (verbose) + wxLogError( _("TIFF: Error reading image.") ); + + _TIFFfree( raster ); + image->Destroy(); + TIFFClose( tif ); + + return false; + } + + unsigned char *ptr = image->GetData(); + ptr += w*3*(h-1); + + unsigned char *alpha = hasAlpha ? image->GetAlpha() : NULL; + if ( hasAlpha ) + alpha += w*(h-1); + + uint32 pos = 0; + + for (uint32 i = 0; i < h; i++) + { + for (uint32 j = 0; j < w; j++) + { + *(ptr++) = (unsigned char)TIFFGetR(raster[pos]); + *(ptr++) = (unsigned char)TIFFGetG(raster[pos]); + *(ptr++) = (unsigned char)TIFFGetB(raster[pos]); + if ( hasAlpha ) + *(alpha++) = (unsigned char)TIFFGetA(raster[pos]); + + pos++; + } + + // subtract line we just added plus one line: + ptr -= 2*w*3; + if ( hasAlpha ) + alpha -= 2*w; + } + + _TIFFfree( raster ); + + TIFFClose( tif ); + + return true; +} + +int wxTIFFHandler::GetImageCount( wxInputStream& stream ) +{ + TIFF *tif = TIFFwxOpen( stream, "image", "r" ); + + if (!tif) + return 0; + + int dircount = 0; // according to the libtiff docs, dircount should be set to 1 here??? + do { + dircount++; + } while (TIFFReadDirectory(tif)); + + TIFFClose( tif ); + + return dircount; +} + +bool wxTIFFHandler::SaveFile( wxImage *image, wxOutputStream& stream, bool verbose ) +{ + TIFF *tif = TIFFwxOpen( stream, "image", "w" ); + + if (!tif) + { + if (verbose) + wxLogError( _("TIFF: Error saving image.") ); + + return false; + } + + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, (uint32)image->GetWidth()); + TIFFSetField(tif, TIFFTAG_IMAGELENGTH, (uint32)image->GetHeight()); + TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); + TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); + + if ( image->HasOption(wxIMAGE_OPTION_RESOLUTIONX) && + image->HasOption(wxIMAGE_OPTION_RESOLUTIONY) ) + { + TIFFSetField(tif, TIFFTAG_XRESOLUTION, + (float)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONX)); + TIFFSetField(tif, TIFFTAG_YRESOLUTION, + (float)image->GetOptionInt(wxIMAGE_OPTION_RESOLUTIONY)); + } + + int spp = image->GetOptionInt(wxIMAGE_OPTION_SAMPLESPERPIXEL); + if ( !spp ) + spp = 3; + + int bpp = image->GetOptionInt(wxIMAGE_OPTION_BITSPERSAMPLE); + if ( !bpp ) + bpp=8; + + int compression = image->GetOptionInt(wxIMAGE_OPTION_COMPRESSION); + if ( !compression ) + { + // we can't use COMPRESSION_LZW because current version of libtiff + // doesn't implement it ("no longer implemented due to Unisys patent + // enforcement") and other compression methods are lossy so we + // shouldn't use them by default -- and the only remaining one is none + compression = COMPRESSION_NONE; + } + + TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, spp); + TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, bpp); + TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, spp*bpp == 1 ? PHOTOMETRIC_MINISBLACK + : PHOTOMETRIC_RGB); + TIFFSetField(tif, TIFFTAG_COMPRESSION, compression); + + // scanlinesize if determined by spp and bpp + tsize_t linebytes = (tsize_t)image->GetWidth() * spp * bpp / 8; + + if ( (image->GetWidth() % 8 > 0) && (spp * bpp < 8) ) + linebytes+=1; + + unsigned char *buf; + + if (TIFFScanlineSize(tif) > linebytes || (spp * bpp < 24)) + { + buf = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(tif)); + if (!buf) + { + if (verbose) + wxLogError( _("TIFF: Couldn't allocate memory.") ); + + TIFFClose( tif ); + + return false; + } + } + else + { + buf = NULL; + } + + TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP,TIFFDefaultStripSize(tif, (uint32) -1)); + + unsigned char *ptr = image->GetData(); + for ( int row = 0; row < image->GetHeight(); row++ ) + { + if ( buf ) + { + if ( spp * bpp > 1 ) + { + // color image + memcpy(buf, ptr, image->GetWidth()); + } + else // black and white image + { + for ( int column = 0; column < linebytes; column++ ) + { + uint8 reverse = 0; + for ( int bp = 0; bp < 8; bp++ ) + { + if ( ptr[column*24 + bp*3] > 0 ) + { + // check only red as this is sufficient + reverse = (uint8)(reverse | 128 >> bp); + } + } + + buf[column] = reverse; + } + } + } + + if ( TIFFWriteScanline(tif, buf ? buf : ptr, (uint32)row, 0) < 0 ) + { + if (verbose) + wxLogError( _("TIFF: Error writing image.") ); + + TIFFClose( tif ); + if (buf) + _TIFFfree(buf); + + return false; + } + + ptr += image->GetWidth()*3; + } + + (void) TIFFClose(tif); + + if (buf) + _TIFFfree(buf); + + return true; +} + +bool wxTIFFHandler::DoCanRead( wxInputStream& stream ) +{ + unsigned char hdr[2]; + + if ( !stream.Read(&hdr[0], WXSIZEOF(hdr)) ) + return false; + + return (hdr[0] == 'I' && hdr[1] == 'I') || + (hdr[0] == 'M' && hdr[1] == 'M'); +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_LIBTIFF diff --git a/Source/3rd Party/wx/src/common/imagxpm.cpp b/Source/3rd Party/wx/src/common/imagxpm.cpp index cca244c1a..8ef328cf2 100644 --- a/Source/3rd Party/wx/src/common/imagxpm.cpp +++ b/Source/3rd Party/wx/src/common/imagxpm.cpp @@ -1,224 +1,224 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/imagxpm.cpp -// Purpose: wxXPMHandler -// Author: Vaclav Slavik, Robert Roebling -// RCS-ID: $Id: imagxpm.cpp 53477 2008-05-07 07:28:57Z JS $ -// Copyright: (c) 2001 Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -/* - -This file is partially based on source code of ImageMagick by John Cristy. Its -license is as follows: - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % -% X X PPPP M M % -% X X P P MM MM % -% X PPPP M M M % -% X X P M M % -% X X P M M % -% % -% % -% Read/Write ImageMagick Image Format. % -% % -% % -% Software Design % -% John Cristy % -% July 1992 % -% % -% % -% Copyright (C) 2001 ImageMagick Studio, a non-profit organization dedicated % -% to making software imaging solutions freely available. % -% % -% Permission is hereby granted, free of charge, to any person obtaining a % -% copy of this software and associated documentation files ("ImageMagick"), % -% to deal in ImageMagick without restriction, including without limitation % -% the rights to use, copy, modify, merge, publish, distribute, sublicense, % -% and/or sell copies of ImageMagick, and to permit persons to whom the % -% ImageMagick is furnished to do so, subject to the following conditions: % -% % -% The above copyright notice and this permission notice shall be included in % -% all copies or substantial portions of ImageMagick. % -% % -% The software is provided "as is", without warranty of any kind, express or % -% implied, including but not limited to the warranties of merchantability, % -% fitness for a particular purpose and noninfringement. In no event shall % -% ImageMagick Studio be liable for any claim, damages or other liability, % -% whether in an action of contract, tort or otherwise, arising from, out of % -% or in connection with ImageMagick or the use or other dealings in % -% ImageMagick. % -% % -% Except as contained in this notice, the name of the ImageMagick Studio % -% shall not be used in advertising or otherwise to promote the sale, use or % -% other dealings in ImageMagick without prior written authorization from the % -% ImageMagick Studio. % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% -*/ - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_XPM - -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/utils.h" -#endif - -#include "wx/imagxpm.h" -#include "wx/wfstream.h" -#include "wx/xpmdecod.h" - -IMPLEMENT_DYNAMIC_CLASS(wxXPMHandler,wxImageHandler) - -//----------------------------------------------------------------------------- -// wxXPMHandler -//----------------------------------------------------------------------------- - -#if wxUSE_STREAMS - -bool wxXPMHandler::LoadFile(wxImage *image, - wxInputStream& stream, - bool WXUNUSED(verbose), int WXUNUSED(index)) -{ - wxXPMDecoder decoder; - - wxImage img = decoder.ReadFile(stream); - if ( !img.Ok() ) - return false; - *image = img; - return true; -} - -bool wxXPMHandler::SaveFile(wxImage * image, - wxOutputStream& stream, bool WXUNUSED(verbose)) -{ - // 1. count colours: - #define MaxCixels 92 - static const char Cixel[MaxCixels+1] = - " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk" - "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; - int i, j, k; - - wxImageHistogram histogram; - int cols = int(image->ComputeHistogram(histogram)); - - int chars_per_pixel = 1; - for ( k = MaxCixels; cols > k; k *= MaxCixels) - chars_per_pixel++; - - // 2. write the header: - wxString sName; - if ( image->HasOption(wxIMAGE_OPTION_FILENAME) ) - { - wxSplitPath(image->GetOption(wxIMAGE_OPTION_FILENAME), - NULL, &sName, NULL); - sName << wxT("_xpm"); - } - - if ( !sName.empty() ) - sName = wxString(wxT("/* XPM */\nstatic const char *")) + sName; - else - sName = wxT("/* XPM */\nstatic const char *xpm_data"); - stream.Write( (const char*) sName.ToAscii(), sName.Len() ); - - char tmpbuf[200]; - // VS: 200b is safe upper bound for anything produced by sprintf below - // (<101 bytes the string, neither %i can expand into more than 10 chars) - sprintf(tmpbuf, - "[] = {\n" - "/* columns rows colors chars-per-pixel */\n" - "\"%i %i %i %i\",\n", - image->GetWidth(), image->GetHeight(), cols, chars_per_pixel); - stream.Write(tmpbuf, strlen(tmpbuf)); - - // 3. create color symbols table: - char *symbols_data = new char[cols * (chars_per_pixel+1)]; - char **symbols = new char*[cols]; - - // 2a. find mask colour: - unsigned long mask_key = 0x1000000 /*invalid RGB value*/; - if (image->HasMask()) - mask_key = (image->GetMaskRed() << 16) | - (image->GetMaskGreen() << 8) | image->GetMaskBlue(); - - // 2b. generate colour table: - for (wxImageHistogram::iterator entry = histogram.begin(); - entry != histogram.end(); ++entry ) - { - unsigned long index = entry->second.index; - symbols[index] = symbols_data + index * (chars_per_pixel+1); - char *sym = symbols[index]; - - for (j = 0; j < chars_per_pixel; j++) - { - sym[j] = Cixel[index % MaxCixels]; - index /= MaxCixels; - } - sym[j] = '\0'; - - unsigned long key = entry->first; - - if (key == 0) - sprintf( tmpbuf, "\"%s c Black\",\n", sym); - else if (key == mask_key) - sprintf( tmpbuf, "\"%s c None\",\n", sym); - else - { - wxByte r = wxByte(key >> 16); - wxByte g = wxByte(key >> 8); - wxByte b = wxByte(key); - sprintf(tmpbuf, "\"%s c #%02X%02X%02X\",\n", sym, r, g, b); - } - stream.Write( tmpbuf, strlen(tmpbuf) ); - } - - stream.Write("/* pixels */\n", 13); - - unsigned char *data = image->GetData(); - for (j = 0; j < image->GetHeight(); j++) - { - char tmp_c; - tmp_c = '\"'; stream.Write(&tmp_c, 1); - for (i = 0; i < image->GetWidth(); i++, data += 3) - { - unsigned long key = (data[0] << 16) | (data[1] << 8) | (data[2]); - stream.Write(symbols[histogram[key].index], chars_per_pixel); - } - tmp_c = '\"'; stream.Write(&tmp_c, 1); - if ( j + 1 < image->GetHeight() ) - { - tmp_c = ','; stream.Write(&tmp_c, 1); - } - tmp_c = '\n'; stream.Write(&tmp_c, 1); - } - stream.Write("};\n", 3 ); - - // Clean up: - delete[] symbols; - delete[] symbols_data; - - return true; -} - -bool wxXPMHandler::DoCanRead(wxInputStream& stream) -{ - wxXPMDecoder decoder; - return decoder.CanRead(stream); -} - -#endif // wxUSE_STREAMS - -#endif // wxUSE_XPM +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/imagxpm.cpp +// Purpose: wxXPMHandler +// Author: Vaclav Slavik, Robert Roebling +// RCS-ID: $Id: imagxpm.cpp 53477 2008-05-07 07:28:57Z JS $ +// Copyright: (c) 2001 Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +/* + +This file is partially based on source code of ImageMagick by John Cristy. Its +license is as follows: + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% X X PPPP M M % +% X X P P MM MM % +% X PPPP M M M % +% X X P M M % +% X X P M M % +% % +% % +% Read/Write ImageMagick Image Format. % +% % +% % +% Software Design % +% John Cristy % +% July 1992 % +% % +% % +% Copyright (C) 2001 ImageMagick Studio, a non-profit organization dedicated % +% to making software imaging solutions freely available. % +% % +% Permission is hereby granted, free of charge, to any person obtaining a % +% copy of this software and associated documentation files ("ImageMagick"), % +% to deal in ImageMagick without restriction, including without limitation % +% the rights to use, copy, modify, merge, publish, distribute, sublicense, % +% and/or sell copies of ImageMagick, and to permit persons to whom the % +% ImageMagick is furnished to do so, subject to the following conditions: % +% % +% The above copyright notice and this permission notice shall be included in % +% all copies or substantial portions of ImageMagick. % +% % +% The software is provided "as is", without warranty of any kind, express or % +% implied, including but not limited to the warranties of merchantability, % +% fitness for a particular purpose and noninfringement. In no event shall % +% ImageMagick Studio be liable for any claim, damages or other liability, % +% whether in an action of contract, tort or otherwise, arising from, out of % +% or in connection with ImageMagick or the use or other dealings in % +% ImageMagick. % +% % +% Except as contained in this notice, the name of the ImageMagick Studio % +% shall not be used in advertising or otherwise to promote the sale, use or % +% other dealings in ImageMagick without prior written authorization from the % +% ImageMagick Studio. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% +*/ + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_XPM + +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/utils.h" +#endif + +#include "wx/imagxpm.h" +#include "wx/wfstream.h" +#include "wx/xpmdecod.h" + +IMPLEMENT_DYNAMIC_CLASS(wxXPMHandler,wxImageHandler) + +//----------------------------------------------------------------------------- +// wxXPMHandler +//----------------------------------------------------------------------------- + +#if wxUSE_STREAMS + +bool wxXPMHandler::LoadFile(wxImage *image, + wxInputStream& stream, + bool WXUNUSED(verbose), int WXUNUSED(index)) +{ + wxXPMDecoder decoder; + + wxImage img = decoder.ReadFile(stream); + if ( !img.Ok() ) + return false; + *image = img; + return true; +} + +bool wxXPMHandler::SaveFile(wxImage * image, + wxOutputStream& stream, bool WXUNUSED(verbose)) +{ + // 1. count colours: + #define MaxCixels 92 + static const char Cixel[MaxCixels+1] = + " .XoO+@#$%&*=-;:>,<1234567890qwertyuipasdfghjk" + "lzxcvbnmMNBVCZASDFGHJKLPIUYTREWQ!~^/()_`'][{}|"; + int i, j, k; + + wxImageHistogram histogram; + int cols = int(image->ComputeHistogram(histogram)); + + int chars_per_pixel = 1; + for ( k = MaxCixels; cols > k; k *= MaxCixels) + chars_per_pixel++; + + // 2. write the header: + wxString sName; + if ( image->HasOption(wxIMAGE_OPTION_FILENAME) ) + { + wxSplitPath(image->GetOption(wxIMAGE_OPTION_FILENAME), + NULL, &sName, NULL); + sName << wxT("_xpm"); + } + + if ( !sName.empty() ) + sName = wxString(wxT("/* XPM */\nstatic const char *")) + sName; + else + sName = wxT("/* XPM */\nstatic const char *xpm_data"); + stream.Write( (const char*) sName.ToAscii(), sName.Len() ); + + char tmpbuf[200]; + // VS: 200b is safe upper bound for anything produced by sprintf below + // (<101 bytes the string, neither %i can expand into more than 10 chars) + sprintf(tmpbuf, + "[] = {\n" + "/* columns rows colors chars-per-pixel */\n" + "\"%i %i %i %i\",\n", + image->GetWidth(), image->GetHeight(), cols, chars_per_pixel); + stream.Write(tmpbuf, strlen(tmpbuf)); + + // 3. create color symbols table: + char *symbols_data = new char[cols * (chars_per_pixel+1)]; + char **symbols = new char*[cols]; + + // 2a. find mask colour: + unsigned long mask_key = 0x1000000 /*invalid RGB value*/; + if (image->HasMask()) + mask_key = (image->GetMaskRed() << 16) | + (image->GetMaskGreen() << 8) | image->GetMaskBlue(); + + // 2b. generate colour table: + for (wxImageHistogram::iterator entry = histogram.begin(); + entry != histogram.end(); ++entry ) + { + unsigned long index = entry->second.index; + symbols[index] = symbols_data + index * (chars_per_pixel+1); + char *sym = symbols[index]; + + for (j = 0; j < chars_per_pixel; j++) + { + sym[j] = Cixel[index % MaxCixels]; + index /= MaxCixels; + } + sym[j] = '\0'; + + unsigned long key = entry->first; + + if (key == 0) + sprintf( tmpbuf, "\"%s c Black\",\n", sym); + else if (key == mask_key) + sprintf( tmpbuf, "\"%s c None\",\n", sym); + else + { + wxByte r = wxByte(key >> 16); + wxByte g = wxByte(key >> 8); + wxByte b = wxByte(key); + sprintf(tmpbuf, "\"%s c #%02X%02X%02X\",\n", sym, r, g, b); + } + stream.Write( tmpbuf, strlen(tmpbuf) ); + } + + stream.Write("/* pixels */\n", 13); + + unsigned char *data = image->GetData(); + for (j = 0; j < image->GetHeight(); j++) + { + char tmp_c; + tmp_c = '\"'; stream.Write(&tmp_c, 1); + for (i = 0; i < image->GetWidth(); i++, data += 3) + { + unsigned long key = (data[0] << 16) | (data[1] << 8) | (data[2]); + stream.Write(symbols[histogram[key].index], chars_per_pixel); + } + tmp_c = '\"'; stream.Write(&tmp_c, 1); + if ( j + 1 < image->GetHeight() ) + { + tmp_c = ','; stream.Write(&tmp_c, 1); + } + tmp_c = '\n'; stream.Write(&tmp_c, 1); + } + stream.Write("};\n", 3 ); + + // Clean up: + delete[] symbols; + delete[] symbols_data; + + return true; +} + +bool wxXPMHandler::DoCanRead(wxInputStream& stream) +{ + wxXPMDecoder decoder; + return decoder.CanRead(stream); +} + +#endif // wxUSE_STREAMS + +#endif // wxUSE_XPM diff --git a/Source/3rd Party/wx/src/common/init.cpp b/Source/3rd Party/wx/src/common/init.cpp index f05f0badf..9d68e6abb 100644 --- a/Source/3rd Party/wx/src/common/init.cpp +++ b/Source/3rd Party/wx/src/common/init.cpp @@ -1,505 +1,505 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/init.cpp -// Purpose: initialisation for the library -// Author: Vadim Zeitlin -// Modified by: -// Created: 04.10.99 -// RCS-ID: $Id: init.cpp 61555 2009-07-30 07:42:54Z VS $ -// Copyright: (c) Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif //__BORLANDC__ - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/filefn.h" - #include "wx/log.h" - #include "wx/thread.h" - #include "wx/intl.h" - #include "wx/module.h" -#endif - -#include "wx/init.h" - -#include "wx/ptr_scpd.h" -#include "wx/except.h" - -#if defined(__WXMSW__) && defined(__WXDEBUG__) - #include "wx/msw/msvcrt.h" - - static struct EnableMemLeakChecking - { - EnableMemLeakChecking() - { - // do check for memory leaks on program exit (another useful flag - // is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free deallocated - // memory which may be used to simulate low-memory condition) - wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF); - } - } gs_enableLeakChecks; -#endif // __WXMSW__ && __WXDEBUG__ - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -// we need a dummy app object if the user doesn't want to create a real one -class wxDummyConsoleApp : public wxAppConsole -{ -public: - wxDummyConsoleApp() { } - - virtual int OnRun() { wxFAIL_MSG( _T("unreachable code") ); return 0; } - - DECLARE_NO_COPY_CLASS(wxDummyConsoleApp) -}; - -// we need a special kind of auto pointer to wxApp which not only deletes the -// pointer it holds in its dtor but also resets the global application pointer -wxDECLARE_SCOPED_PTR(wxAppConsole, wxAppPtrBase) -wxDEFINE_SCOPED_PTR(wxAppConsole, wxAppPtrBase) - -class wxAppPtr : public wxAppPtrBase -{ -public: - wxEXPLICIT wxAppPtr(wxAppConsole *ptr = NULL) : wxAppPtrBase(ptr) { } - ~wxAppPtr() - { - if ( get() ) - { - // the pointer is going to be deleted in the base class dtor, don't - // leave the dangling pointer! - wxApp::SetInstance(NULL); - } - } - - void Set(wxAppConsole *ptr) - { - reset(ptr); - - wxApp::SetInstance(ptr); - } - - DECLARE_NO_COPY_CLASS(wxAppPtr) -}; - -// class to ensure that wxAppBase::CleanUp() is called if our Initialize() -// fails -class wxCallAppCleanup -{ -public: - wxCallAppCleanup(wxAppConsole *app) : m_app(app) { } - ~wxCallAppCleanup() { if ( m_app ) m_app->CleanUp(); } - - void Dismiss() { m_app = NULL; } - -private: - wxAppConsole *m_app; -}; - -// ---------------------------------------------------------------------------- -// private functions -// ---------------------------------------------------------------------------- - -// suppress warnings about unused variables -static inline void Use(void *) { } - -#define WX_SUPPRESS_UNUSED_WARN(x) Use(&x) - -// ---------------------------------------------------------------------------- -// initialization data -// ---------------------------------------------------------------------------- - -static struct InitData -{ - InitData() - { - nInitCount = 0; - -#if wxUSE_UNICODE - argc = 0; - // argv = NULL; -- not even really needed -#endif // wxUSE_UNICODE - } - - // critical section protecting this struct - wxCRIT_SECT_DECLARE_MEMBER(csInit); - - // number of times wxInitialize() was called minus the number of times - // wxUninitialize() was - size_t nInitCount; - -#if wxUSE_UNICODE - int argc; - - // if we receive the command line arguments as ASCII and have to convert - // them to Unicode ourselves (this is the case under Unix but not Windows, - // for example), we remember the converted argv here because we'll have to - // free it when doing cleanup to avoid memory leaks - wchar_t **argv; -#endif // wxUSE_UNICODE - - DECLARE_NO_COPY_CLASS(InitData) -} gs_initData; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// command line arguments ANSI -> Unicode conversion -// ---------------------------------------------------------------------------- - -#if wxUSE_UNICODE - -static void ConvertArgsToUnicode(int argc, char **argv) -{ - gs_initData.argv = new wchar_t *[argc + 1]; - int wargc = 0; - for ( int i = 0; i < argc; i++ ) - { -#ifdef __DARWIN__ - wxWCharBuffer buf(wxConvFileName->cMB2WX(argv[i])); -#else - wxWCharBuffer buf(wxConvLocal.cMB2WX(argv[i])); -#endif - if ( !buf ) - { - wxLogWarning(_("Command line argument %d couldn't be converted to Unicode and will be ignored."), - i); - } - else // converted ok - { - gs_initData.argv[wargc++] = wxStrdup(buf); - } - } - - gs_initData.argc = wargc; - gs_initData.argv[wargc] = NULL; -} - -static void FreeConvertedArgs() -{ - if ( gs_initData.argv ) - { - for ( int i = 0; i < gs_initData.argc; i++ ) - { - free(gs_initData.argv[i]); - } - - delete [] gs_initData.argv; - gs_initData.argv = NULL; - gs_initData.argc = 0; - } -} - -#endif // wxUSE_UNICODE - -// ---------------------------------------------------------------------------- -// start up -// ---------------------------------------------------------------------------- - -// initialization which is always done (not customizable) before wxApp creation -static bool DoCommonPreInit() -{ -#if wxUSE_LOG - // Reset logging in case we were cleaned up and are being reinitialized. - wxLog::DoCreateOnDemand(); - - // install temporary log sink: we can't use wxLogGui before wxApp is - // constructed and if we use wxLogStderr, all messages during - // initialization simply disappear under Windows - // - // note that we will delete this log target below - delete wxLog::SetActiveTarget(new wxLogBuffer); -#endif // wxUSE_LOG - - return true; -} - -// non customizable initialization done after wxApp creation and initialization -static bool DoCommonPostInit() -{ - wxModule::RegisterModules(); - - if ( !wxModule::InitializeModules() ) - { - wxLogError(_("Initialization failed in post init, aborting.")); - return false; - } - - return true; -} - -bool wxEntryStart(int& argc, wxChar **argv) -{ - // do minimal, always necessary, initialization - // -------------------------------------------- - - // initialize wxRTTI - if ( !DoCommonPreInit() ) - { - return false; - } - - - // first of all, we need an application object - // ------------------------------------------- - - // the user might have already created it himself somehow - wxAppPtr app(wxTheApp); - if ( !app.get() ) - { - // if not, he might have used IMPLEMENT_APP() to give us a function to - // create it - wxAppInitializerFunction fnCreate = wxApp::GetInitializerFunction(); - - if ( fnCreate ) - { - // he did, try to create the custom wxApp object - app.Set((*fnCreate)()); - } - } - - if ( !app.get() ) - { - // either IMPLEMENT_APP() was not used at all or it failed -- in any - // case we still need something - app.Set(new wxDummyConsoleApp); - } - - - // wxApp initialization: this can be customized - // -------------------------------------------- - - if ( !app->Initialize(argc, argv) ) - { - return false; - } - - wxCallAppCleanup callAppCleanup(app.get()); - - // for compatibility call the old initialization function too - if ( !app->OnInitGui() ) - return false; - - - // common initialization after wxTheApp creation - // --------------------------------------------- - - if ( !DoCommonPostInit() ) - return false; - - - // prevent the smart pointer from destroying its contents - app.release(); - - // and the cleanup object from doing cleanup - callAppCleanup.Dismiss(); - -#if wxUSE_LOG - // now that we have a valid wxApp (wxLogGui would have crashed if we used - // it before now), we can delete the temporary sink we had created for the - // initialization messages -- the next time logging function is called, the - // sink will be recreated but this time wxAppTraits will be used - delete wxLog::SetActiveTarget(NULL); -#endif // wxUSE_LOG - - return true; -} - -#if wxUSE_UNICODE - -// we provide a wxEntryStart() wrapper taking "char *" pointer too -bool wxEntryStart(int& argc, char **argv) -{ - ConvertArgsToUnicode(argc, argv); - - if ( !wxEntryStart(gs_initData.argc, gs_initData.argv) ) - { - FreeConvertedArgs(); - - return false; - } - - return true; -} - -#endif // wxUSE_UNICODE - -// ---------------------------------------------------------------------------- -// clean up -// ---------------------------------------------------------------------------- - -// cleanup done before destroying wxTheApp -static void DoCommonPreCleanup() -{ -#if wxUSE_LOG - // flush the logged messages if any and install a 'safer' log target: the - // default one (wxLogGui) can't be used after the resources are freed just - // below and the user supplied one might be even more unsafe (using any - // wxWidgets GUI function is unsafe starting from now) - wxLog::DontCreateOnDemand(); - - // this will flush the old messages if any - delete wxLog::SetActiveTarget(new wxLogStderr); -#endif // wxUSE_LOG -} - -// cleanup done after destroying wxTheApp -static void DoCommonPostCleanup() -{ - wxModule::CleanUpModules(); - - // we can't do this in wxApp itself because it doesn't know if argv had - // been allocated -#if wxUSE_UNICODE - FreeConvertedArgs(); -#endif // wxUSE_UNICODE - - // use Set(NULL) and not Get() to avoid creating a message output object on - // demand when we just want to delete it - delete wxMessageOutput::Set(NULL); - -#if wxUSE_LOG - // and now delete the last logger as well - delete wxLog::SetActiveTarget(NULL); -#endif // wxUSE_LOG -} - -void wxEntryCleanup() -{ - DoCommonPreCleanup(); - - - // delete the application object - if ( wxTheApp ) - { - wxTheApp->CleanUp(); - - // reset the global pointer to it to NULL before destroying it as in - // some circumstances this can result in executing the code using - // wxTheApp and using half-destroyed object is no good - wxAppConsole * const app = wxApp::GetInstance(); - wxApp::SetInstance(NULL); - delete app; - } - - - DoCommonPostCleanup(); -} - -// ---------------------------------------------------------------------------- -// wxEntry -// ---------------------------------------------------------------------------- - -// for MSW the real wxEntry is defined in msw/main.cpp -#ifndef __WXMSW__ - #define wxEntryReal wxEntry -#endif // !__WXMSW__ - -int wxEntryReal(int& argc, wxChar **argv) -{ - // library initialization - wxInitializer initializer(argc, argv); - - if ( !initializer.IsOk() ) - { -#if wxUSE_LOG - // flush any log messages explaining why we failed - delete wxLog::SetActiveTarget(NULL); -#endif - return -1; - } - - wxTRY - { - - // app initialization - if ( !wxTheApp->CallOnInit() ) - { - // don't call OnExit() if OnInit() failed - return -1; - } - - // ensure that OnExit() is called if OnInit() had succeeded - class CallOnExit - { - public: - ~CallOnExit() { wxTheApp->OnExit(); } - } callOnExit; - - WX_SUPPRESS_UNUSED_WARN(callOnExit); - - // app execution - return wxTheApp->OnRun(); - } - wxCATCH_ALL( wxTheApp->OnUnhandledException(); return -1; ) -} - -#if wxUSE_UNICODE - -// as with wxEntryStart, we provide an ANSI wrapper -int wxEntry(int& argc, char **argv) -{ - ConvertArgsToUnicode(argc, argv); - - return wxEntry(gs_initData.argc, gs_initData.argv); -} - -#endif // wxUSE_UNICODE - -// ---------------------------------------------------------------------------- -// wxInitialize/wxUninitialize -// ---------------------------------------------------------------------------- - -bool wxInitialize(int argc, wxChar **argv) -{ - wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit); - - if ( gs_initData.nInitCount++ ) - { - // already initialized - return true; - } - - return wxEntryStart(argc, argv); -} - -#if wxUSE_UNICODE -bool wxInitialize(int argc, char **argv) -{ - wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit); - - if ( gs_initData.nInitCount++ ) - { - // already initialized - return true; - } - - return wxEntryStart(argc, argv); -} -#endif // wxUSE_UNICODE - -void wxUninitialize() -{ - wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit); - - if ( --gs_initData.nInitCount == 0 ) - { - wxEntryCleanup(); - } -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/init.cpp +// Purpose: initialisation for the library +// Author: Vadim Zeitlin +// Modified by: +// Created: 04.10.99 +// RCS-ID: $Id: init.cpp 61555 2009-07-30 07:42:54Z VS $ +// Copyright: (c) Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif //__BORLANDC__ + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/filefn.h" + #include "wx/log.h" + #include "wx/thread.h" + #include "wx/intl.h" + #include "wx/module.h" +#endif + +#include "wx/init.h" + +#include "wx/ptr_scpd.h" +#include "wx/except.h" + +#if defined(__WXMSW__) && defined(__WXDEBUG__) + #include "wx/msw/msvcrt.h" + + static struct EnableMemLeakChecking + { + EnableMemLeakChecking() + { + // do check for memory leaks on program exit (another useful flag + // is _CRTDBG_DELAY_FREE_MEM_DF which doesn't free deallocated + // memory which may be used to simulate low-memory condition) + wxCrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF); + } + } gs_enableLeakChecks; +#endif // __WXMSW__ && __WXDEBUG__ + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// we need a dummy app object if the user doesn't want to create a real one +class wxDummyConsoleApp : public wxAppConsole +{ +public: + wxDummyConsoleApp() { } + + virtual int OnRun() { wxFAIL_MSG( _T("unreachable code") ); return 0; } + + DECLARE_NO_COPY_CLASS(wxDummyConsoleApp) +}; + +// we need a special kind of auto pointer to wxApp which not only deletes the +// pointer it holds in its dtor but also resets the global application pointer +wxDECLARE_SCOPED_PTR(wxAppConsole, wxAppPtrBase) +wxDEFINE_SCOPED_PTR(wxAppConsole, wxAppPtrBase) + +class wxAppPtr : public wxAppPtrBase +{ +public: + wxEXPLICIT wxAppPtr(wxAppConsole *ptr = NULL) : wxAppPtrBase(ptr) { } + ~wxAppPtr() + { + if ( get() ) + { + // the pointer is going to be deleted in the base class dtor, don't + // leave the dangling pointer! + wxApp::SetInstance(NULL); + } + } + + void Set(wxAppConsole *ptr) + { + reset(ptr); + + wxApp::SetInstance(ptr); + } + + DECLARE_NO_COPY_CLASS(wxAppPtr) +}; + +// class to ensure that wxAppBase::CleanUp() is called if our Initialize() +// fails +class wxCallAppCleanup +{ +public: + wxCallAppCleanup(wxAppConsole *app) : m_app(app) { } + ~wxCallAppCleanup() { if ( m_app ) m_app->CleanUp(); } + + void Dismiss() { m_app = NULL; } + +private: + wxAppConsole *m_app; +}; + +// ---------------------------------------------------------------------------- +// private functions +// ---------------------------------------------------------------------------- + +// suppress warnings about unused variables +static inline void Use(void *) { } + +#define WX_SUPPRESS_UNUSED_WARN(x) Use(&x) + +// ---------------------------------------------------------------------------- +// initialization data +// ---------------------------------------------------------------------------- + +static struct InitData +{ + InitData() + { + nInitCount = 0; + +#if wxUSE_UNICODE + argc = 0; + // argv = NULL; -- not even really needed +#endif // wxUSE_UNICODE + } + + // critical section protecting this struct + wxCRIT_SECT_DECLARE_MEMBER(csInit); + + // number of times wxInitialize() was called minus the number of times + // wxUninitialize() was + size_t nInitCount; + +#if wxUSE_UNICODE + int argc; + + // if we receive the command line arguments as ASCII and have to convert + // them to Unicode ourselves (this is the case under Unix but not Windows, + // for example), we remember the converted argv here because we'll have to + // free it when doing cleanup to avoid memory leaks + wchar_t **argv; +#endif // wxUSE_UNICODE + + DECLARE_NO_COPY_CLASS(InitData) +} gs_initData; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// command line arguments ANSI -> Unicode conversion +// ---------------------------------------------------------------------------- + +#if wxUSE_UNICODE + +static void ConvertArgsToUnicode(int argc, char **argv) +{ + gs_initData.argv = new wchar_t *[argc + 1]; + int wargc = 0; + for ( int i = 0; i < argc; i++ ) + { +#ifdef __DARWIN__ + wxWCharBuffer buf(wxConvFileName->cMB2WX(argv[i])); +#else + wxWCharBuffer buf(wxConvLocal.cMB2WX(argv[i])); +#endif + if ( !buf ) + { + wxLogWarning(_("Command line argument %d couldn't be converted to Unicode and will be ignored."), + i); + } + else // converted ok + { + gs_initData.argv[wargc++] = wxStrdup(buf); + } + } + + gs_initData.argc = wargc; + gs_initData.argv[wargc] = NULL; +} + +static void FreeConvertedArgs() +{ + if ( gs_initData.argv ) + { + for ( int i = 0; i < gs_initData.argc; i++ ) + { + free(gs_initData.argv[i]); + } + + delete [] gs_initData.argv; + gs_initData.argv = NULL; + gs_initData.argc = 0; + } +} + +#endif // wxUSE_UNICODE + +// ---------------------------------------------------------------------------- +// start up +// ---------------------------------------------------------------------------- + +// initialization which is always done (not customizable) before wxApp creation +static bool DoCommonPreInit() +{ +#if wxUSE_LOG + // Reset logging in case we were cleaned up and are being reinitialized. + wxLog::DoCreateOnDemand(); + + // install temporary log sink: we can't use wxLogGui before wxApp is + // constructed and if we use wxLogStderr, all messages during + // initialization simply disappear under Windows + // + // note that we will delete this log target below + delete wxLog::SetActiveTarget(new wxLogBuffer); +#endif // wxUSE_LOG + + return true; +} + +// non customizable initialization done after wxApp creation and initialization +static bool DoCommonPostInit() +{ + wxModule::RegisterModules(); + + if ( !wxModule::InitializeModules() ) + { + wxLogError(_("Initialization failed in post init, aborting.")); + return false; + } + + return true; +} + +bool wxEntryStart(int& argc, wxChar **argv) +{ + // do minimal, always necessary, initialization + // -------------------------------------------- + + // initialize wxRTTI + if ( !DoCommonPreInit() ) + { + return false; + } + + + // first of all, we need an application object + // ------------------------------------------- + + // the user might have already created it himself somehow + wxAppPtr app(wxTheApp); + if ( !app.get() ) + { + // if not, he might have used IMPLEMENT_APP() to give us a function to + // create it + wxAppInitializerFunction fnCreate = wxApp::GetInitializerFunction(); + + if ( fnCreate ) + { + // he did, try to create the custom wxApp object + app.Set((*fnCreate)()); + } + } + + if ( !app.get() ) + { + // either IMPLEMENT_APP() was not used at all or it failed -- in any + // case we still need something + app.Set(new wxDummyConsoleApp); + } + + + // wxApp initialization: this can be customized + // -------------------------------------------- + + if ( !app->Initialize(argc, argv) ) + { + return false; + } + + wxCallAppCleanup callAppCleanup(app.get()); + + // for compatibility call the old initialization function too + if ( !app->OnInitGui() ) + return false; + + + // common initialization after wxTheApp creation + // --------------------------------------------- + + if ( !DoCommonPostInit() ) + return false; + + + // prevent the smart pointer from destroying its contents + app.release(); + + // and the cleanup object from doing cleanup + callAppCleanup.Dismiss(); + +#if wxUSE_LOG + // now that we have a valid wxApp (wxLogGui would have crashed if we used + // it before now), we can delete the temporary sink we had created for the + // initialization messages -- the next time logging function is called, the + // sink will be recreated but this time wxAppTraits will be used + delete wxLog::SetActiveTarget(NULL); +#endif // wxUSE_LOG + + return true; +} + +#if wxUSE_UNICODE + +// we provide a wxEntryStart() wrapper taking "char *" pointer too +bool wxEntryStart(int& argc, char **argv) +{ + ConvertArgsToUnicode(argc, argv); + + if ( !wxEntryStart(gs_initData.argc, gs_initData.argv) ) + { + FreeConvertedArgs(); + + return false; + } + + return true; +} + +#endif // wxUSE_UNICODE + +// ---------------------------------------------------------------------------- +// clean up +// ---------------------------------------------------------------------------- + +// cleanup done before destroying wxTheApp +static void DoCommonPreCleanup() +{ +#if wxUSE_LOG + // flush the logged messages if any and install a 'safer' log target: the + // default one (wxLogGui) can't be used after the resources are freed just + // below and the user supplied one might be even more unsafe (using any + // wxWidgets GUI function is unsafe starting from now) + wxLog::DontCreateOnDemand(); + + // this will flush the old messages if any + delete wxLog::SetActiveTarget(new wxLogStderr); +#endif // wxUSE_LOG +} + +// cleanup done after destroying wxTheApp +static void DoCommonPostCleanup() +{ + wxModule::CleanUpModules(); + + // we can't do this in wxApp itself because it doesn't know if argv had + // been allocated +#if wxUSE_UNICODE + FreeConvertedArgs(); +#endif // wxUSE_UNICODE + + // use Set(NULL) and not Get() to avoid creating a message output object on + // demand when we just want to delete it + delete wxMessageOutput::Set(NULL); + +#if wxUSE_LOG + // and now delete the last logger as well + delete wxLog::SetActiveTarget(NULL); +#endif // wxUSE_LOG +} + +void wxEntryCleanup() +{ + DoCommonPreCleanup(); + + + // delete the application object + if ( wxTheApp ) + { + wxTheApp->CleanUp(); + + // reset the global pointer to it to NULL before destroying it as in + // some circumstances this can result in executing the code using + // wxTheApp and using half-destroyed object is no good + wxAppConsole * const app = wxApp::GetInstance(); + wxApp::SetInstance(NULL); + delete app; + } + + + DoCommonPostCleanup(); +} + +// ---------------------------------------------------------------------------- +// wxEntry +// ---------------------------------------------------------------------------- + +// for MSW the real wxEntry is defined in msw/main.cpp +#ifndef __WXMSW__ + #define wxEntryReal wxEntry +#endif // !__WXMSW__ + +int wxEntryReal(int& argc, wxChar **argv) +{ + // library initialization + wxInitializer initializer(argc, argv); + + if ( !initializer.IsOk() ) + { +#if wxUSE_LOG + // flush any log messages explaining why we failed + delete wxLog::SetActiveTarget(NULL); +#endif + return -1; + } + + wxTRY + { + + // app initialization + if ( !wxTheApp->CallOnInit() ) + { + // don't call OnExit() if OnInit() failed + return -1; + } + + // ensure that OnExit() is called if OnInit() had succeeded + class CallOnExit + { + public: + ~CallOnExit() { wxTheApp->OnExit(); } + } callOnExit; + + WX_SUPPRESS_UNUSED_WARN(callOnExit); + + // app execution + return wxTheApp->OnRun(); + } + wxCATCH_ALL( wxTheApp->OnUnhandledException(); return -1; ) +} + +#if wxUSE_UNICODE + +// as with wxEntryStart, we provide an ANSI wrapper +int wxEntry(int& argc, char **argv) +{ + ConvertArgsToUnicode(argc, argv); + + return wxEntry(gs_initData.argc, gs_initData.argv); +} + +#endif // wxUSE_UNICODE + +// ---------------------------------------------------------------------------- +// wxInitialize/wxUninitialize +// ---------------------------------------------------------------------------- + +bool wxInitialize(int argc, wxChar **argv) +{ + wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit); + + if ( gs_initData.nInitCount++ ) + { + // already initialized + return true; + } + + return wxEntryStart(argc, argv); +} + +#if wxUSE_UNICODE +bool wxInitialize(int argc, char **argv) +{ + wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit); + + if ( gs_initData.nInitCount++ ) + { + // already initialized + return true; + } + + return wxEntryStart(argc, argv); +} +#endif // wxUSE_UNICODE + +void wxUninitialize() +{ + wxCRIT_SECT_LOCKER(lockInit, gs_initData.csInit); + + if ( --gs_initData.nInitCount == 0 ) + { + wxEntryCleanup(); + } +} diff --git a/Source/3rd Party/wx/src/common/intl.cpp b/Source/3rd Party/wx/src/common/intl.cpp index 2ad2e4e0b..60083b7f5 100644 --- a/Source/3rd Party/wx/src/common/intl.cpp +++ b/Source/3rd Party/wx/src/common/intl.cpp @@ -1,3784 +1,3784 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/intl.cpp -// Purpose: Internationalization and localisation for wxWidgets -// Author: Vadim Zeitlin -// Modified by: Michael N. Filippov -// (2003/09/30 - PluralForms support) -// Created: 29/01/98 -// RCS-ID: $Id: intl.cpp 61340 2009-07-06 21:19:58Z VZ $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declaration -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifdef __EMX__ -// The following define is needed by Innotek's libc to -// make the definition of struct localeconv available. -#define __INTERNAL_DEFS -#endif - -#if wxUSE_INTL - -#ifndef WX_PRECOMP - #include "wx/dynarray.h" - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" - #include "wx/app.h" - #include "wx/hashmap.h" - #include "wx/module.h" -#endif // WX_PRECOMP - -#ifndef __WXWINCE__ - #include -#endif - -// standard headers -#include -#include -#ifdef HAVE_LANGINFO_H - #include -#endif - -#ifdef __WIN32__ - #include "wx/msw/private.h" -#elif defined(__UNIX_LIKE__) - #include "wx/fontmap.h" // for CharsetToEncoding() -#endif - -#include "wx/file.h" -#include "wx/filename.h" -#include "wx/tokenzr.h" -#include "wx/fontmap.h" -#include "wx/encconv.h" -#include "wx/ptr_scpd.h" -#include "wx/apptrait.h" -#include "wx/stdpaths.h" - -#if defined(__WXMAC__) - #include "wx/mac/private.h" // includes mac headers -#endif - -#if defined(__DARWIN__) - #include "wx/mac/corefoundation/cfref.h" - #include - #include "wx/mac/corefoundation/cfstring.h" -#endif - -// ---------------------------------------------------------------------------- -// simple types -// ---------------------------------------------------------------------------- - -// this should *not* be wxChar, this type must have exactly 8 bits! -typedef wxUint8 size_t8; -typedef wxUint32 size_t32; - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// magic number identifying the .mo format file -const size_t32 MSGCATALOG_MAGIC = 0x950412de; -const size_t32 MSGCATALOG_MAGIC_SW = 0xde120495; - -// the constants describing the format of lang_LANG locale string -static const size_t LEN_LANG = 2; -static const size_t LEN_SUBLANG = 2; -static const size_t LEN_FULL = LEN_LANG + 1 + LEN_SUBLANG; // 1 for '_' - -#define TRACE_I18N _T("i18n") - -// ---------------------------------------------------------------------------- -// global functions -// ---------------------------------------------------------------------------- - -#ifdef __WXDEBUG__ - -// small class to suppress the translation erros until exit from current scope -class NoTransErr -{ -public: - NoTransErr() { ms_suppressCount++; } - ~NoTransErr() { ms_suppressCount--; } - - static bool Suppress() { return ms_suppressCount > 0; } - -private: - static size_t ms_suppressCount; -}; - -size_t NoTransErr::ms_suppressCount = 0; - -#else // !Debug - -class NoTransErr -{ -public: - NoTransErr() { } - ~NoTransErr() { } -}; - -#endif // Debug/!Debug - -static wxLocale *wxSetLocale(wxLocale *pLocale); - -// helper functions of GetSystemLanguage() -#ifdef __UNIX__ - -// get just the language part -static inline wxString ExtractLang(const wxString& langFull) -{ - return langFull.Left(LEN_LANG); -} - -// get everything else (including the leading '_') -static inline wxString ExtractNotLang(const wxString& langFull) -{ - return langFull.Mid(LEN_LANG); -} - -#endif // __UNIX__ - - -// ---------------------------------------------------------------------------- -// Plural forms parser -// ---------------------------------------------------------------------------- - -/* - Simplified Grammar - -Expression: - LogicalOrExpression '?' Expression ':' Expression - LogicalOrExpression - -LogicalOrExpression: - LogicalAndExpression "||" LogicalOrExpression // to (a || b) || c - LogicalAndExpression - -LogicalAndExpression: - EqualityExpression "&&" LogicalAndExpression // to (a && b) && c - EqualityExpression - -EqualityExpression: - RelationalExpression "==" RelationalExperession - RelationalExpression "!=" RelationalExperession - RelationalExpression - -RelationalExpression: - MultiplicativeExpression '>' MultiplicativeExpression - MultiplicativeExpression '<' MultiplicativeExpression - MultiplicativeExpression ">=" MultiplicativeExpression - MultiplicativeExpression "<=" MultiplicativeExpression - MultiplicativeExpression - -MultiplicativeExpression: - PmExpression '%' PmExpression - PmExpression - -PmExpression: - N - Number - '(' Expression ')' -*/ - -class wxPluralFormsToken -{ -public: - enum Type - { - T_ERROR, T_EOF, T_NUMBER, T_N, T_PLURAL, T_NPLURALS, T_EQUAL, T_ASSIGN, - T_GREATER, T_GREATER_OR_EQUAL, T_LESS, T_LESS_OR_EQUAL, - T_REMINDER, T_NOT_EQUAL, - T_LOGICAL_AND, T_LOGICAL_OR, T_QUESTION, T_COLON, T_SEMICOLON, - T_LEFT_BRACKET, T_RIGHT_BRACKET - }; - Type type() const { return m_type; } - void setType(Type type) { m_type = type; } - // for T_NUMBER only - typedef int Number; - Number number() const { return m_number; } - void setNumber(Number num) { m_number = num; } -private: - Type m_type; - Number m_number; -}; - - -class wxPluralFormsScanner -{ -public: - wxPluralFormsScanner(const char* s); - const wxPluralFormsToken& token() const { return m_token; } - bool nextToken(); // returns false if error -private: - const char* m_s; - wxPluralFormsToken m_token; -}; - -wxPluralFormsScanner::wxPluralFormsScanner(const char* s) : m_s(s) -{ - nextToken(); -} - -bool wxPluralFormsScanner::nextToken() -{ - wxPluralFormsToken::Type type = wxPluralFormsToken::T_ERROR; - while (isspace((unsigned char) *m_s)) - { - ++m_s; - } - if (*m_s == 0) - { - type = wxPluralFormsToken::T_EOF; - } - else if (isdigit((unsigned char) *m_s)) - { - wxPluralFormsToken::Number number = *m_s++ - '0'; - while (isdigit((unsigned char) *m_s)) - { - number = number * 10 + (*m_s++ - '0'); - } - m_token.setNumber(number); - type = wxPluralFormsToken::T_NUMBER; - } - else if (isalpha((unsigned char) *m_s)) - { - const char* begin = m_s++; - while (isalnum((unsigned char) *m_s)) - { - ++m_s; - } - size_t size = m_s - begin; - if (size == 1 && memcmp(begin, "n", size) == 0) - { - type = wxPluralFormsToken::T_N; - } - else if (size == 6 && memcmp(begin, "plural", size) == 0) - { - type = wxPluralFormsToken::T_PLURAL; - } - else if (size == 8 && memcmp(begin, "nplurals", size) == 0) - { - type = wxPluralFormsToken::T_NPLURALS; - } - } - else if (*m_s == '=') - { - ++m_s; - if (*m_s == '=') - { - ++m_s; - type = wxPluralFormsToken::T_EQUAL; - } - else - { - type = wxPluralFormsToken::T_ASSIGN; - } - } - else if (*m_s == '>') - { - ++m_s; - if (*m_s == '=') - { - ++m_s; - type = wxPluralFormsToken::T_GREATER_OR_EQUAL; - } - else - { - type = wxPluralFormsToken::T_GREATER; - } - } - else if (*m_s == '<') - { - ++m_s; - if (*m_s == '=') - { - ++m_s; - type = wxPluralFormsToken::T_LESS_OR_EQUAL; - } - else - { - type = wxPluralFormsToken::T_LESS; - } - } - else if (*m_s == '%') - { - ++m_s; - type = wxPluralFormsToken::T_REMINDER; - } - else if (*m_s == '!' && m_s[1] == '=') - { - m_s += 2; - type = wxPluralFormsToken::T_NOT_EQUAL; - } - else if (*m_s == '&' && m_s[1] == '&') - { - m_s += 2; - type = wxPluralFormsToken::T_LOGICAL_AND; - } - else if (*m_s == '|' && m_s[1] == '|') - { - m_s += 2; - type = wxPluralFormsToken::T_LOGICAL_OR; - } - else if (*m_s == '?') - { - ++m_s; - type = wxPluralFormsToken::T_QUESTION; - } - else if (*m_s == ':') - { - ++m_s; - type = wxPluralFormsToken::T_COLON; - } else if (*m_s == ';') { - ++m_s; - type = wxPluralFormsToken::T_SEMICOLON; - } - else if (*m_s == '(') - { - ++m_s; - type = wxPluralFormsToken::T_LEFT_BRACKET; - } - else if (*m_s == ')') - { - ++m_s; - type = wxPluralFormsToken::T_RIGHT_BRACKET; - } - m_token.setType(type); - return type != wxPluralFormsToken::T_ERROR; -} - -class wxPluralFormsNode; - -// NB: Can't use wxDEFINE_SCOPED_PTR_TYPE because wxPluralFormsNode is not -// fully defined yet: -class wxPluralFormsNodePtr -{ -public: - wxPluralFormsNodePtr(wxPluralFormsNode *p = NULL) : m_p(p) {} - ~wxPluralFormsNodePtr(); - wxPluralFormsNode& operator*() const { return *m_p; } - wxPluralFormsNode* operator->() const { return m_p; } - wxPluralFormsNode* get() const { return m_p; } - wxPluralFormsNode* release(); - void reset(wxPluralFormsNode *p); - -private: - wxPluralFormsNode *m_p; -}; - -class wxPluralFormsNode -{ -public: - wxPluralFormsNode(const wxPluralFormsToken& token) : m_token(token) {} - const wxPluralFormsToken& token() const { return m_token; } - const wxPluralFormsNode* node(size_t i) const - { return m_nodes[i].get(); } - void setNode(size_t i, wxPluralFormsNode* n); - wxPluralFormsNode* releaseNode(size_t i); - wxPluralFormsToken::Number evaluate(wxPluralFormsToken::Number n) const; - -private: - wxPluralFormsToken m_token; - wxPluralFormsNodePtr m_nodes[3]; -}; - -wxPluralFormsNodePtr::~wxPluralFormsNodePtr() -{ - delete m_p; -} -wxPluralFormsNode* wxPluralFormsNodePtr::release() -{ - wxPluralFormsNode *p = m_p; - m_p = NULL; - return p; -} -void wxPluralFormsNodePtr::reset(wxPluralFormsNode *p) -{ - if (p != m_p) - { - delete m_p; - m_p = p; - } -} - - -void wxPluralFormsNode::setNode(size_t i, wxPluralFormsNode* n) -{ - m_nodes[i].reset(n); -} - -wxPluralFormsNode* wxPluralFormsNode::releaseNode(size_t i) -{ - return m_nodes[i].release(); -} - -wxPluralFormsToken::Number -wxPluralFormsNode::evaluate(wxPluralFormsToken::Number n) const -{ - switch (token().type()) - { - // leaf - case wxPluralFormsToken::T_NUMBER: - return token().number(); - case wxPluralFormsToken::T_N: - return n; - // 2 args - case wxPluralFormsToken::T_EQUAL: - return node(0)->evaluate(n) == node(1)->evaluate(n); - case wxPluralFormsToken::T_NOT_EQUAL: - return node(0)->evaluate(n) != node(1)->evaluate(n); - case wxPluralFormsToken::T_GREATER: - return node(0)->evaluate(n) > node(1)->evaluate(n); - case wxPluralFormsToken::T_GREATER_OR_EQUAL: - return node(0)->evaluate(n) >= node(1)->evaluate(n); - case wxPluralFormsToken::T_LESS: - return node(0)->evaluate(n) < node(1)->evaluate(n); - case wxPluralFormsToken::T_LESS_OR_EQUAL: - return node(0)->evaluate(n) <= node(1)->evaluate(n); - case wxPluralFormsToken::T_REMINDER: - { - wxPluralFormsToken::Number number = node(1)->evaluate(n); - if (number != 0) - { - return node(0)->evaluate(n) % number; - } - else - { - return 0; - } - } - case wxPluralFormsToken::T_LOGICAL_AND: - return node(0)->evaluate(n) && node(1)->evaluate(n); - case wxPluralFormsToken::T_LOGICAL_OR: - return node(0)->evaluate(n) || node(1)->evaluate(n); - // 3 args - case wxPluralFormsToken::T_QUESTION: - return node(0)->evaluate(n) - ? node(1)->evaluate(n) - : node(2)->evaluate(n); - default: - return 0; - } -} - - -class wxPluralFormsCalculator -{ -public: - wxPluralFormsCalculator() : m_nplurals(0), m_plural(0) {} - - // input: number, returns msgstr index - int evaluate(int n) const; - - // input: text after "Plural-Forms:" (e.g. "nplurals=2; plural=(n != 1);"), - // if s == 0, creates default handler - // returns 0 if error - static wxPluralFormsCalculator* make(const char* s = 0); - - ~wxPluralFormsCalculator() {} - - void init(wxPluralFormsToken::Number nplurals, wxPluralFormsNode* plural); - -private: - wxPluralFormsToken::Number m_nplurals; - wxPluralFormsNodePtr m_plural; -}; - -wxDEFINE_SCOPED_PTR_TYPE(wxPluralFormsCalculator) - -void wxPluralFormsCalculator::init(wxPluralFormsToken::Number nplurals, - wxPluralFormsNode* plural) -{ - m_nplurals = nplurals; - m_plural.reset(plural); -} - -int wxPluralFormsCalculator::evaluate(int n) const -{ - if (m_plural.get() == 0) - { - return 0; - } - wxPluralFormsToken::Number number = m_plural->evaluate(n); - if (number < 0 || number > m_nplurals) - { - return 0; - } - return number; -} - - -class wxPluralFormsParser -{ -public: - wxPluralFormsParser(wxPluralFormsScanner& scanner) : m_scanner(scanner) {} - bool parse(wxPluralFormsCalculator& rCalculator); - -private: - wxPluralFormsNode* parsePlural(); - // stops at T_SEMICOLON, returns 0 if error - wxPluralFormsScanner& m_scanner; - const wxPluralFormsToken& token() const; - bool nextToken(); - - wxPluralFormsNode* expression(); - wxPluralFormsNode* logicalOrExpression(); - wxPluralFormsNode* logicalAndExpression(); - wxPluralFormsNode* equalityExpression(); - wxPluralFormsNode* multiplicativeExpression(); - wxPluralFormsNode* relationalExpression(); - wxPluralFormsNode* pmExpression(); -}; - -bool wxPluralFormsParser::parse(wxPluralFormsCalculator& rCalculator) -{ - if (token().type() != wxPluralFormsToken::T_NPLURALS) - return false; - if (!nextToken()) - return false; - if (token().type() != wxPluralFormsToken::T_ASSIGN) - return false; - if (!nextToken()) - return false; - if (token().type() != wxPluralFormsToken::T_NUMBER) - return false; - wxPluralFormsToken::Number nplurals = token().number(); - if (!nextToken()) - return false; - if (token().type() != wxPluralFormsToken::T_SEMICOLON) - return false; - if (!nextToken()) - return false; - if (token().type() != wxPluralFormsToken::T_PLURAL) - return false; - if (!nextToken()) - return false; - if (token().type() != wxPluralFormsToken::T_ASSIGN) - return false; - if (!nextToken()) - return false; - wxPluralFormsNode* plural = parsePlural(); - if (plural == 0) - return false; - if (token().type() != wxPluralFormsToken::T_SEMICOLON) - return false; - if (!nextToken()) - return false; - if (token().type() != wxPluralFormsToken::T_EOF) - return false; - rCalculator.init(nplurals, plural); - return true; -} - -wxPluralFormsNode* wxPluralFormsParser::parsePlural() -{ - wxPluralFormsNode* p = expression(); - if (p == NULL) - { - return NULL; - } - wxPluralFormsNodePtr n(p); - if (token().type() != wxPluralFormsToken::T_SEMICOLON) - { - return NULL; - } - return n.release(); -} - -const wxPluralFormsToken& wxPluralFormsParser::token() const -{ - return m_scanner.token(); -} - -bool wxPluralFormsParser::nextToken() -{ - if (!m_scanner.nextToken()) - return false; - return true; -} - -wxPluralFormsNode* wxPluralFormsParser::expression() -{ - wxPluralFormsNode* p = logicalOrExpression(); - if (p == NULL) - return NULL; - wxPluralFormsNodePtr n(p); - if (token().type() == wxPluralFormsToken::T_QUESTION) - { - wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); - if (!nextToken()) - { - return 0; - } - p = expression(); - if (p == 0) - { - return 0; - } - qn->setNode(1, p); - if (token().type() != wxPluralFormsToken::T_COLON) - { - return 0; - } - if (!nextToken()) - { - return 0; - } - p = expression(); - if (p == 0) - { - return 0; - } - qn->setNode(2, p); - qn->setNode(0, n.release()); - return qn.release(); - } - return n.release(); -} - -wxPluralFormsNode*wxPluralFormsParser::logicalOrExpression() -{ - wxPluralFormsNode* p = logicalAndExpression(); - if (p == NULL) - return NULL; - wxPluralFormsNodePtr ln(p); - if (token().type() == wxPluralFormsToken::T_LOGICAL_OR) - { - wxPluralFormsNodePtr un(new wxPluralFormsNode(token())); - if (!nextToken()) - { - return 0; - } - p = logicalOrExpression(); - if (p == 0) - { - return 0; - } - wxPluralFormsNodePtr rn(p); // right - if (rn->token().type() == wxPluralFormsToken::T_LOGICAL_OR) - { - // see logicalAndExpression comment - un->setNode(0, ln.release()); - un->setNode(1, rn->releaseNode(0)); - rn->setNode(0, un.release()); - return rn.release(); - } - - - un->setNode(0, ln.release()); - un->setNode(1, rn.release()); - return un.release(); - } - return ln.release(); -} - -wxPluralFormsNode* wxPluralFormsParser::logicalAndExpression() -{ - wxPluralFormsNode* p = equalityExpression(); - if (p == NULL) - return NULL; - wxPluralFormsNodePtr ln(p); // left - if (token().type() == wxPluralFormsToken::T_LOGICAL_AND) - { - wxPluralFormsNodePtr un(new wxPluralFormsNode(token())); // up - if (!nextToken()) - { - return NULL; - } - p = logicalAndExpression(); - if (p == 0) - { - return NULL; - } - wxPluralFormsNodePtr rn(p); // right - if (rn->token().type() == wxPluralFormsToken::T_LOGICAL_AND) - { -// transform 1 && (2 && 3) -> (1 && 2) && 3 -// u r -// l r -> u 3 -// 2 3 l 2 - un->setNode(0, ln.release()); - un->setNode(1, rn->releaseNode(0)); - rn->setNode(0, un.release()); - return rn.release(); - } - - un->setNode(0, ln.release()); - un->setNode(1, rn.release()); - return un.release(); - } - return ln.release(); -} - -wxPluralFormsNode* wxPluralFormsParser::equalityExpression() -{ - wxPluralFormsNode* p = relationalExpression(); - if (p == NULL) - return NULL; - wxPluralFormsNodePtr n(p); - if (token().type() == wxPluralFormsToken::T_EQUAL - || token().type() == wxPluralFormsToken::T_NOT_EQUAL) - { - wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); - if (!nextToken()) - { - return NULL; - } - p = relationalExpression(); - if (p == NULL) - { - return NULL; - } - qn->setNode(1, p); - qn->setNode(0, n.release()); - return qn.release(); - } - return n.release(); -} - -wxPluralFormsNode* wxPluralFormsParser::relationalExpression() -{ - wxPluralFormsNode* p = multiplicativeExpression(); - if (p == NULL) - return NULL; - wxPluralFormsNodePtr n(p); - if (token().type() == wxPluralFormsToken::T_GREATER - || token().type() == wxPluralFormsToken::T_LESS - || token().type() == wxPluralFormsToken::T_GREATER_OR_EQUAL - || token().type() == wxPluralFormsToken::T_LESS_OR_EQUAL) - { - wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); - if (!nextToken()) - { - return NULL; - } - p = multiplicativeExpression(); - if (p == NULL) - { - return NULL; - } - qn->setNode(1, p); - qn->setNode(0, n.release()); - return qn.release(); - } - return n.release(); -} - -wxPluralFormsNode* wxPluralFormsParser::multiplicativeExpression() -{ - wxPluralFormsNode* p = pmExpression(); - if (p == NULL) - return NULL; - wxPluralFormsNodePtr n(p); - if (token().type() == wxPluralFormsToken::T_REMINDER) - { - wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); - if (!nextToken()) - { - return NULL; - } - p = pmExpression(); - if (p == NULL) - { - return NULL; - } - qn->setNode(1, p); - qn->setNode(0, n.release()); - return qn.release(); - } - return n.release(); -} - -wxPluralFormsNode* wxPluralFormsParser::pmExpression() -{ - wxPluralFormsNodePtr n; - if (token().type() == wxPluralFormsToken::T_N - || token().type() == wxPluralFormsToken::T_NUMBER) - { - n.reset(new wxPluralFormsNode(token())); - if (!nextToken()) - { - return NULL; - } - } - else if (token().type() == wxPluralFormsToken::T_LEFT_BRACKET) { - if (!nextToken()) - { - return NULL; - } - wxPluralFormsNode* p = expression(); - if (p == NULL) - { - return NULL; - } - n.reset(p); - if (token().type() != wxPluralFormsToken::T_RIGHT_BRACKET) - { - return NULL; - } - if (!nextToken()) - { - return NULL; - } - } - else - { - return NULL; - } - return n.release(); -} - -wxPluralFormsCalculator* wxPluralFormsCalculator::make(const char* s) -{ - wxPluralFormsCalculatorPtr calculator(new wxPluralFormsCalculator); - if (s != NULL) - { - wxPluralFormsScanner scanner(s); - wxPluralFormsParser p(scanner); - if (!p.parse(*calculator)) - { - return NULL; - } - } - return calculator.release(); -} - - - - -// ---------------------------------------------------------------------------- -// wxMsgCatalogFile corresponds to one disk-file message catalog. -// -// This is a "low-level" class and is used only by wxMsgCatalog -// ---------------------------------------------------------------------------- - -WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxString, wxMessagesHash); - -class wxMsgCatalogFile -{ -public: - // ctor & dtor - wxMsgCatalogFile(); - ~wxMsgCatalogFile(); - - // load the catalog from disk (szDirPrefix corresponds to language) - bool Load(const wxChar *szDirPrefix, const wxChar *szName, - wxPluralFormsCalculatorPtr& rPluralFormsCalculator); - - // fills the hash with string-translation pairs - void FillHash(wxMessagesHash& hash, - const wxString& msgIdCharset, - bool convertEncoding) const; - - // return the charset of the strings in this catalog or empty string if - // none/unknown - wxString GetCharset() const { return m_charset; } - -private: - // this implementation is binary compatible with GNU gettext() version 0.10 - - // an entry in the string table - struct wxMsgTableEntry - { - size_t32 nLen; // length of the string - size_t32 ofsString; // pointer to the string - }; - - // header of a .mo file - struct wxMsgCatalogHeader - { - size_t32 magic, // offset +00: magic id - revision, // +04: revision - numStrings; // +08: number of strings in the file - size_t32 ofsOrigTable, // +0C: start of original string table - ofsTransTable; // +10: start of translated string table - size_t32 nHashSize, // +14: hash table size - ofsHashTable; // +18: offset of hash table start - }; - - // all data is stored here, NULL if no data loaded - size_t8 *m_pData; - - // amount of memory pointed to by m_pData. - size_t32 m_nSize; - - // data description - size_t32 m_numStrings; // number of strings in this domain - wxMsgTableEntry *m_pOrigTable, // pointer to original strings - *m_pTransTable; // translated - - wxString m_charset; // from the message catalog header - - - // swap the 2 halves of 32 bit integer if needed - size_t32 Swap(size_t32 ui) const - { - return m_bSwapped ? (ui << 24) | ((ui & 0xff00) << 8) | - ((ui >> 8) & 0xff00) | (ui >> 24) - : ui; - } - - const char *StringAtOfs(wxMsgTableEntry *pTable, size_t32 n) const - { - const wxMsgTableEntry * const ent = pTable + n; - - // this check could fail for a corrupt message catalog - size_t32 ofsString = Swap(ent->ofsString); - if ( ofsString + Swap(ent->nLen) > m_nSize) - { - return NULL; - } - - return (const char *)(m_pData + ofsString); - } - - bool m_bSwapped; // wrong endianness? - - DECLARE_NO_COPY_CLASS(wxMsgCatalogFile) -}; - - -// ---------------------------------------------------------------------------- -// wxMsgCatalog corresponds to one loaded message catalog. -// -// This is a "low-level" class and is used only by wxLocale (that's why -// it's designed to be stored in a linked list) -// ---------------------------------------------------------------------------- - -class wxMsgCatalog -{ -public: -#if !wxUSE_UNICODE - wxMsgCatalog() { m_conv = NULL; } - ~wxMsgCatalog(); -#endif - - // load the catalog from disk (szDirPrefix corresponds to language) - bool Load(const wxChar *szDirPrefix, const wxChar *szName, - const wxChar *msgIdCharset = NULL, bool bConvertEncoding = false); - - // get name of the catalog - wxString GetName() const { return m_name; } - - // get the translated string: returns NULL if not found - const wxChar *GetString(const wxChar *sz, size_t n = size_t(-1)) const; - - // public variable pointing to the next element in a linked list (or NULL) - wxMsgCatalog *m_pNext; - -private: - wxMessagesHash m_messages; // all messages in the catalog - wxString m_name; // name of the domain - -#if !wxUSE_UNICODE - // the conversion corresponding to this catalog charset if we installed it - // as the global one - wxCSConv *m_conv; -#endif - - wxPluralFormsCalculatorPtr m_pluralFormsCalculator; -}; - -// ---------------------------------------------------------------------------- -// global variables -// ---------------------------------------------------------------------------- - -// the list of the directories to search for message catalog files -static wxArrayString gs_searchPrefixes; - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxMsgCatalogFile class -// ---------------------------------------------------------------------------- - -wxMsgCatalogFile::wxMsgCatalogFile() -{ - m_pData = NULL; - m_nSize = 0; -} - -wxMsgCatalogFile::~wxMsgCatalogFile() -{ - delete [] m_pData; -} - -// return the directories to search for message catalogs under the given -// prefix, separated by wxPATH_SEP -static -wxString GetMsgCatalogSubdirs(const wxChar *prefix, const wxChar *lang) -{ - // Search first in Unix-standard prefix/lang/LC_MESSAGES, then in - // prefix/lang and finally in just prefix. - // - // Note that we use LC_MESSAGES on all platforms and not just Unix, because - // it doesn't cost much to look into one more directory and doing it this - // way has two important benefits: - // a) we don't break compatibility with wx-2.6 and older by stopping to - // look in a directory where the catalogs used to be and thus silently - // breaking apps after they are recompiled against the latest wx - // b) it makes it possible to package app's support files in the same - // way on all target platforms - wxString pathPrefix; - pathPrefix << prefix << wxFILE_SEP_PATH << lang; - - wxString searchPath; - searchPath.reserve(4*pathPrefix.length()); - searchPath << pathPrefix << wxFILE_SEP_PATH << wxT("LC_MESSAGES") << wxPATH_SEP - << prefix << wxFILE_SEP_PATH << wxPATH_SEP - << pathPrefix; - - return searchPath; -} - -// construct the search path for the given language -static wxString GetFullSearchPath(const wxChar *lang) -{ - // first take the entries explicitly added by the program - wxArrayString paths; - paths.reserve(gs_searchPrefixes.size() + 1); - size_t n, - count = gs_searchPrefixes.size(); - for ( n = 0; n < count; n++ ) - { - paths.Add(GetMsgCatalogSubdirs(gs_searchPrefixes[n], lang)); - } - - -#if wxUSE_STDPATHS - // then look in the standard location - const wxString stdp = wxStandardPaths::Get(). - GetLocalizedResourcesDir(lang, wxStandardPaths::ResourceCat_Messages); - - if ( paths.Index(stdp) == wxNOT_FOUND ) - paths.Add(stdp); -#endif // wxUSE_STDPATHS - - // last look in default locations -#ifdef __UNIX__ - // LC_PATH is a standard env var containing the search path for the .mo - // files - const wxChar *pszLcPath = wxGetenv(wxT("LC_PATH")); - if ( pszLcPath ) - { - const wxString lcp = GetMsgCatalogSubdirs(pszLcPath, lang); - if ( paths.Index(lcp) == wxNOT_FOUND ) - paths.Add(lcp); - } - - // also add the one from where wxWin was installed: - wxString wxp = wxGetInstallPrefix(); - if ( !wxp.empty() ) - { - wxp = GetMsgCatalogSubdirs(wxp + _T("/share/locale"), lang); - if ( paths.Index(wxp) == wxNOT_FOUND ) - paths.Add(wxp); - } -#endif // __UNIX__ - - - // finally construct the full search path - wxString searchPath; - searchPath.reserve(500); - count = paths.size(); - for ( n = 0; n < count; n++ ) - { - searchPath += paths[n]; - if ( n != count - 1 ) - searchPath += wxPATH_SEP; - } - - return searchPath; -} - -// open disk file and read in it's contents -bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName, - wxPluralFormsCalculatorPtr& rPluralFormsCalculator) -{ - wxString searchPath; - -#if wxUSE_FONTMAP - // first look for the catalog for this language and the current locale: - // notice that we don't use the system name for the locale as this would - // force us to install catalogs in different locations depending on the - // system but always use the canonical name - wxFontEncoding encSys = wxLocale::GetSystemEncoding(); - if ( encSys != wxFONTENCODING_SYSTEM ) - { - wxString fullname(szDirPrefix); - fullname << _T('.') << wxFontMapperBase::GetEncodingName(encSys); - searchPath << GetFullSearchPath(fullname) << wxPATH_SEP; - } -#endif // wxUSE_FONTMAP - - - searchPath += GetFullSearchPath(szDirPrefix); - const wxChar *sublocale = wxStrchr(szDirPrefix, wxT('_')); - if ( sublocale ) - { - // also add just base locale name: for things like "fr_BE" (belgium - // french) we should use "fr" if no belgium specific message catalogs - // exist - searchPath << wxPATH_SEP - << GetFullSearchPath(wxString(szDirPrefix). - Left((size_t)(sublocale - szDirPrefix))); - } - - // don't give translation errors here because the wxstd catalog might - // not yet be loaded (and it's normal) - // - // (we're using an object because we have several return paths) - - NoTransErr noTransErr; - wxLogVerbose(_("looking for catalog '%s' in path '%s'."), - szName, searchPath.c_str()); - wxLogTrace(TRACE_I18N, _T("Looking for \"%s.mo\" in \"%s\""), - szName, searchPath.c_str()); - - wxFileName fn(szName); - fn.SetExt(_T("mo")); - wxString strFullName; - if ( !wxFindFileInPath(&strFullName, searchPath, fn.GetFullPath()) ) { - wxLogVerbose(_("catalog file for domain '%s' not found."), szName); - wxLogTrace(TRACE_I18N, _T("Catalog \"%s.mo\" not found"), szName); - return false; - } - - // open file - wxLogVerbose(_("using catalog '%s' from '%s'."), szName, strFullName.c_str()); - wxLogTrace(TRACE_I18N, _T("Using catalog \"%s\"."), strFullName.c_str()); - - wxFile fileMsg(strFullName); - if ( !fileMsg.IsOpened() ) - return false; - - // get the file size (assume it is less than 4Gb...) - wxFileOffset lenFile = fileMsg.Length(); - if ( lenFile == wxInvalidOffset ) - return false; - - size_t nSize = wx_truncate_cast(size_t, lenFile); - wxASSERT_MSG( nSize == lenFile + size_t(0), _T("message catalog bigger than 4GB?") ); - - // read the whole file in memory - m_pData = new size_t8[nSize]; - if ( fileMsg.Read(m_pData, nSize) != lenFile ) { - wxDELETEA(m_pData); - return false; - } - - // examine header - bool bValid = nSize + (size_t)0 > sizeof(wxMsgCatalogHeader); - - wxMsgCatalogHeader *pHeader = (wxMsgCatalogHeader *)m_pData; - if ( bValid ) { - // we'll have to swap all the integers if it's true - m_bSwapped = pHeader->magic == MSGCATALOG_MAGIC_SW; - - // check the magic number - bValid = m_bSwapped || pHeader->magic == MSGCATALOG_MAGIC; - } - - if ( !bValid ) { - // it's either too short or has incorrect magic number - wxLogWarning(_("'%s' is not a valid message catalog."), strFullName.c_str()); - - wxDELETEA(m_pData); - return false; - } - - // initialize - m_numStrings = Swap(pHeader->numStrings); - m_pOrigTable = (wxMsgTableEntry *)(m_pData + - Swap(pHeader->ofsOrigTable)); - m_pTransTable = (wxMsgTableEntry *)(m_pData + - Swap(pHeader->ofsTransTable)); - m_nSize = (size_t32)nSize; - - // now parse catalog's header and try to extract catalog charset and - // plural forms formula from it: - - const char* headerData = StringAtOfs(m_pOrigTable, 0); - if (headerData && headerData[0] == 0) - { - // Extract the charset: - wxString header = wxString::FromAscii(StringAtOfs(m_pTransTable, 0)); - int begin = header.Find(wxT("Content-Type: text/plain; charset=")); - if (begin != wxNOT_FOUND) - { - begin += 34; //strlen("Content-Type: text/plain; charset=") - size_t end = header.find('\n', begin); - if (end != size_t(-1)) - { - m_charset.assign(header, begin, end - begin); - if (m_charset == wxT("CHARSET")) - { - // "CHARSET" is not valid charset, but lazy translator - m_charset.Clear(); - } - } - } - // else: incorrectly filled Content-Type header - - // Extract plural forms: - begin = header.Find(wxT("Plural-Forms:")); - if (begin != wxNOT_FOUND) - { - begin += 13; - size_t end = header.find('\n', begin); - if (end != size_t(-1)) - { - wxString pfs(header, begin, end - begin); - wxPluralFormsCalculator* pCalculator = wxPluralFormsCalculator - ::make(pfs.ToAscii()); - if (pCalculator != 0) - { - rPluralFormsCalculator.reset(pCalculator); - } - else - { - wxLogVerbose(_("Cannot parse Plural-Forms:'%s'"), pfs.c_str()); - } - } - } - if (rPluralFormsCalculator.get() == NULL) - { - rPluralFormsCalculator.reset(wxPluralFormsCalculator::make()); - } - } - - // everything is fine - return true; -} - -void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, - const wxString& msgIdCharset, - bool convertEncoding) const -{ -#if wxUSE_UNICODE - // this parameter doesn't make sense, we always must convert encoding in - // Unicode build - convertEncoding = true; -#elif wxUSE_FONTMAP - if ( convertEncoding ) - { - // determine if we need any conversion at all - wxFontEncoding encCat = wxFontMapperBase::GetEncodingFromName(m_charset); - if ( encCat == wxLocale::GetSystemEncoding() ) - { - // no need to convert - convertEncoding = false; - } - } -#endif // wxUSE_UNICODE/wxUSE_FONTMAP - -#if wxUSE_WCHAR_T - // conversion to use to convert catalog strings to the GUI encoding - wxMBConv *inputConv, - *inputConvPtr = NULL; // same as inputConv but safely deleteable - if ( convertEncoding && !m_charset.empty() ) - { - inputConvPtr = - inputConv = new wxCSConv(m_charset); - } - else // no need or not possible to convert the encoding - { -#if wxUSE_UNICODE - // we must somehow convert the narrow strings in the message catalog to - // wide strings, so use the default conversion if we have no charset - inputConv = wxConvCurrent; -#else // !wxUSE_UNICODE - inputConv = NULL; -#endif // wxUSE_UNICODE/!wxUSE_UNICODE - } - - // conversion to apply to msgid strings before looking them up: we only - // need it if the msgids are neither in 7 bit ASCII nor in the same - // encoding as the catalog - wxCSConv *sourceConv = msgIdCharset.empty() || (msgIdCharset == m_charset) - ? NULL - : new wxCSConv(msgIdCharset); - -#elif wxUSE_FONTMAP - wxASSERT_MSG( msgIdCharset.empty(), - _T("non-ASCII msgid languages only supported if wxUSE_WCHAR_T=1") ); - - wxEncodingConverter converter; - if ( convertEncoding ) - { - wxFontEncoding targetEnc = wxFONTENCODING_SYSTEM; - wxFontEncoding enc = wxFontMapperBase::Get()->CharsetToEncoding(m_charset, false); - if ( enc == wxFONTENCODING_SYSTEM ) - { - convertEncoding = false; // unknown encoding - } - else - { - targetEnc = wxLocale::GetSystemEncoding(); - if (targetEnc == wxFONTENCODING_SYSTEM) - { - wxFontEncodingArray a = wxEncodingConverter::GetPlatformEquivalents(enc); - if (a[0] == enc) - // no conversion needed, locale uses native encoding - convertEncoding = false; - if (a.GetCount() == 0) - // we don't know common equiv. under this platform - convertEncoding = false; - targetEnc = a[0]; - } - } - - if ( convertEncoding ) - { - converter.Init(enc, targetEnc); - } - } -#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T - (void)convertEncoding; // get rid of warnings about unused parameter - - for (size_t32 i = 0; i < m_numStrings; i++) - { - const char *data = StringAtOfs(m_pOrigTable, i); - - wxString msgid; -#if wxUSE_UNICODE - msgid = wxString(data, *inputConv); -#else // ASCII - #if wxUSE_WCHAR_T - if ( inputConv && sourceConv ) - msgid = wxString(inputConv->cMB2WC(data), *sourceConv); - else - #endif - msgid = data; -#endif // wxUSE_UNICODE - - data = StringAtOfs(m_pTransTable, i); - size_t length = Swap(m_pTransTable[i].nLen); - size_t offset = 0; - size_t index = 0; - while (offset < length) - { - const char * const str = data + offset; - - wxString msgstr; -#if wxUSE_UNICODE - msgstr = wxString(str, *inputConv); -#elif wxUSE_WCHAR_T - if ( inputConv ) - msgstr = wxString(inputConv->cMB2WC(str), *wxConvUI); - else - msgstr = str; -#else // !wxUSE_WCHAR_T - #if wxUSE_FONTMAP - if ( convertEncoding ) - msgstr = wxString(converter.Convert(str)); - else - #endif - msgstr = str; -#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T - - if ( !msgstr.empty() ) - { - hash[index == 0 ? msgid : msgid + wxChar(index)] = msgstr; - } - - // skip this string - offset += strlen(str) + 1; - ++index; - } - } - -#if wxUSE_WCHAR_T - delete sourceConv; - delete inputConvPtr; -#endif // wxUSE_WCHAR_T -} - - -// ---------------------------------------------------------------------------- -// wxMsgCatalog class -// ---------------------------------------------------------------------------- - -#if !wxUSE_UNICODE -wxMsgCatalog::~wxMsgCatalog() -{ - if ( m_conv ) - { - if ( wxConvUI == m_conv ) - { - // we only change wxConvUI if it points to wxConvLocal so we reset - // it back to it too - wxConvUI = &wxConvLocal; - } - - delete m_conv; - } -} -#endif // !wxUSE_UNICODE - -bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName, - const wxChar *msgIdCharset, bool bConvertEncoding) -{ - wxMsgCatalogFile file; - - m_name = szName; - - if ( !file.Load(szDirPrefix, szName, m_pluralFormsCalculator) ) - return false; - - file.FillHash(m_messages, msgIdCharset, bConvertEncoding); - -#if !wxUSE_UNICODE && wxUSE_WCHAR_T - // we should use a conversion compatible with the message catalog encoding - // in the GUI if we don't convert the strings to the current conversion but - // as the encoding is global, only change it once, otherwise we could get - // into trouble if we use several message catalogs with different encodings - // - // this is, of course, a hack but it at least allows the program to use - // message catalogs in any encodings without asking the user to change his - // locale - if ( !bConvertEncoding && - !file.GetCharset().empty() && - wxConvUI == &wxConvLocal ) - { - wxConvUI = - m_conv = new wxCSConv(file.GetCharset()); - } -#endif // !wxUSE_UNICODE && wxUSE_WCHAR_T - - return true; -} - -const wxChar *wxMsgCatalog::GetString(const wxChar *sz, size_t n) const -{ - int index = 0; - if (n != size_t(-1)) - { - index = m_pluralFormsCalculator->evaluate(n); - } - wxMessagesHash::const_iterator i; - if (index != 0) - { - i = m_messages.find(wxString(sz) + wxChar(index)); // plural - } - else - { - i = m_messages.find(sz); - } - - if ( i != m_messages.end() ) - { - return i->second.c_str(); - } - else - return NULL; -} - -// ---------------------------------------------------------------------------- -// wxLocale -// ---------------------------------------------------------------------------- - -#include "wx/arrimpl.cpp" -WX_DECLARE_EXPORTED_OBJARRAY(wxLanguageInfo, wxLanguageInfoArray); -WX_DEFINE_OBJARRAY(wxLanguageInfoArray) - -wxLanguageInfoArray *wxLocale::ms_languagesDB = NULL; - -/*static*/ void wxLocale::CreateLanguagesDB() -{ - if (ms_languagesDB == NULL) - { - ms_languagesDB = new wxLanguageInfoArray; - InitLanguagesDB(); - } -} - -/*static*/ void wxLocale::DestroyLanguagesDB() -{ - delete ms_languagesDB; - ms_languagesDB = NULL; -} - - -void wxLocale::DoCommonInit() -{ - m_pszOldLocale = NULL; - - m_pOldLocale = wxSetLocale(this); - - m_pMsgCat = NULL; - m_language = wxLANGUAGE_UNKNOWN; - m_initialized = false; -} - -// NB: this function has (desired) side effect of changing current locale -bool wxLocale::Init(const wxChar *szName, - const wxChar *szShort, - const wxChar *szLocale, - bool bLoadDefault, - bool bConvertEncoding) -{ - wxASSERT_MSG( !m_initialized, - _T("you can't call wxLocale::Init more than once") ); - - m_initialized = true; - m_strLocale = szName; - m_strShort = szShort; - m_bConvertEncoding = bConvertEncoding; - m_language = wxLANGUAGE_UNKNOWN; - - // change current locale (default: same as long name) - if ( szLocale == NULL ) - { - // the argument to setlocale() - szLocale = szShort; - - wxCHECK_MSG( szLocale, false, _T("no locale to set in wxLocale::Init()") ); - } - -#ifdef __WXWINCE__ - // FIXME: I'm guessing here - wxChar localeName[256]; - int ret = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLANGUAGE, localeName, - 256); - if (ret != 0) - { - m_pszOldLocale = wxStrdup(localeName); - } - else - m_pszOldLocale = NULL; - - // TODO: how to find languageId - // SetLocaleInfo(languageId, SORT_DEFAULT, localeName); -#else - wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, szLocale); - if ( oldLocale ) - m_pszOldLocale = wxStrdup(oldLocale); - else - m_pszOldLocale = NULL; -#endif - - if ( m_pszOldLocale == NULL ) - wxLogError(_("locale '%s' can not be set."), szLocale); - - // the short name will be used to look for catalog files as well, - // so we need something here - if ( m_strShort.empty() ) { - // FIXME I don't know how these 2 letter abbreviations are formed, - // this wild guess is surely wrong - if ( szLocale && szLocale[0] ) - { - m_strShort += (wxChar)wxTolower(szLocale[0]); - if ( szLocale[1] ) - m_strShort += (wxChar)wxTolower(szLocale[1]); - } - } - - // load the default catalog with wxWidgets standard messages - m_pMsgCat = NULL; - bool bOk = true; - if ( bLoadDefault ) - { - bOk = AddCatalog(wxT("wxstd")); - - // there may be a catalog with toolkit specific overrides, it is not - // an error if this does not exist - if ( bOk ) - { - wxString port(wxPlatformInfo::Get().GetPortIdName()); - if ( !port.empty() ) - { - AddCatalog(port.BeforeFirst(wxT('/')).MakeLower()); - } - } - } - - return bOk; -} - - -#if defined(__UNIX__) && wxUSE_UNICODE && !defined(__WXMAC__) -static wxWCharBuffer wxSetlocaleTryUTF(int c, const wxChar *lc) -{ - wxMB2WXbuf l = wxSetlocale(c, lc); - if ( !l && lc && lc[0] != 0 ) - { - wxString buf(lc); - wxString buf2; - buf2 = buf + wxT(".UTF-8"); - l = wxSetlocale(c, buf2.c_str()); - if ( !l ) - { - buf2 = buf + wxT(".utf-8"); - l = wxSetlocale(c, buf2.c_str()); - } - if ( !l ) - { - buf2 = buf + wxT(".UTF8"); - l = wxSetlocale(c, buf2.c_str()); - } - if ( !l ) - { - buf2 = buf + wxT(".utf8"); - l = wxSetlocale(c, buf2.c_str()); - } - } - return l; -} -#else -#define wxSetlocaleTryUTF(c, lc) wxSetlocale(c, lc) -#endif - -bool wxLocale::Init(int language, int flags) -{ - int lang = language; - if (lang == wxLANGUAGE_DEFAULT) - { - // auto detect the language - lang = GetSystemLanguage(); - } - - // We failed to detect system language, so we will use English: - if (lang == wxLANGUAGE_UNKNOWN) - { - return false; - } - - const wxLanguageInfo *info = GetLanguageInfo(lang); - - // Unknown language: - if (info == NULL) - { - wxLogError(wxT("Unknown language %i."), lang); - return false; - } - - wxString name = info->Description; - wxString canonical = info->CanonicalName; - wxString locale; - - // Set the locale: -#if defined(__OS2__) - wxMB2WXbuf retloc = wxSetlocale(LC_ALL , wxEmptyString); -#elif defined(__UNIX__) && !defined(__WXMAC__) - if (language != wxLANGUAGE_DEFAULT) - locale = info->CanonicalName; - - wxMB2WXbuf retloc = wxSetlocaleTryUTF(LC_ALL, locale); - - const wxString langOnly = locale.Left(2); - if ( !retloc ) - { - // Some C libraries don't like xx_YY form and require xx only - retloc = wxSetlocaleTryUTF(LC_ALL, langOnly); - } - -#if wxUSE_FONTMAP - // some systems (e.g. FreeBSD and HP-UX) don't have xx_YY aliases but - // require the full xx_YY.encoding form, so try using UTF-8 because this is - // the only thing we can do generically - // - // TODO: add encodings applicable to each language to the lang DB and try - // them all in turn here - if ( !retloc ) - { - const wxChar **names = - wxFontMapperBase::GetAllEncodingNames(wxFONTENCODING_UTF8); - while ( *names ) - { - retloc = wxSetlocale(LC_ALL, locale + _T('.') + *names++); - if ( retloc ) - break; - } - } -#endif // wxUSE_FONTMAP - - if ( !retloc ) - { - // Some C libraries (namely glibc) still use old ISO 639, - // so will translate the abbrev for them - wxString localeAlt; - if ( langOnly == wxT("he") ) - localeAlt = wxT("iw") + locale.Mid(3); - else if ( langOnly == wxT("id") ) - localeAlt = wxT("in") + locale.Mid(3); - else if ( langOnly == wxT("yi") ) - localeAlt = wxT("ji") + locale.Mid(3); - else if ( langOnly == wxT("nb") ) - localeAlt = wxT("no_NO"); - else if ( langOnly == wxT("nn") ) - localeAlt = wxT("no_NY"); - - if ( !localeAlt.empty() ) - { - retloc = wxSetlocaleTryUTF(LC_ALL, localeAlt); - if ( !retloc ) - retloc = wxSetlocaleTryUTF(LC_ALL, localeAlt.Left(2)); - } - } - - if ( !retloc ) - { - wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str()); - return false; - } - -#ifdef __AIX__ - // at least in AIX 5.2 libc is buggy and the string returned from setlocale(LC_ALL) - // can't be passed back to it because it returns 6 strings (one for each locale - // category), i.e. for C locale we get back "C C C C C C" - // - // this contradicts IBM own docs but this is not of much help, so just work around - // it in the crudest possible manner - wxChar *p = wxStrchr((wxChar *)retloc, _T(' ')); - if ( p ) - *p = _T('\0'); -#endif // __AIX__ - -#elif defined(__WIN32__) - - #if wxUSE_UNICODE && (defined(__VISUALC__) || defined(__MINGW32__)) - // NB: setlocale() from msvcrt.dll (used by VC++ and Mingw) - // can't set locale to language that can only be written using - // Unicode. Therefore wxSetlocale call failed, but we don't want - // to report it as an error -- so that at least message catalogs - // can be used. Watch for code marked with - // #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS bellow. - #define SETLOCALE_FAILS_ON_UNICODE_LANGS - #endif - -#if !wxUSE_UNICODE - const -#endif - wxMB2WXbuf retloc = wxT("C"); - if (language != wxLANGUAGE_DEFAULT) - { - if (info->WinLang == 0) - { - wxLogWarning(wxT("Locale '%s' not supported by OS."), name.c_str()); - // retloc already set to "C" - } - else - { - int codepage - #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS - = -1 - #endif - ; - wxUint32 lcid = MAKELCID(MAKELANGID(info->WinLang, info->WinSublang), - SORT_DEFAULT); - // FIXME -#ifndef __WXWINCE__ - SetThreadLocale(lcid); -#endif - // NB: we must translate LCID to CRT's setlocale string ourselves, - // because SetThreadLocale does not modify change the - // interpretation of setlocale(LC_ALL, "") call: - wxChar buffer[256]; - buffer[0] = wxT('\0'); - GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, buffer, 256); - locale << buffer; - if (GetLocaleInfo(lcid, LOCALE_SENGCOUNTRY, buffer, 256) > 0) - locale << wxT("_") << buffer; - if (GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, buffer, 256) > 0) - { - codepage = wxAtoi(buffer); - if (codepage != 0) - locale << wxT(".") << buffer; - } - if (locale.empty()) - { - wxLogLastError(wxT("SetThreadLocale")); - wxLogError(wxT("Cannot set locale to language %s."), name.c_str()); - return false; - } - else - { - // FIXME -#ifndef __WXWINCE__ - retloc = wxSetlocale(LC_ALL, locale); -#endif -#ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS - if (codepage == 0 && (const wxChar*)retloc == NULL) - { - retloc = wxT("C"); - } -#endif - } - } - } - else - { - // FIXME -#ifndef __WXWINCE__ - retloc = wxSetlocale(LC_ALL, wxEmptyString); -#else - retloc = NULL; -#endif -#ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS - if ((const wxChar*)retloc == NULL) - { - wxChar buffer[16]; - if (GetLocaleInfo(LOCALE_USER_DEFAULT, - LOCALE_IDEFAULTANSICODEPAGE, buffer, 16) > 0 && - wxStrcmp(buffer, wxT("0")) == 0) - { - retloc = wxT("C"); - } - } -#endif - } - - if ( !retloc ) - { - wxLogError(wxT("Cannot set locale to language %s."), name.c_str()); - return false; - } -#elif defined(__WXMAC__) - if (lang == wxLANGUAGE_DEFAULT) - locale = wxEmptyString; - else - locale = info->CanonicalName; - - wxMB2WXbuf retloc = wxSetlocale(LC_ALL, locale); - - if ( !retloc ) - { - // Some C libraries don't like xx_YY form and require xx only - retloc = wxSetlocale(LC_ALL, locale.Mid(0,2)); - } - if ( !retloc ) - { - wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str()); - return false; - } -#else - wxUnusedVar(flags); - return false; - #define WX_NO_LOCALE_SUPPORT -#endif - -#ifndef WX_NO_LOCALE_SUPPORT - wxChar *szLocale = retloc ? wxStrdup(retloc) : NULL; - bool ret = Init(name, canonical, szLocale, - (flags & wxLOCALE_LOAD_DEFAULT) != 0, - (flags & wxLOCALE_CONV_ENCODING) != 0); - free(szLocale); - - if (IsOk()) // setlocale() succeeded - m_language = lang; - - return ret; -#endif // !WX_NO_LOCALE_SUPPORT -} - - - -void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) -{ - if ( gs_searchPrefixes.Index(prefix) == wxNOT_FOUND ) - { - gs_searchPrefixes.Add(prefix); - } - //else: already have it -} - -/*static*/ int wxLocale::GetSystemLanguage() -{ - CreateLanguagesDB(); - - // init i to avoid compiler warning - size_t i = 0, - count = ms_languagesDB->GetCount(); - -#if defined(__UNIX__) && !defined(__WXMAC__) - // first get the string identifying the language from the environment - wxString langFull; - if (!wxGetEnv(wxT("LC_ALL"), &langFull) && - !wxGetEnv(wxT("LC_MESSAGES"), &langFull) && - !wxGetEnv(wxT("LANG"), &langFull)) - { - // no language specified, treat it as English - return wxLANGUAGE_ENGLISH_US; - } - - if ( langFull == _T("C") || langFull == _T("POSIX") ) - { - // default C locale is English too - return wxLANGUAGE_ENGLISH_US; - } - - // the language string has the following form - // - // lang[_LANG][.encoding][@modifier] - // - // (see environ(5) in the Open Unix specification) - // - // where lang is the primary language, LANG is a sublang/territory, - // encoding is the charset to use and modifier "allows the user to select - // a specific instance of localization data within a single category" - // - // for example, the following strings are valid: - // fr - // fr_FR - // de_DE.iso88591 - // de_DE@euro - // de_DE.iso88591@euro - - // for now we don't use the encoding, although we probably should (doing - // translations of the msg catalogs on the fly as required) (TODO) - // - // we need the modified for languages like Valencian: ca_ES@valencia - // though, remember it - wxString modifier; - size_t posModifier = langFull.find_first_of(_T("@")); - if ( posModifier != wxString::npos ) - modifier = langFull.Mid(posModifier); - - size_t posEndLang = langFull.find_first_of(_T("@.")); - if ( posEndLang != wxString::npos ) - { - langFull.Truncate(posEndLang); - } - - // in addition to the format above, we also can have full language names - // in LANG env var - for example, SuSE is known to use LANG="german" - so - // check for this - - // do we have just the language (or sublang too)? - bool justLang = langFull.length() == LEN_LANG; - if ( justLang || - (langFull.length() == LEN_FULL && langFull[LEN_LANG] == wxT('_')) ) - { - // 0. Make sure the lang is according to latest ISO 639 - // (this is necessary because glibc uses iw and in instead - // of he and id respectively). - - // the language itself (second part is the dialect/sublang) - wxString langOrig = ExtractLang(langFull); - - wxString lang; - if ( langOrig == wxT("iw")) - lang = _T("he"); - else if (langOrig == wxT("in")) - lang = wxT("id"); - else if (langOrig == wxT("ji")) - lang = wxT("yi"); - else if (langOrig == wxT("no_NO")) - lang = wxT("nb_NO"); - else if (langOrig == wxT("no_NY")) - lang = wxT("nn_NO"); - else if (langOrig == wxT("no")) - lang = wxT("nb_NO"); - else - lang = langOrig; - - // did we change it? - if ( lang != langOrig ) - { - langFull = lang + ExtractNotLang(langFull); - } - - // 1. Try to find the language either as is: - // a) With modifier if set - if ( !modifier.empty() ) - { - wxString langFullWithModifier = langFull + modifier; - for ( i = 0; i < count; i++ ) - { - if ( ms_languagesDB->Item(i).CanonicalName == langFullWithModifier ) - break; - } - } - - // b) Without modifier - if ( modifier.empty() || i == count ) - { - for ( i = 0; i < count; i++ ) - { - if ( ms_languagesDB->Item(i).CanonicalName == langFull ) - break; - } - } - - // 2. If langFull is of the form xx_YY, try to find xx: - if ( i == count && !justLang ) - { - for ( i = 0; i < count; i++ ) - { - if ( ms_languagesDB->Item(i).CanonicalName == lang ) - { - break; - } - } - } - - // 3. If langFull is of the form xx, try to find any xx_YY record: - if ( i == count && justLang ) - { - for ( i = 0; i < count; i++ ) - { - if ( ExtractLang(ms_languagesDB->Item(i).CanonicalName) - == langFull ) - { - break; - } - } - } - } - else // not standard format - { - // try to find the name in verbose description - for ( i = 0; i < count; i++ ) - { - if (ms_languagesDB->Item(i).Description.CmpNoCase(langFull) == 0) - { - break; - } - } - } -#elif defined(__WXMAC__) - const wxChar * lc = NULL ; - long lang = GetScriptVariable( smSystemScript, smScriptLang) ; - switch( GetScriptManagerVariable( smRegionCode ) ) { - case verUS : - lc = wxT("en_US") ; - break ; - case verFrance : - lc = wxT("fr_FR") ; - break ; - case verBritain : - lc = wxT("en_GB") ; - break ; - case verGermany : - lc = wxT("de_DE") ; - break ; - case verItaly : - lc = wxT("it_IT") ; - break ; - case verNetherlands : - lc = wxT("nl_NL") ; - break ; - case verFlemish : - lc = wxT("nl_BE") ; - break ; - case verSweden : - lc = wxT("sv_SE" ); - break ; - case verSpain : - lc = wxT("es_ES" ); - break ; - case verDenmark : - lc = wxT("da_DK") ; - break ; - case verPortugal : - lc = wxT("pt_PT") ; - break ; - case verFrCanada: - lc = wxT("fr_CA") ; - break ; - case verNorway: - lc = wxT("nb_NO") ; - break ; - case verIsrael: - lc = wxT("iw_IL") ; - break ; - case verJapan: - lc = wxT("ja_JP") ; - break ; - case verAustralia: - lc = wxT("en_AU") ; - break ; - case verArabic: - lc = wxT("ar") ; - break ; - case verFinland: - lc = wxT("fi_FI") ; - break ; - case verFrSwiss: - lc = wxT("fr_CH") ; - break ; - case verGrSwiss: - lc = wxT("de_CH") ; - break ; - case verGreece: - lc = wxT("el_GR") ; - break ; - case verIceland: - lc = wxT("is_IS") ; - break ; - case verMalta: - lc = wxT("mt_MT") ; - break ; - case verCyprus: - // _CY is not part of wx, so we have to translate according to the system language - if ( lang == langGreek ) { - lc = wxT("el_GR") ; - } - else if ( lang == langTurkish ) { - lc = wxT("tr_TR") ; - } - break ; - case verTurkey: - lc = wxT("tr_TR") ; - break ; - case verYugoCroatian: - lc = wxT("hr_HR") ; - break ; - case verIndiaHindi: - lc = wxT("hi_IN") ; - break ; - case verPakistanUrdu: - lc = wxT("ur_PK") ; - break ; - case verTurkishModified: - lc = wxT("tr_TR") ; - break ; - case verItalianSwiss: - lc = wxT("it_CH") ; - break ; - case verInternational: - lc = wxT("en") ; - break ; - case verRomania: - lc = wxT("ro_RO") ; - break ; - case verGreecePoly: - lc = wxT("el_GR") ; - break ; - case verLithuania: - lc = wxT("lt_LT") ; - break ; - case verPoland: - lc = wxT("pl_PL") ; - break ; - case verMagyar : - case verHungary: - lc = wxT("hu_HU") ; - break ; - case verEstonia: - lc = wxT("et_EE") ; - break ; - case verLatvia: - lc = wxT("lv_LV") ; - break ; - case verSami: - lc = wxT("se_NO") ; - break ; - case verFaroeIsl: - lc = wxT("fo_FO") ; - break ; - case verIran: - lc = wxT("fa_IR") ; - break ; - case verRussia: - lc = wxT("ru_RU") ; - break ; - case verIreland: - lc = wxT("ga_IE") ; - break ; - case verKorea: - lc = wxT("ko_KR") ; - break ; - case verChina: - lc = wxT("zh_CN") ; - break ; - case verTaiwan: - lc = wxT("zh_TW") ; - break ; - case verThailand: - lc = wxT("th_TH") ; - break ; - case verCzech: - lc = wxT("cs_CZ") ; - break ; - case verSlovak: - lc = wxT("sk_SK") ; - break ; - case verBengali: - lc = wxT("bn") ; - break ; - case verByeloRussian: - lc = wxT("be_BY") ; - break ; - case verUkraine: - lc = wxT("uk_UA") ; - break ; - case verGreeceAlt: - lc = wxT("el_GR") ; - break ; - case verSerbian: - lc = wxT("sr_YU") ; - break ; - case verSlovenian: - lc = wxT("sl_SI") ; - break ; - case verMacedonian: - lc = wxT("mk_MK") ; - break ; - case verCroatia: - lc = wxT("hr_HR") ; - break ; - case verBrazil: - lc = wxT("pt_BR ") ; - break ; - case verBulgaria: - lc = wxT("bg_BG") ; - break ; - case verCatalonia: - lc = wxT("ca_ES") ; - break ; - case verScottishGaelic: - lc = wxT("gd") ; - break ; - case verManxGaelic: - lc = wxT("gv") ; - break ; - case verBreton: - lc = wxT("br") ; - break ; - case verNunavut: - lc = wxT("iu_CA") ; - break ; - case verWelsh: - lc = wxT("cy") ; - break ; - case verIrishGaelicScript: - lc = wxT("ga_IE") ; - break ; - case verEngCanada: - lc = wxT("en_CA") ; - break ; - case verBhutan: - lc = wxT("dz_BT") ; - break ; - case verArmenian: - lc = wxT("hy_AM") ; - break ; - case verGeorgian: - lc = wxT("ka_GE") ; - break ; - case verSpLatinAmerica: - lc = wxT("es_AR") ; - break ; - case verTonga: - lc = wxT("to_TO" ); - break ; - case verFrenchUniversal: - lc = wxT("fr_FR") ; - break ; - case verAustria: - lc = wxT("de_AT") ; - break ; - case verGujarati: - lc = wxT("gu_IN") ; - break ; - case verPunjabi: - lc = wxT("pa") ; - break ; - case verIndiaUrdu: - lc = wxT("ur_IN") ; - break ; - case verVietnam: - lc = wxT("vi_VN") ; - break ; - case verFrBelgium: - lc = wxT("fr_BE") ; - break ; - case verUzbek: - lc = wxT("uz_UZ") ; - break ; - case verSingapore: - lc = wxT("zh_SG") ; - break ; - case verNynorsk: - lc = wxT("nn_NO") ; - break ; - case verAfrikaans: - lc = wxT("af_ZA") ; - break ; - case verEsperanto: - lc = wxT("eo") ; - break ; - case verMarathi: - lc = wxT("mr_IN") ; - break ; - case verTibetan: - lc = wxT("bo") ; - break ; - case verNepal: - lc = wxT("ne_NP") ; - break ; - case verGreenland: - lc = wxT("kl_GL") ; - break ; - default : - break ; - } - if ( !lc ) - return wxLANGUAGE_UNKNOWN; - for ( i = 0; i < count; i++ ) - { - if ( ms_languagesDB->Item(i).CanonicalName == lc ) - { - break; - } - } - -#elif defined(__WIN32__) - LCID lcid = GetUserDefaultLCID(); - if ( lcid != 0 ) - { - wxUint32 lang = PRIMARYLANGID(LANGIDFROMLCID(lcid)); - wxUint32 sublang = SUBLANGID(LANGIDFROMLCID(lcid)); - - for ( i = 0; i < count; i++ ) - { - if (ms_languagesDB->Item(i).WinLang == lang && - ms_languagesDB->Item(i).WinSublang == sublang) - { - break; - } - } - } - //else: leave wxlang == wxLANGUAGE_UNKNOWN -#endif // Unix/Win32 - - if ( i < count ) - { - // we did find a matching entry, use it - return ms_languagesDB->Item(i).Language; - } - - // no info about this language in the database - return wxLANGUAGE_UNKNOWN; -} - -// ---------------------------------------------------------------------------- -// encoding stuff -// ---------------------------------------------------------------------------- - -// this is a bit strange as under Windows we get the encoding name using its -// numeric value and under Unix we do it the other way round, but this just -// reflects the way different systems provide the encoding info - -/* static */ -wxString wxLocale::GetSystemEncodingName() -{ - wxString encname; - -#if defined(__WIN32__) && !defined(__WXMICROWIN__) - // FIXME: what is the error return value for GetACP()? - UINT codepage = ::GetACP(); - encname.Printf(_T("windows-%u"), codepage); -#elif defined(__WXMAC__) - // default is just empty string, this resolves to the default system - // encoding later -#elif defined(__UNIX_LIKE__) - -#if defined(HAVE_LANGINFO_H) && defined(CODESET) - // GNU libc provides current character set this way (this conforms - // to Unix98) - char *oldLocale = strdup(setlocale(LC_CTYPE, NULL)); - setlocale(LC_CTYPE, ""); - const char *alang = nl_langinfo(CODESET); - setlocale(LC_CTYPE, oldLocale); - free(oldLocale); - - if ( alang ) - { - encname = wxString::FromAscii( alang ); - } - else // nl_langinfo() failed -#endif // HAVE_LANGINFO_H - { - // if we can't get at the character set directly, try to see if it's in - // the environment variables (in most cases this won't work, but I was - // out of ideas) - char *lang = getenv( "LC_ALL"); - char *dot = lang ? strchr(lang, '.') : (char *)NULL; - if (!dot) - { - lang = getenv( "LC_CTYPE" ); - if ( lang ) - dot = strchr(lang, '.' ); - } - if (!dot) - { - lang = getenv( "LANG"); - if ( lang ) - dot = strchr(lang, '.'); - } - - if ( dot ) - { - encname = wxString::FromAscii( dot+1 ); - } - } -#endif // Win32/Unix - - return encname; -} - -/* static */ -wxFontEncoding wxLocale::GetSystemEncoding() -{ -#if defined(__WIN32__) && !defined(__WXMICROWIN__) - UINT codepage = ::GetACP(); - - // wxWidgets only knows about CP1250-1257, 874, 932, 936, 949, 950 - if ( codepage >= 1250 && codepage <= 1257 ) - { - return (wxFontEncoding)(wxFONTENCODING_CP1250 + codepage - 1250); - } - - if ( codepage == 874 ) - { - return wxFONTENCODING_CP874; - } - - if ( codepage == 932 ) - { - return wxFONTENCODING_CP932; - } - - if ( codepage == 936 ) - { - return wxFONTENCODING_CP936; - } - - if ( codepage == 949 ) - { - return wxFONTENCODING_CP949; - } - - if ( codepage == 950 ) - { - return wxFONTENCODING_CP950; - } -#elif defined(__WXMAC__) - TextEncoding encoding = 0 ; -#if TARGET_CARBON - encoding = CFStringGetSystemEncoding() ; -#else - UpgradeScriptInfoToTextEncoding ( smSystemScript , kTextLanguageDontCare , kTextRegionDontCare , NULL , &encoding ) ; -#endif - return wxMacGetFontEncFromSystemEnc( encoding ) ; -#elif defined(__UNIX_LIKE__) && wxUSE_FONTMAP - const wxString encname = GetSystemEncodingName(); - if ( !encname.empty() ) - { - wxFontEncoding enc = wxFontMapperBase::GetEncodingFromName(encname); - - // on some modern Linux systems (RedHat 8) the default system locale - // is UTF8 -- but it isn't supported by wxGTK1 in ANSI build at all so - // don't even try to use it in this case -#if !wxUSE_UNICODE && \ - ((defined(__WXGTK__) && !defined(__WXGTK20__)) || defined(__WXMOTIF__)) - if ( enc == wxFONTENCODING_UTF8 ) - { - // the most similar supported encoding... - enc = wxFONTENCODING_ISO8859_1; - } -#endif // !wxUSE_UNICODE - - // GetEncodingFromName() returns wxFONTENCODING_DEFAULT for C locale - // (a.k.a. US-ASCII) which is arguably a bug but keep it like this for - // backwards compatibility and just take care to not return - // wxFONTENCODING_DEFAULT from here as this surely doesn't make sense - if ( enc == wxFONTENCODING_DEFAULT ) - { - // we don't have wxFONTENCODING_ASCII, so use the closest one - return wxFONTENCODING_ISO8859_1; - } - - if ( enc != wxFONTENCODING_MAX ) - { - return enc; - } - //else: return wxFONTENCODING_SYSTEM below - } -#endif // Win32/Unix - - return wxFONTENCODING_SYSTEM; -} - -/* static */ -void wxLocale::AddLanguage(const wxLanguageInfo& info) -{ - CreateLanguagesDB(); - ms_languagesDB->Add(info); -} - -/* static */ -const wxLanguageInfo *wxLocale::GetLanguageInfo(int lang) -{ - CreateLanguagesDB(); - - // calling GetLanguageInfo(wxLANGUAGE_DEFAULT) is a natural thing to do, so - // make it work - if ( lang == wxLANGUAGE_DEFAULT ) - lang = GetSystemLanguage(); - - const size_t count = ms_languagesDB->GetCount(); - for ( size_t i = 0; i < count; i++ ) - { - if ( ms_languagesDB->Item(i).Language == lang ) - { - // We need to create a temporary here in order to make this work with BCC in final build mode - wxLanguageInfo *ptr = &ms_languagesDB->Item(i); - return ptr; - } - } - - return NULL; -} - -/* static */ -wxString wxLocale::GetLanguageName(int lang) -{ - const wxLanguageInfo *info = GetLanguageInfo(lang); - if ( !info ) - return wxEmptyString; - else - return info->Description; -} - -/* static */ -const wxLanguageInfo *wxLocale::FindLanguageInfo(const wxString& locale) -{ - CreateLanguagesDB(); - - const wxLanguageInfo *infoRet = NULL; - - const size_t count = ms_languagesDB->GetCount(); - for ( size_t i = 0; i < count; i++ ) - { - const wxLanguageInfo *info = &ms_languagesDB->Item(i); - - if ( wxStricmp(locale, info->CanonicalName) == 0 || - wxStricmp(locale, info->Description) == 0 ) - { - // exact match, stop searching - infoRet = info; - break; - } - - if ( wxStricmp(locale, info->CanonicalName.BeforeFirst(_T('_'))) == 0 ) - { - // a match -- but maybe we'll find an exact one later, so continue - // looking - // - // OTOH, maybe we had already found a language match and in this - // case don't overwrite it becauce the entry for the default - // country always appears first in ms_languagesDB - if ( !infoRet ) - infoRet = info; - } - } - - return infoRet; -} - -wxString wxLocale::GetSysName() const -{ - // FIXME -#ifndef __WXWINCE__ - return wxSetlocale(LC_ALL, NULL); -#else - return wxEmptyString; -#endif -} - -// clean up -wxLocale::~wxLocale() -{ - // free memory - wxMsgCatalog *pTmpCat; - while ( m_pMsgCat != NULL ) { - pTmpCat = m_pMsgCat; - m_pMsgCat = m_pMsgCat->m_pNext; - delete pTmpCat; - } - - // restore old locale pointer - wxSetLocale(m_pOldLocale); - - // FIXME -#ifndef __WXWINCE__ - wxSetlocale(LC_ALL, m_pszOldLocale); -#endif - free((wxChar *)m_pszOldLocale); // const_cast -} - -// get the translation of given string in current locale -const wxChar *wxLocale::GetString(const wxChar *szOrigString, - const wxChar *szDomain) const -{ - return GetString(szOrigString, szOrigString, size_t(-1), szDomain); -} - -const wxChar *wxLocale::GetString(const wxChar *szOrigString, - const wxChar *szOrigString2, - size_t n, - const wxChar *szDomain) const -{ - if ( wxIsEmpty(szOrigString) ) - return wxEmptyString; - - const wxChar *pszTrans = NULL; - wxMsgCatalog *pMsgCat; - - if ( szDomain != NULL && szDomain[0] ) - { - pMsgCat = FindCatalog(szDomain); - - // does the catalog exist? - if ( pMsgCat != NULL ) - pszTrans = pMsgCat->GetString(szOrigString, n); - } - else - { - // search in all domains - for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) - { - pszTrans = pMsgCat->GetString(szOrigString, n); - if ( pszTrans != NULL ) // take the first found - break; - } - } - - if ( pszTrans == NULL ) - { -#ifdef __WXDEBUG__ - if ( !NoTransErr::Suppress() ) - { - NoTransErr noTransErr; - - wxLogTrace(TRACE_I18N, - _T("string \"%s\"[%ld] not found in %slocale '%s'."), - szOrigString, (long)n, - szDomain ? wxString::Format(_T("domain '%s' "), szDomain).c_str() - : _T(""), - m_strLocale.c_str()); - } -#endif // __WXDEBUG__ - - if (n == size_t(-1)) - return szOrigString; - else - return n == 1 ? szOrigString : szOrigString2; - } - - return pszTrans; -} - -wxString wxLocale::GetHeaderValue( const wxChar* szHeader, - const wxChar* szDomain ) const -{ - if ( wxIsEmpty(szHeader) ) - return wxEmptyString; - - wxChar const * pszTrans = NULL; - wxMsgCatalog *pMsgCat; - - if ( szDomain != NULL ) - { - pMsgCat = FindCatalog(szDomain); - - // does the catalog exist? - if ( pMsgCat == NULL ) - return wxEmptyString; - - pszTrans = pMsgCat->GetString(wxEmptyString, (size_t)-1); - } - else - { - // search in all domains - for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) - { - pszTrans = pMsgCat->GetString(wxEmptyString, (size_t)-1); - if ( pszTrans != NULL ) // take the first found - break; - } - } - - if ( wxIsEmpty(pszTrans) ) - return wxEmptyString; - - wxChar const * pszFound = wxStrstr(pszTrans, szHeader); - if ( pszFound == NULL ) - return wxEmptyString; - - pszFound += wxStrlen(szHeader) + 2 /* ': ' */; - - // Every header is separated by \n - - wxChar const * pszEndLine = wxStrchr(pszFound, wxT('\n')); - if ( pszEndLine == NULL ) pszEndLine = pszFound + wxStrlen(pszFound); - - - // wxString( wxChar*, length); - wxString retVal( pszFound, pszEndLine - pszFound ); - - return retVal; -} - - -// find catalog by name in a linked list, return NULL if !found -wxMsgCatalog *wxLocale::FindCatalog(const wxChar *szDomain) const -{ - // linear search in the linked list - wxMsgCatalog *pMsgCat; - for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) - { - if ( wxStricmp(pMsgCat->GetName(), szDomain) == 0 ) - return pMsgCat; - } - - return NULL; -} - -// check if the given locale is provided by OS and C run time -/* static */ -bool wxLocale::IsAvailable(int lang) -{ - const wxLanguageInfo *info = wxLocale::GetLanguageInfo(lang); - wxCHECK_MSG( info, false, _T("invalid language") ); - -#if defined(__WIN32__) - if ( !info->WinLang ) - return false; - - if ( !::IsValidLocale - ( - MAKELCID(MAKELANGID(info->WinLang, info->WinSublang), - SORT_DEFAULT), - LCID_INSTALLED - ) ) - return false; - -#elif defined(__UNIX__) - - // Test if setting the locale works, then set it back. - wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, wxEmptyString); - wxMB2WXbuf tmp = wxSetlocaleTryUTF(LC_ALL, info->CanonicalName); - if ( !tmp ) - { - // Some C libraries don't like xx_YY form and require xx only - tmp = wxSetlocaleTryUTF(LC_ALL, info->CanonicalName.Left(2)); - if ( !tmp ) - return false; - } - // restore the original locale - wxSetlocale(LC_ALL, oldLocale); -#endif - - return true; -} - -// check if the given catalog is loaded -bool wxLocale::IsLoaded(const wxChar *szDomain) const -{ - return FindCatalog(szDomain) != NULL; -} - -// add a catalog to our linked list -bool wxLocale::AddCatalog(const wxChar *szDomain) -{ - return AddCatalog(szDomain, wxLANGUAGE_ENGLISH_US, NULL); -} - -// add a catalog to our linked list -bool wxLocale::AddCatalog(const wxChar *szDomain, - wxLanguage msgIdLanguage, - const wxChar *msgIdCharset) - -{ - wxMsgCatalog *pMsgCat = new wxMsgCatalog; - - if ( pMsgCat->Load(m_strShort, szDomain, msgIdCharset, m_bConvertEncoding) ) { - // add it to the head of the list so that in GetString it will - // be searched before the catalogs added earlier - pMsgCat->m_pNext = m_pMsgCat; - m_pMsgCat = pMsgCat; - - return true; - } - else { - // don't add it because it couldn't be loaded anyway - delete pMsgCat; - - // It is OK to not load catalog if the msgid language and m_language match, - // in which case we can directly display the texts embedded in program's - // source code: - if (m_language == msgIdLanguage) - return true; - - // If there's no exact match, we may still get partial match where the - // (basic) language is same, but the country differs. For example, it's - // permitted to use en_US strings from sources even if m_language is en_GB: - const wxLanguageInfo *msgIdLangInfo = GetLanguageInfo(msgIdLanguage); - if ( msgIdLangInfo && - msgIdLangInfo->CanonicalName.Mid(0, 2) == m_strShort.Mid(0, 2) ) - { - return true; - } - - return false; - } -} - -// ---------------------------------------------------------------------------- -// accessors for locale-dependent data -// ---------------------------------------------------------------------------- - -#ifdef __WXMSW__ - -/* static */ -wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) -{ - wxUint32 lcid = LOCALE_USER_DEFAULT; - - if (wxGetLocale()) - { - const wxLanguageInfo *info = GetLanguageInfo(wxGetLocale()->GetLanguage()); - if (info) - { ; - lcid = MAKELCID(MAKELANGID(info->WinLang, info->WinSublang), - SORT_DEFAULT); - } - } - - wxString str; - wxChar buffer[256]; - size_t count; - buffer[0] = wxT('\0'); - switch (index) - { - case wxLOCALE_DECIMAL_POINT: - count = ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, buffer, 256); - if (!count) - str << wxT("."); - else - str << buffer; - break; -#if 0 - case wxSYS_LIST_SEPARATOR: - count = ::GetLocaleInfo(lcid, LOCALE_SLIST, buffer, 256); - if (!count) - str << wxT(","); - else - str << buffer; - break; - case wxSYS_LEADING_ZERO: // 0 means no leading zero, 1 means leading zero - count = ::GetLocaleInfo(lcid, LOCALE_ILZERO, buffer, 256); - if (!count) - str << wxT("0"); - else - str << buffer; - break; -#endif - default: - wxFAIL_MSG(wxT("Unknown System String !")); - } - return str; -} - -#elif defined(__DARWIN__) - -/* static */ -wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) -{ - CFLocaleRef userLocaleRefRaw; - if ( wxGetLocale() ) - { - userLocaleRefRaw = CFLocaleCreate - ( - kCFAllocatorDefault, - wxMacCFStringHolder(wxGetLocale()->GetCanonicalName()) - ); - } - else // no current locale, use the default one - { - userLocaleRefRaw = CFLocaleCopyCurrent(); - } - - wxCFRef userLocaleRef(userLocaleRefRaw); - - CFTypeRef cfstr; - switch ( index ) - { - case wxLOCALE_THOUSANDS_SEP: - cfstr = CFLocaleGetValue(userLocaleRef, kCFLocaleGroupingSeparator); - break; - - case wxLOCALE_DECIMAL_POINT: - cfstr = CFLocaleGetValue(userLocaleRef, kCFLocaleDecimalSeparator); - break; - - default: - wxFAIL_MSG( _T("Unknown locale info") ); - } - - wxMacCFStringHolder - str(CFStringCreateCopy(NULL, static_cast(cfstr))); - return str.AsString(); -} - -#else // !__WXMSW__ && !__DARWIN__ - -/* static */ -wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) -{ - struct lconv *locale_info = localeconv(); - switch (cat) - { - case wxLOCALE_CAT_NUMBER: - switch (index) - { - case wxLOCALE_THOUSANDS_SEP: - return wxString(locale_info->thousands_sep, - *wxConvCurrent); - case wxLOCALE_DECIMAL_POINT: - return wxString(locale_info->decimal_point, - *wxConvCurrent); - default: - return wxEmptyString; - } - case wxLOCALE_CAT_MONEY: - switch (index) - { - case wxLOCALE_THOUSANDS_SEP: - return wxString(locale_info->mon_thousands_sep, - *wxConvCurrent); - case wxLOCALE_DECIMAL_POINT: - return wxString(locale_info->mon_decimal_point, - *wxConvCurrent); - default: - return wxEmptyString; - } - default: - return wxEmptyString; - } -} - -#endif // __WXMSW__/!__WXMSW__ - -// ---------------------------------------------------------------------------- -// global functions and variables -// ---------------------------------------------------------------------------- - -// retrieve/change current locale -// ------------------------------ - -// the current locale object -static wxLocale *g_pLocale = NULL; - -wxLocale *wxGetLocale() -{ - return g_pLocale; -} - -wxLocale *wxSetLocale(wxLocale *pLocale) -{ - wxLocale *pOld = g_pLocale; - g_pLocale = pLocale; - return pOld; -} - - - -// ---------------------------------------------------------------------------- -// wxLocale module (for lazy destruction of languagesDB) -// ---------------------------------------------------------------------------- - -class wxLocaleModule: public wxModule -{ - DECLARE_DYNAMIC_CLASS(wxLocaleModule) - public: - wxLocaleModule() {} - bool OnInit() { return true; } - void OnExit() { wxLocale::DestroyLanguagesDB(); } -}; - -IMPLEMENT_DYNAMIC_CLASS(wxLocaleModule, wxModule) - - - -// ---------------------------------------------------------------------------- -// default languages table & initialization -// ---------------------------------------------------------------------------- - - - -// --- --- --- generated code begins here --- --- --- - -// This table is generated by misc/languages/genlang.py -// When making changes, please put them into misc/languages/langtabl.txt - -#if !defined(__WIN32__) || defined(__WXMICROWIN__) - -#define SETWINLANG(info,lang,sublang) - -#else - -#define SETWINLANG(info,lang,sublang) \ - info.WinLang = lang, info.WinSublang = sublang; - -#ifndef LANG_AFRIKAANS -#define LANG_AFRIKAANS (0) -#endif -#ifndef LANG_ALBANIAN -#define LANG_ALBANIAN (0) -#endif -#ifndef LANG_ARABIC -#define LANG_ARABIC (0) -#endif -#ifndef LANG_ARMENIAN -#define LANG_ARMENIAN (0) -#endif -#ifndef LANG_ASSAMESE -#define LANG_ASSAMESE (0) -#endif -#ifndef LANG_AZERI -#define LANG_AZERI (0) -#endif -#ifndef LANG_BASQUE -#define LANG_BASQUE (0) -#endif -#ifndef LANG_BELARUSIAN -#define LANG_BELARUSIAN (0) -#endif -#ifndef LANG_BENGALI -#define LANG_BENGALI (0) -#endif -#ifndef LANG_BULGARIAN -#define LANG_BULGARIAN (0) -#endif -#ifndef LANG_CATALAN -#define LANG_CATALAN (0) -#endif -#ifndef LANG_CHINESE -#define LANG_CHINESE (0) -#endif -#ifndef LANG_CROATIAN -#define LANG_CROATIAN (0) -#endif -#ifndef LANG_CZECH -#define LANG_CZECH (0) -#endif -#ifndef LANG_DANISH -#define LANG_DANISH (0) -#endif -#ifndef LANG_DUTCH -#define LANG_DUTCH (0) -#endif -#ifndef LANG_ENGLISH -#define LANG_ENGLISH (0) -#endif -#ifndef LANG_ESTONIAN -#define LANG_ESTONIAN (0) -#endif -#ifndef LANG_FAEROESE -#define LANG_FAEROESE (0) -#endif -#ifndef LANG_FARSI -#define LANG_FARSI (0) -#endif -#ifndef LANG_FINNISH -#define LANG_FINNISH (0) -#endif -#ifndef LANG_FRENCH -#define LANG_FRENCH (0) -#endif -#ifndef LANG_GEORGIAN -#define LANG_GEORGIAN (0) -#endif -#ifndef LANG_GERMAN -#define LANG_GERMAN (0) -#endif -#ifndef LANG_GREEK -#define LANG_GREEK (0) -#endif -#ifndef LANG_GUJARATI -#define LANG_GUJARATI (0) -#endif -#ifndef LANG_HEBREW -#define LANG_HEBREW (0) -#endif -#ifndef LANG_HINDI -#define LANG_HINDI (0) -#endif -#ifndef LANG_HUNGARIAN -#define LANG_HUNGARIAN (0) -#endif -#ifndef LANG_ICELANDIC -#define LANG_ICELANDIC (0) -#endif -#ifndef LANG_INDONESIAN -#define LANG_INDONESIAN (0) -#endif -#ifndef LANG_ITALIAN -#define LANG_ITALIAN (0) -#endif -#ifndef LANG_JAPANESE -#define LANG_JAPANESE (0) -#endif -#ifndef LANG_KANNADA -#define LANG_KANNADA (0) -#endif -#ifndef LANG_KASHMIRI -#define LANG_KASHMIRI (0) -#endif -#ifndef LANG_KAZAK -#define LANG_KAZAK (0) -#endif -#ifndef LANG_KONKANI -#define LANG_KONKANI (0) -#endif -#ifndef LANG_KOREAN -#define LANG_KOREAN (0) -#endif -#ifndef LANG_LATVIAN -#define LANG_LATVIAN (0) -#endif -#ifndef LANG_LITHUANIAN -#define LANG_LITHUANIAN (0) -#endif -#ifndef LANG_MACEDONIAN -#define LANG_MACEDONIAN (0) -#endif -#ifndef LANG_MALAY -#define LANG_MALAY (0) -#endif -#ifndef LANG_MALAYALAM -#define LANG_MALAYALAM (0) -#endif -#ifndef LANG_MANIPURI -#define LANG_MANIPURI (0) -#endif -#ifndef LANG_MARATHI -#define LANG_MARATHI (0) -#endif -#ifndef LANG_NEPALI -#define LANG_NEPALI (0) -#endif -#ifndef LANG_NORWEGIAN -#define LANG_NORWEGIAN (0) -#endif -#ifndef LANG_ORIYA -#define LANG_ORIYA (0) -#endif -#ifndef LANG_POLISH -#define LANG_POLISH (0) -#endif -#ifndef LANG_PORTUGUESE -#define LANG_PORTUGUESE (0) -#endif -#ifndef LANG_PUNJABI -#define LANG_PUNJABI (0) -#endif -#ifndef LANG_ROMANIAN -#define LANG_ROMANIAN (0) -#endif -#ifndef LANG_RUSSIAN -#define LANG_RUSSIAN (0) -#endif -#ifndef LANG_SAMI -#define LANG_SAMI (0) -#endif -#ifndef LANG_SANSKRIT -#define LANG_SANSKRIT (0) -#endif -#ifndef LANG_SERBIAN -#define LANG_SERBIAN (0) -#endif -#ifndef LANG_SINDHI -#define LANG_SINDHI (0) -#endif -#ifndef LANG_SLOVAK -#define LANG_SLOVAK (0) -#endif -#ifndef LANG_SLOVENIAN -#define LANG_SLOVENIAN (0) -#endif -#ifndef LANG_SPANISH -#define LANG_SPANISH (0) -#endif -#ifndef LANG_SWAHILI -#define LANG_SWAHILI (0) -#endif -#ifndef LANG_SWEDISH -#define LANG_SWEDISH (0) -#endif -#ifndef LANG_TAMIL -#define LANG_TAMIL (0) -#endif -#ifndef LANG_TATAR -#define LANG_TATAR (0) -#endif -#ifndef LANG_TELUGU -#define LANG_TELUGU (0) -#endif -#ifndef LANG_THAI -#define LANG_THAI (0) -#endif -#ifndef LANG_TURKISH -#define LANG_TURKISH (0) -#endif -#ifndef LANG_UKRAINIAN -#define LANG_UKRAINIAN (0) -#endif -#ifndef LANG_URDU -#define LANG_URDU (0) -#endif -#ifndef LANG_UZBEK -#define LANG_UZBEK (0) -#endif -#ifndef LANG_VALENCIAN -#define LANG_VALENCIAN (0) -#endif -#ifndef LANG_VIETNAMESE -#define LANG_VIETNAMESE (0) -#endif -#ifndef SUBLANG_ARABIC_ALGERIA -#define SUBLANG_ARABIC_ALGERIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_BAHRAIN -#define SUBLANG_ARABIC_BAHRAIN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_EGYPT -#define SUBLANG_ARABIC_EGYPT SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_IRAQ -#define SUBLANG_ARABIC_IRAQ SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_JORDAN -#define SUBLANG_ARABIC_JORDAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_KUWAIT -#define SUBLANG_ARABIC_KUWAIT SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_LEBANON -#define SUBLANG_ARABIC_LEBANON SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_LIBYA -#define SUBLANG_ARABIC_LIBYA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_MOROCCO -#define SUBLANG_ARABIC_MOROCCO SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_OMAN -#define SUBLANG_ARABIC_OMAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_QATAR -#define SUBLANG_ARABIC_QATAR SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_SAUDI_ARABIA -#define SUBLANG_ARABIC_SAUDI_ARABIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_SYRIA -#define SUBLANG_ARABIC_SYRIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_TUNISIA -#define SUBLANG_ARABIC_TUNISIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_UAE -#define SUBLANG_ARABIC_UAE SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ARABIC_YEMEN -#define SUBLANG_ARABIC_YEMEN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_AZERI_CYRILLIC -#define SUBLANG_AZERI_CYRILLIC SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_AZERI_LATIN -#define SUBLANG_AZERI_LATIN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_CHINESE_SIMPLIFIED -#define SUBLANG_CHINESE_SIMPLIFIED SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_CHINESE_TRADITIONAL -#define SUBLANG_CHINESE_TRADITIONAL SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_CHINESE_HONGKONG -#define SUBLANG_CHINESE_HONGKONG SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_CHINESE_MACAU -#define SUBLANG_CHINESE_MACAU SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_CHINESE_SINGAPORE -#define SUBLANG_CHINESE_SINGAPORE SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_DUTCH -#define SUBLANG_DUTCH SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_DUTCH_BELGIAN -#define SUBLANG_DUTCH_BELGIAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_UK -#define SUBLANG_ENGLISH_UK SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_US -#define SUBLANG_ENGLISH_US SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_AUS -#define SUBLANG_ENGLISH_AUS SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_BELIZE -#define SUBLANG_ENGLISH_BELIZE SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_CAN -#define SUBLANG_ENGLISH_CAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_CARIBBEAN -#define SUBLANG_ENGLISH_CARIBBEAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_EIRE -#define SUBLANG_ENGLISH_EIRE SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_JAMAICA -#define SUBLANG_ENGLISH_JAMAICA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_NZ -#define SUBLANG_ENGLISH_NZ SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_PHILIPPINES -#define SUBLANG_ENGLISH_PHILIPPINES SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_SOUTH_AFRICA -#define SUBLANG_ENGLISH_SOUTH_AFRICA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_TRINIDAD -#define SUBLANG_ENGLISH_TRINIDAD SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ENGLISH_ZIMBABWE -#define SUBLANG_ENGLISH_ZIMBABWE SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_FRENCH -#define SUBLANG_FRENCH SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_FRENCH_BELGIAN -#define SUBLANG_FRENCH_BELGIAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_FRENCH_CANADIAN -#define SUBLANG_FRENCH_CANADIAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_FRENCH_LUXEMBOURG -#define SUBLANG_FRENCH_LUXEMBOURG SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_FRENCH_MONACO -#define SUBLANG_FRENCH_MONACO SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_FRENCH_SWISS -#define SUBLANG_FRENCH_SWISS SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_GERMAN -#define SUBLANG_GERMAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_GERMAN_AUSTRIAN -#define SUBLANG_GERMAN_AUSTRIAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_GERMAN_LIECHTENSTEIN -#define SUBLANG_GERMAN_LIECHTENSTEIN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_GERMAN_LUXEMBOURG -#define SUBLANG_GERMAN_LUXEMBOURG SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_GERMAN_SWISS -#define SUBLANG_GERMAN_SWISS SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ITALIAN -#define SUBLANG_ITALIAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_ITALIAN_SWISS -#define SUBLANG_ITALIAN_SWISS SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_KASHMIRI_INDIA -#define SUBLANG_KASHMIRI_INDIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_KOREAN -#define SUBLANG_KOREAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_LITHUANIAN -#define SUBLANG_LITHUANIAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM -#define SUBLANG_MALAY_BRUNEI_DARUSSALAM SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_MALAY_MALAYSIA -#define SUBLANG_MALAY_MALAYSIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_NEPALI_INDIA -#define SUBLANG_NEPALI_INDIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_NORWEGIAN_BOKMAL -#define SUBLANG_NORWEGIAN_BOKMAL SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_NORWEGIAN_NYNORSK -#define SUBLANG_NORWEGIAN_NYNORSK SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_PORTUGUESE -#define SUBLANG_PORTUGUESE SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_PORTUGUESE_BRAZILIAN -#define SUBLANG_PORTUGUESE_BRAZILIAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SERBIAN_CYRILLIC -#define SUBLANG_SERBIAN_CYRILLIC SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SERBIAN_LATIN -#define SUBLANG_SERBIAN_LATIN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH -#define SUBLANG_SPANISH SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_ARGENTINA -#define SUBLANG_SPANISH_ARGENTINA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_BOLIVIA -#define SUBLANG_SPANISH_BOLIVIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_CHILE -#define SUBLANG_SPANISH_CHILE SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_COLOMBIA -#define SUBLANG_SPANISH_COLOMBIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_COSTA_RICA -#define SUBLANG_SPANISH_COSTA_RICA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC -#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_ECUADOR -#define SUBLANG_SPANISH_ECUADOR SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_EL_SALVADOR -#define SUBLANG_SPANISH_EL_SALVADOR SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_GUATEMALA -#define SUBLANG_SPANISH_GUATEMALA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_HONDURAS -#define SUBLANG_SPANISH_HONDURAS SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_MEXICAN -#define SUBLANG_SPANISH_MEXICAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_MODERN -#define SUBLANG_SPANISH_MODERN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_NICARAGUA -#define SUBLANG_SPANISH_NICARAGUA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_PANAMA -#define SUBLANG_SPANISH_PANAMA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_PARAGUAY -#define SUBLANG_SPANISH_PARAGUAY SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_PERU -#define SUBLANG_SPANISH_PERU SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_PUERTO_RICO -#define SUBLANG_SPANISH_PUERTO_RICO SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_URUGUAY -#define SUBLANG_SPANISH_URUGUAY SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SPANISH_VENEZUELA -#define SUBLANG_SPANISH_VENEZUELA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SWEDISH -#define SUBLANG_SWEDISH SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_SWEDISH_FINLAND -#define SUBLANG_SWEDISH_FINLAND SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_URDU_INDIA -#define SUBLANG_URDU_INDIA SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_URDU_PAKISTAN -#define SUBLANG_URDU_PAKISTAN SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_UZBEK_CYRILLIC -#define SUBLANG_UZBEK_CYRILLIC SUBLANG_DEFAULT -#endif -#ifndef SUBLANG_UZBEK_LATIN -#define SUBLANG_UZBEK_LATIN SUBLANG_DEFAULT -#endif - - -#endif // __WIN32__ - -#define LNG(wxlang, canonical, winlang, winsublang, layout, desc) \ - info.Language = wxlang; \ - info.CanonicalName = wxT(canonical); \ - info.LayoutDirection = layout; \ - info.Description = wxT(desc); \ - SETWINLANG(info, winlang, winsublang) \ - AddLanguage(info); - -void wxLocale::InitLanguagesDB() -{ - wxLanguageInfo info; - wxStringTokenizer tkn; - - LNG(wxLANGUAGE_ABKHAZIAN, "ab" , 0 , 0 , wxLayout_LeftToRight, "Abkhazian") - LNG(wxLANGUAGE_AFAR, "aa" , 0 , 0 , wxLayout_LeftToRight, "Afar") - LNG(wxLANGUAGE_AFRIKAANS, "af_ZA", LANG_AFRIKAANS , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Afrikaans") - LNG(wxLANGUAGE_ALBANIAN, "sq_AL", LANG_ALBANIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Albanian") - LNG(wxLANGUAGE_AMHARIC, "am" , 0 , 0 , wxLayout_LeftToRight, "Amharic") - LNG(wxLANGUAGE_ARABIC, "ar" , LANG_ARABIC , SUBLANG_DEFAULT , wxLayout_RightToLeft, "Arabic") - LNG(wxLANGUAGE_ARABIC_ALGERIA, "ar_DZ", LANG_ARABIC , SUBLANG_ARABIC_ALGERIA , wxLayout_RightToLeft, "Arabic (Algeria)") - LNG(wxLANGUAGE_ARABIC_BAHRAIN, "ar_BH", LANG_ARABIC , SUBLANG_ARABIC_BAHRAIN , wxLayout_RightToLeft, "Arabic (Bahrain)") - LNG(wxLANGUAGE_ARABIC_EGYPT, "ar_EG", LANG_ARABIC , SUBLANG_ARABIC_EGYPT , wxLayout_RightToLeft, "Arabic (Egypt)") - LNG(wxLANGUAGE_ARABIC_IRAQ, "ar_IQ", LANG_ARABIC , SUBLANG_ARABIC_IRAQ , wxLayout_RightToLeft, "Arabic (Iraq)") - LNG(wxLANGUAGE_ARABIC_JORDAN, "ar_JO", LANG_ARABIC , SUBLANG_ARABIC_JORDAN , wxLayout_RightToLeft, "Arabic (Jordan)") - LNG(wxLANGUAGE_ARABIC_KUWAIT, "ar_KW", LANG_ARABIC , SUBLANG_ARABIC_KUWAIT , wxLayout_RightToLeft, "Arabic (Kuwait)") - LNG(wxLANGUAGE_ARABIC_LEBANON, "ar_LB", LANG_ARABIC , SUBLANG_ARABIC_LEBANON , wxLayout_RightToLeft, "Arabic (Lebanon)") - LNG(wxLANGUAGE_ARABIC_LIBYA, "ar_LY", LANG_ARABIC , SUBLANG_ARABIC_LIBYA , wxLayout_RightToLeft, "Arabic (Libya)") - LNG(wxLANGUAGE_ARABIC_MOROCCO, "ar_MA", LANG_ARABIC , SUBLANG_ARABIC_MOROCCO , wxLayout_RightToLeft, "Arabic (Morocco)") - LNG(wxLANGUAGE_ARABIC_OMAN, "ar_OM", LANG_ARABIC , SUBLANG_ARABIC_OMAN , wxLayout_RightToLeft, "Arabic (Oman)") - LNG(wxLANGUAGE_ARABIC_QATAR, "ar_QA", LANG_ARABIC , SUBLANG_ARABIC_QATAR , wxLayout_RightToLeft, "Arabic (Qatar)") - LNG(wxLANGUAGE_ARABIC_SAUDI_ARABIA, "ar_SA", LANG_ARABIC , SUBLANG_ARABIC_SAUDI_ARABIA , wxLayout_RightToLeft, "Arabic (Saudi Arabia)") - LNG(wxLANGUAGE_ARABIC_SUDAN, "ar_SD", 0 , 0 , wxLayout_RightToLeft, "Arabic (Sudan)") - LNG(wxLANGUAGE_ARABIC_SYRIA, "ar_SY", LANG_ARABIC , SUBLANG_ARABIC_SYRIA , wxLayout_RightToLeft, "Arabic (Syria)") - LNG(wxLANGUAGE_ARABIC_TUNISIA, "ar_TN", LANG_ARABIC , SUBLANG_ARABIC_TUNISIA , wxLayout_RightToLeft, "Arabic (Tunisia)") - LNG(wxLANGUAGE_ARABIC_UAE, "ar_AE", LANG_ARABIC , SUBLANG_ARABIC_UAE , wxLayout_RightToLeft, "Arabic (Uae)") - LNG(wxLANGUAGE_ARABIC_YEMEN, "ar_YE", LANG_ARABIC , SUBLANG_ARABIC_YEMEN , wxLayout_RightToLeft, "Arabic (Yemen)") - LNG(wxLANGUAGE_ARMENIAN, "hy" , LANG_ARMENIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Armenian") - LNG(wxLANGUAGE_ASSAMESE, "as" , LANG_ASSAMESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Assamese") - LNG(wxLANGUAGE_AYMARA, "ay" , 0 , 0 , wxLayout_LeftToRight, "Aymara") - LNG(wxLANGUAGE_AZERI, "az" , LANG_AZERI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Azeri") - LNG(wxLANGUAGE_AZERI_CYRILLIC, "az" , LANG_AZERI , SUBLANG_AZERI_CYRILLIC , wxLayout_LeftToRight, "Azeri (Cyrillic)") - LNG(wxLANGUAGE_AZERI_LATIN, "az" , LANG_AZERI , SUBLANG_AZERI_LATIN , wxLayout_LeftToRight, "Azeri (Latin)") - LNG(wxLANGUAGE_BASHKIR, "ba" , 0 , 0 , wxLayout_LeftToRight, "Bashkir") - LNG(wxLANGUAGE_BASQUE, "eu_ES", LANG_BASQUE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Basque") - LNG(wxLANGUAGE_BELARUSIAN, "be_BY", LANG_BELARUSIAN, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Belarusian") - LNG(wxLANGUAGE_BENGALI, "bn" , LANG_BENGALI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Bengali") - LNG(wxLANGUAGE_BHUTANI, "dz" , 0 , 0 , wxLayout_LeftToRight, "Bhutani") - LNG(wxLANGUAGE_BIHARI, "bh" , 0 , 0 , wxLayout_LeftToRight, "Bihari") - LNG(wxLANGUAGE_BISLAMA, "bi" , 0 , 0 , wxLayout_LeftToRight, "Bislama") - LNG(wxLANGUAGE_BRETON, "br" , 0 , 0 , wxLayout_LeftToRight, "Breton") - LNG(wxLANGUAGE_BULGARIAN, "bg_BG", LANG_BULGARIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Bulgarian") - LNG(wxLANGUAGE_BURMESE, "my" , 0 , 0 , wxLayout_LeftToRight, "Burmese") - LNG(wxLANGUAGE_CAMBODIAN, "km" , 0 , 0 , wxLayout_LeftToRight, "Cambodian") - LNG(wxLANGUAGE_CATALAN, "ca_ES", LANG_CATALAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Catalan") - LNG(wxLANGUAGE_CHINESE, "zh_TW", LANG_CHINESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Chinese") - LNG(wxLANGUAGE_CHINESE_SIMPLIFIED, "zh_CN", LANG_CHINESE , SUBLANG_CHINESE_SIMPLIFIED , wxLayout_LeftToRight, "Chinese (Simplified)") - LNG(wxLANGUAGE_CHINESE_TRADITIONAL, "zh_TW", LANG_CHINESE , SUBLANG_CHINESE_TRADITIONAL , wxLayout_LeftToRight, "Chinese (Traditional)") - LNG(wxLANGUAGE_CHINESE_HONGKONG, "zh_HK", LANG_CHINESE , SUBLANG_CHINESE_HONGKONG , wxLayout_LeftToRight, "Chinese (Hongkong)") - LNG(wxLANGUAGE_CHINESE_MACAU, "zh_MO", LANG_CHINESE , SUBLANG_CHINESE_MACAU , wxLayout_LeftToRight, "Chinese (Macau)") - LNG(wxLANGUAGE_CHINESE_SINGAPORE, "zh_SG", LANG_CHINESE , SUBLANG_CHINESE_SINGAPORE , wxLayout_LeftToRight, "Chinese (Singapore)") - LNG(wxLANGUAGE_CHINESE_TAIWAN, "zh_TW", LANG_CHINESE , SUBLANG_CHINESE_TRADITIONAL , wxLayout_LeftToRight, "Chinese (Taiwan)") - LNG(wxLANGUAGE_CORSICAN, "co" , 0 , 0 , wxLayout_LeftToRight, "Corsican") - LNG(wxLANGUAGE_CROATIAN, "hr_HR", LANG_CROATIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Croatian") - LNG(wxLANGUAGE_CZECH, "cs_CZ", LANG_CZECH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Czech") - LNG(wxLANGUAGE_DANISH, "da_DK", LANG_DANISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Danish") - LNG(wxLANGUAGE_DUTCH, "nl_NL", LANG_DUTCH , SUBLANG_DUTCH , wxLayout_LeftToRight, "Dutch") - LNG(wxLANGUAGE_DUTCH_BELGIAN, "nl_BE", LANG_DUTCH , SUBLANG_DUTCH_BELGIAN , wxLayout_LeftToRight, "Dutch (Belgian)") - LNG(wxLANGUAGE_ENGLISH, "en_GB", LANG_ENGLISH , SUBLANG_ENGLISH_UK , wxLayout_LeftToRight, "English") - LNG(wxLANGUAGE_ENGLISH_UK, "en_GB", LANG_ENGLISH , SUBLANG_ENGLISH_UK , wxLayout_LeftToRight, "English (U.K.)") - LNG(wxLANGUAGE_ENGLISH_US, "en_US", LANG_ENGLISH , SUBLANG_ENGLISH_US , wxLayout_LeftToRight, "English (U.S.)") - LNG(wxLANGUAGE_ENGLISH_AUSTRALIA, "en_AU", LANG_ENGLISH , SUBLANG_ENGLISH_AUS , wxLayout_LeftToRight, "English (Australia)") - LNG(wxLANGUAGE_ENGLISH_BELIZE, "en_BZ", LANG_ENGLISH , SUBLANG_ENGLISH_BELIZE , wxLayout_LeftToRight, "English (Belize)") - LNG(wxLANGUAGE_ENGLISH_BOTSWANA, "en_BW", 0 , 0 , wxLayout_LeftToRight, "English (Botswana)") - LNG(wxLANGUAGE_ENGLISH_CANADA, "en_CA", LANG_ENGLISH , SUBLANG_ENGLISH_CAN , wxLayout_LeftToRight, "English (Canada)") - LNG(wxLANGUAGE_ENGLISH_CARIBBEAN, "en_CB", LANG_ENGLISH , SUBLANG_ENGLISH_CARIBBEAN , wxLayout_LeftToRight, "English (Caribbean)") - LNG(wxLANGUAGE_ENGLISH_DENMARK, "en_DK", 0 , 0 , wxLayout_LeftToRight, "English (Denmark)") - LNG(wxLANGUAGE_ENGLISH_EIRE, "en_IE", LANG_ENGLISH , SUBLANG_ENGLISH_EIRE , wxLayout_LeftToRight, "English (Eire)") - LNG(wxLANGUAGE_ENGLISH_JAMAICA, "en_JM", LANG_ENGLISH , SUBLANG_ENGLISH_JAMAICA , wxLayout_LeftToRight, "English (Jamaica)") - LNG(wxLANGUAGE_ENGLISH_NEW_ZEALAND, "en_NZ", LANG_ENGLISH , SUBLANG_ENGLISH_NZ , wxLayout_LeftToRight, "English (New Zealand)") - LNG(wxLANGUAGE_ENGLISH_PHILIPPINES, "en_PH", LANG_ENGLISH , SUBLANG_ENGLISH_PHILIPPINES , wxLayout_LeftToRight, "English (Philippines)") - LNG(wxLANGUAGE_ENGLISH_SOUTH_AFRICA, "en_ZA", LANG_ENGLISH , SUBLANG_ENGLISH_SOUTH_AFRICA , wxLayout_LeftToRight, "English (South Africa)") - LNG(wxLANGUAGE_ENGLISH_TRINIDAD, "en_TT", LANG_ENGLISH , SUBLANG_ENGLISH_TRINIDAD , wxLayout_LeftToRight, "English (Trinidad)") - LNG(wxLANGUAGE_ENGLISH_ZIMBABWE, "en_ZW", LANG_ENGLISH , SUBLANG_ENGLISH_ZIMBABWE , wxLayout_LeftToRight, "English (Zimbabwe)") - LNG(wxLANGUAGE_ESPERANTO, "eo" , 0 , 0 , wxLayout_LeftToRight, "Esperanto") - LNG(wxLANGUAGE_ESTONIAN, "et_EE", LANG_ESTONIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Estonian") - LNG(wxLANGUAGE_FAEROESE, "fo_FO", LANG_FAEROESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Faeroese") - LNG(wxLANGUAGE_FARSI, "fa_IR", LANG_FARSI , SUBLANG_DEFAULT , wxLayout_RightToLeft, "Farsi") - LNG(wxLANGUAGE_FIJI, "fj" , 0 , 0 , wxLayout_LeftToRight, "Fiji") - LNG(wxLANGUAGE_FINNISH, "fi_FI", LANG_FINNISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Finnish") - LNG(wxLANGUAGE_FRENCH, "fr_FR", LANG_FRENCH , SUBLANG_FRENCH , wxLayout_LeftToRight, "French") - LNG(wxLANGUAGE_FRENCH_BELGIAN, "fr_BE", LANG_FRENCH , SUBLANG_FRENCH_BELGIAN , wxLayout_LeftToRight, "French (Belgian)") - LNG(wxLANGUAGE_FRENCH_CANADIAN, "fr_CA", LANG_FRENCH , SUBLANG_FRENCH_CANADIAN , wxLayout_LeftToRight, "French (Canadian)") - LNG(wxLANGUAGE_FRENCH_LUXEMBOURG, "fr_LU", LANG_FRENCH , SUBLANG_FRENCH_LUXEMBOURG , wxLayout_LeftToRight, "French (Luxembourg)") - LNG(wxLANGUAGE_FRENCH_MONACO, "fr_MC", LANG_FRENCH , SUBLANG_FRENCH_MONACO , wxLayout_LeftToRight, "French (Monaco)") - LNG(wxLANGUAGE_FRENCH_SWISS, "fr_CH", LANG_FRENCH , SUBLANG_FRENCH_SWISS , wxLayout_LeftToRight, "French (Swiss)") - LNG(wxLANGUAGE_FRISIAN, "fy" , 0 , 0 , wxLayout_LeftToRight, "Frisian") - LNG(wxLANGUAGE_GALICIAN, "gl_ES", 0 , 0 , wxLayout_LeftToRight, "Galician") - LNG(wxLANGUAGE_GEORGIAN, "ka_GE", LANG_GEORGIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Georgian") - LNG(wxLANGUAGE_GERMAN, "de_DE", LANG_GERMAN , SUBLANG_GERMAN , wxLayout_LeftToRight, "German") - LNG(wxLANGUAGE_GERMAN_AUSTRIAN, "de_AT", LANG_GERMAN , SUBLANG_GERMAN_AUSTRIAN , wxLayout_LeftToRight, "German (Austrian)") - LNG(wxLANGUAGE_GERMAN_BELGIUM, "de_BE", 0 , 0 , wxLayout_LeftToRight, "German (Belgium)") - LNG(wxLANGUAGE_GERMAN_LIECHTENSTEIN, "de_LI", LANG_GERMAN , SUBLANG_GERMAN_LIECHTENSTEIN , wxLayout_LeftToRight, "German (Liechtenstein)") - LNG(wxLANGUAGE_GERMAN_LUXEMBOURG, "de_LU", LANG_GERMAN , SUBLANG_GERMAN_LUXEMBOURG , wxLayout_LeftToRight, "German (Luxembourg)") - LNG(wxLANGUAGE_GERMAN_SWISS, "de_CH", LANG_GERMAN , SUBLANG_GERMAN_SWISS , wxLayout_LeftToRight, "German (Swiss)") - LNG(wxLANGUAGE_GREEK, "el_GR", LANG_GREEK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Greek") - LNG(wxLANGUAGE_GREENLANDIC, "kl_GL", 0 , 0 , wxLayout_LeftToRight, "Greenlandic") - LNG(wxLANGUAGE_GUARANI, "gn" , 0 , 0 , wxLayout_LeftToRight, "Guarani") - LNG(wxLANGUAGE_GUJARATI, "gu" , LANG_GUJARATI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Gujarati") - LNG(wxLANGUAGE_HAUSA, "ha" , 0 , 0 , wxLayout_LeftToRight, "Hausa") - LNG(wxLANGUAGE_HEBREW, "he_IL", LANG_HEBREW , SUBLANG_DEFAULT , wxLayout_RightToLeft, "Hebrew") - LNG(wxLANGUAGE_HINDI, "hi_IN", LANG_HINDI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Hindi") - LNG(wxLANGUAGE_HUNGARIAN, "hu_HU", LANG_HUNGARIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Hungarian") - LNG(wxLANGUAGE_ICELANDIC, "is_IS", LANG_ICELANDIC , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Icelandic") - LNG(wxLANGUAGE_INDONESIAN, "id_ID", LANG_INDONESIAN, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Indonesian") - LNG(wxLANGUAGE_INTERLINGUA, "ia" , 0 , 0 , wxLayout_LeftToRight, "Interlingua") - LNG(wxLANGUAGE_INTERLINGUE, "ie" , 0 , 0 , wxLayout_LeftToRight, "Interlingue") - LNG(wxLANGUAGE_INUKTITUT, "iu" , 0 , 0 , wxLayout_LeftToRight, "Inuktitut") - LNG(wxLANGUAGE_INUPIAK, "ik" , 0 , 0 , wxLayout_LeftToRight, "Inupiak") - LNG(wxLANGUAGE_IRISH, "ga_IE", 0 , 0 , wxLayout_LeftToRight, "Irish") - LNG(wxLANGUAGE_ITALIAN, "it_IT", LANG_ITALIAN , SUBLANG_ITALIAN , wxLayout_LeftToRight, "Italian") - LNG(wxLANGUAGE_ITALIAN_SWISS, "it_CH", LANG_ITALIAN , SUBLANG_ITALIAN_SWISS , wxLayout_LeftToRight, "Italian (Swiss)") - LNG(wxLANGUAGE_JAPANESE, "ja_JP", LANG_JAPANESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Japanese") - LNG(wxLANGUAGE_JAVANESE, "jw" , 0 , 0 , wxLayout_LeftToRight, "Javanese") - LNG(wxLANGUAGE_KANNADA, "kn" , LANG_KANNADA , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kannada") - LNG(wxLANGUAGE_KASHMIRI, "ks" , LANG_KASHMIRI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kashmiri") - LNG(wxLANGUAGE_KASHMIRI_INDIA, "ks_IN", LANG_KASHMIRI , SUBLANG_KASHMIRI_INDIA , wxLayout_LeftToRight, "Kashmiri (India)") - LNG(wxLANGUAGE_KAZAKH, "kk" , LANG_KAZAK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kazakh") - LNG(wxLANGUAGE_KERNEWEK, "kw_GB", 0 , 0 , wxLayout_LeftToRight, "Kernewek") - LNG(wxLANGUAGE_KINYARWANDA, "rw" , 0 , 0 , wxLayout_LeftToRight, "Kinyarwanda") - LNG(wxLANGUAGE_KIRGHIZ, "ky" , 0 , 0 , wxLayout_LeftToRight, "Kirghiz") - LNG(wxLANGUAGE_KIRUNDI, "rn" , 0 , 0 , wxLayout_LeftToRight, "Kirundi") - LNG(wxLANGUAGE_KONKANI, "" , LANG_KONKANI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Konkani") - LNG(wxLANGUAGE_KOREAN, "ko_KR", LANG_KOREAN , SUBLANG_KOREAN , wxLayout_LeftToRight, "Korean") - LNG(wxLANGUAGE_KURDISH, "ku_TR", 0 , 0 , wxLayout_LeftToRight, "Kurdish") - LNG(wxLANGUAGE_LAOTHIAN, "lo" , 0 , 0 , wxLayout_LeftToRight, "Laothian") - LNG(wxLANGUAGE_LATIN, "la" , 0 , 0 , wxLayout_LeftToRight, "Latin") - LNG(wxLANGUAGE_LATVIAN, "lv_LV", LANG_LATVIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Latvian") - LNG(wxLANGUAGE_LINGALA, "ln" , 0 , 0 , wxLayout_LeftToRight, "Lingala") - LNG(wxLANGUAGE_LITHUANIAN, "lt_LT", LANG_LITHUANIAN, SUBLANG_LITHUANIAN , wxLayout_LeftToRight, "Lithuanian") - LNG(wxLANGUAGE_MACEDONIAN, "mk_MK", LANG_MACEDONIAN, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Macedonian") - LNG(wxLANGUAGE_MALAGASY, "mg" , 0 , 0 , wxLayout_LeftToRight, "Malagasy") - LNG(wxLANGUAGE_MALAY, "ms_MY", LANG_MALAY , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Malay") - LNG(wxLANGUAGE_MALAYALAM, "ml" , LANG_MALAYALAM , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Malayalam") - LNG(wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM, "ms_BN", LANG_MALAY , SUBLANG_MALAY_BRUNEI_DARUSSALAM , wxLayout_LeftToRight, "Malay (Brunei Darussalam)") - LNG(wxLANGUAGE_MALAY_MALAYSIA, "ms_MY", LANG_MALAY , SUBLANG_MALAY_MALAYSIA , wxLayout_LeftToRight, "Malay (Malaysia)") - LNG(wxLANGUAGE_MALTESE, "mt_MT", 0 , 0 , wxLayout_LeftToRight, "Maltese") - LNG(wxLANGUAGE_MANIPURI, "" , LANG_MANIPURI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Manipuri") - LNG(wxLANGUAGE_MAORI, "mi" , 0 , 0 , wxLayout_LeftToRight, "Maori") - LNG(wxLANGUAGE_MARATHI, "mr_IN", LANG_MARATHI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Marathi") - LNG(wxLANGUAGE_MOLDAVIAN, "mo" , 0 , 0 , wxLayout_LeftToRight, "Moldavian") - LNG(wxLANGUAGE_MONGOLIAN, "mn" , 0 , 0 , wxLayout_LeftToRight, "Mongolian") - LNG(wxLANGUAGE_NAURU, "na" , 0 , 0 , wxLayout_LeftToRight, "Nauru") - LNG(wxLANGUAGE_NEPALI, "ne_NP", LANG_NEPALI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Nepali") - LNG(wxLANGUAGE_NEPALI_INDIA, "ne_IN", LANG_NEPALI , SUBLANG_NEPALI_INDIA , wxLayout_LeftToRight, "Nepali (India)") - LNG(wxLANGUAGE_NORWEGIAN_BOKMAL, "nb_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_BOKMAL , wxLayout_LeftToRight, "Norwegian (Bokmal)") - LNG(wxLANGUAGE_NORWEGIAN_NYNORSK, "nn_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_NYNORSK , wxLayout_LeftToRight, "Norwegian (Nynorsk)") - LNG(wxLANGUAGE_OCCITAN, "oc" , 0 , 0 , wxLayout_LeftToRight, "Occitan") - LNG(wxLANGUAGE_ORIYA, "or" , LANG_ORIYA , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Oriya") - LNG(wxLANGUAGE_OROMO, "om" , 0 , 0 , wxLayout_LeftToRight, "(Afan) Oromo") - LNG(wxLANGUAGE_PASHTO, "ps" , 0 , 0 , wxLayout_LeftToRight, "Pashto, Pushto") - LNG(wxLANGUAGE_POLISH, "pl_PL", LANG_POLISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Polish") - LNG(wxLANGUAGE_PORTUGUESE, "pt_PT", LANG_PORTUGUESE, SUBLANG_PORTUGUESE , wxLayout_LeftToRight, "Portuguese") - LNG(wxLANGUAGE_PORTUGUESE_BRAZILIAN, "pt_BR", LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN , wxLayout_LeftToRight, "Portuguese (Brazilian)") - LNG(wxLANGUAGE_PUNJABI, "pa" , LANG_PUNJABI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Punjabi") - LNG(wxLANGUAGE_QUECHUA, "qu" , 0 , 0 , wxLayout_LeftToRight, "Quechua") - LNG(wxLANGUAGE_RHAETO_ROMANCE, "rm" , 0 , 0 , wxLayout_LeftToRight, "Rhaeto-Romance") - LNG(wxLANGUAGE_ROMANIAN, "ro_RO", LANG_ROMANIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Romanian") - LNG(wxLANGUAGE_RUSSIAN, "ru_RU", LANG_RUSSIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Russian") - LNG(wxLANGUAGE_RUSSIAN_UKRAINE, "ru_UA", 0 , 0 , wxLayout_LeftToRight, "Russian (Ukraine)") - LNG(wxLANGUAGE_SAMI, "se_NO", LANG_SAMI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Northern Sami") - LNG(wxLANGUAGE_SAMOAN, "sm" , 0 , 0 , wxLayout_LeftToRight, "Samoan") - LNG(wxLANGUAGE_SANGHO, "sg" , 0 , 0 , wxLayout_LeftToRight, "Sangho") - LNG(wxLANGUAGE_SANSKRIT, "sa" , LANG_SANSKRIT , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Sanskrit") - LNG(wxLANGUAGE_SCOTS_GAELIC, "gd" , 0 , 0 , wxLayout_LeftToRight, "Scots Gaelic") - LNG(wxLANGUAGE_SERBIAN, "sr_RS", LANG_SERBIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Serbian") - LNG(wxLANGUAGE_SERBIAN_CYRILLIC, "sr_RS", LANG_SERBIAN , SUBLANG_SERBIAN_CYRILLIC , wxLayout_LeftToRight, "Serbian (Cyrillic)") - LNG(wxLANGUAGE_SERBIAN_LATIN, "sr_RS@latin", LANG_SERBIAN , SUBLANG_SERBIAN_LATIN , wxLayout_LeftToRight, "Serbian (Latin)") - LNG(wxLANGUAGE_SERBIAN_CYRILLIC, "sr_YU", LANG_SERBIAN , SUBLANG_SERBIAN_CYRILLIC , wxLayout_LeftToRight, "Serbian (Cyrillic)") - LNG(wxLANGUAGE_SERBIAN_LATIN, "sr_YU@latin", LANG_SERBIAN , SUBLANG_SERBIAN_LATIN , wxLayout_LeftToRight, "Serbian (Latin)") - LNG(wxLANGUAGE_SERBO_CROATIAN, "sh" , 0 , 0 , wxLayout_LeftToRight, "Serbo-Croatian") - LNG(wxLANGUAGE_SESOTHO, "st" , 0 , 0 , wxLayout_LeftToRight, "Sesotho") - LNG(wxLANGUAGE_SETSWANA, "tn" , 0 , 0 , wxLayout_LeftToRight, "Setswana") - LNG(wxLANGUAGE_SHONA, "sn" , 0 , 0 , wxLayout_LeftToRight, "Shona") - LNG(wxLANGUAGE_SINDHI, "sd" , LANG_SINDHI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Sindhi") - LNG(wxLANGUAGE_SINHALESE, "si" , 0 , 0 , wxLayout_LeftToRight, "Sinhalese") - LNG(wxLANGUAGE_SISWATI, "ss" , 0 , 0 , wxLayout_LeftToRight, "Siswati") - LNG(wxLANGUAGE_SLOVAK, "sk_SK", LANG_SLOVAK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Slovak") - LNG(wxLANGUAGE_SLOVENIAN, "sl_SI", LANG_SLOVENIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Slovenian") - LNG(wxLANGUAGE_SOMALI, "so" , 0 , 0 , wxLayout_LeftToRight, "Somali") - LNG(wxLANGUAGE_SPANISH, "es_ES", LANG_SPANISH , SUBLANG_SPANISH , wxLayout_LeftToRight, "Spanish") - LNG(wxLANGUAGE_SPANISH_ARGENTINA, "es_AR", LANG_SPANISH , SUBLANG_SPANISH_ARGENTINA , wxLayout_LeftToRight, "Spanish (Argentina)") - LNG(wxLANGUAGE_SPANISH_BOLIVIA, "es_BO", LANG_SPANISH , SUBLANG_SPANISH_BOLIVIA , wxLayout_LeftToRight, "Spanish (Bolivia)") - LNG(wxLANGUAGE_SPANISH_CHILE, "es_CL", LANG_SPANISH , SUBLANG_SPANISH_CHILE , wxLayout_LeftToRight, "Spanish (Chile)") - LNG(wxLANGUAGE_SPANISH_COLOMBIA, "es_CO", LANG_SPANISH , SUBLANG_SPANISH_COLOMBIA , wxLayout_LeftToRight, "Spanish (Colombia)") - LNG(wxLANGUAGE_SPANISH_COSTA_RICA, "es_CR", LANG_SPANISH , SUBLANG_SPANISH_COSTA_RICA , wxLayout_LeftToRight, "Spanish (Costa Rica)") - LNG(wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC, "es_DO", LANG_SPANISH , SUBLANG_SPANISH_DOMINICAN_REPUBLIC, wxLayout_LeftToRight, "Spanish (Dominican republic)") - LNG(wxLANGUAGE_SPANISH_ECUADOR, "es_EC", LANG_SPANISH , SUBLANG_SPANISH_ECUADOR , wxLayout_LeftToRight, "Spanish (Ecuador)") - LNG(wxLANGUAGE_SPANISH_EL_SALVADOR, "es_SV", LANG_SPANISH , SUBLANG_SPANISH_EL_SALVADOR , wxLayout_LeftToRight, "Spanish (El Salvador)") - LNG(wxLANGUAGE_SPANISH_GUATEMALA, "es_GT", LANG_SPANISH , SUBLANG_SPANISH_GUATEMALA , wxLayout_LeftToRight, "Spanish (Guatemala)") - LNG(wxLANGUAGE_SPANISH_HONDURAS, "es_HN", LANG_SPANISH , SUBLANG_SPANISH_HONDURAS , wxLayout_LeftToRight, "Spanish (Honduras)") - LNG(wxLANGUAGE_SPANISH_MEXICAN, "es_MX", LANG_SPANISH , SUBLANG_SPANISH_MEXICAN , wxLayout_LeftToRight, "Spanish (Mexican)") - LNG(wxLANGUAGE_SPANISH_MODERN, "es_ES", LANG_SPANISH , SUBLANG_SPANISH_MODERN , wxLayout_LeftToRight, "Spanish (Modern)") - LNG(wxLANGUAGE_SPANISH_NICARAGUA, "es_NI", LANG_SPANISH , SUBLANG_SPANISH_NICARAGUA , wxLayout_LeftToRight, "Spanish (Nicaragua)") - LNG(wxLANGUAGE_SPANISH_PANAMA, "es_PA", LANG_SPANISH , SUBLANG_SPANISH_PANAMA , wxLayout_LeftToRight, "Spanish (Panama)") - LNG(wxLANGUAGE_SPANISH_PARAGUAY, "es_PY", LANG_SPANISH , SUBLANG_SPANISH_PARAGUAY , wxLayout_LeftToRight, "Spanish (Paraguay)") - LNG(wxLANGUAGE_SPANISH_PERU, "es_PE", LANG_SPANISH , SUBLANG_SPANISH_PERU , wxLayout_LeftToRight, "Spanish (Peru)") - LNG(wxLANGUAGE_SPANISH_PUERTO_RICO, "es_PR", LANG_SPANISH , SUBLANG_SPANISH_PUERTO_RICO , wxLayout_LeftToRight, "Spanish (Puerto Rico)") - LNG(wxLANGUAGE_SPANISH_URUGUAY, "es_UY", LANG_SPANISH , SUBLANG_SPANISH_URUGUAY , wxLayout_LeftToRight, "Spanish (Uruguay)") - LNG(wxLANGUAGE_SPANISH_US, "es_US", 0 , 0 , wxLayout_LeftToRight, "Spanish (U.S.)") - LNG(wxLANGUAGE_SPANISH_VENEZUELA, "es_VE", LANG_SPANISH , SUBLANG_SPANISH_VENEZUELA , wxLayout_LeftToRight, "Spanish (Venezuela)") - LNG(wxLANGUAGE_SUNDANESE, "su" , 0 , 0 , wxLayout_LeftToRight, "Sundanese") - LNG(wxLANGUAGE_SWAHILI, "sw_KE", LANG_SWAHILI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Swahili") - LNG(wxLANGUAGE_SWEDISH, "sv_SE", LANG_SWEDISH , SUBLANG_SWEDISH , wxLayout_LeftToRight, "Swedish") - LNG(wxLANGUAGE_SWEDISH_FINLAND, "sv_FI", LANG_SWEDISH , SUBLANG_SWEDISH_FINLAND , wxLayout_LeftToRight, "Swedish (Finland)") - LNG(wxLANGUAGE_TAGALOG, "tl_PH", 0 , 0 , wxLayout_LeftToRight, "Tagalog") - LNG(wxLANGUAGE_TAJIK, "tg" , 0 , 0 , wxLayout_LeftToRight, "Tajik") - LNG(wxLANGUAGE_TAMIL, "ta" , LANG_TAMIL , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Tamil") - LNG(wxLANGUAGE_TATAR, "tt" , LANG_TATAR , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Tatar") - LNG(wxLANGUAGE_TELUGU, "te" , LANG_TELUGU , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Telugu") - LNG(wxLANGUAGE_THAI, "th_TH", LANG_THAI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Thai") - LNG(wxLANGUAGE_TIBETAN, "bo" , 0 , 0 , wxLayout_LeftToRight, "Tibetan") - LNG(wxLANGUAGE_TIGRINYA, "ti" , 0 , 0 , wxLayout_LeftToRight, "Tigrinya") - LNG(wxLANGUAGE_TONGA, "to" , 0 , 0 , wxLayout_LeftToRight, "Tonga") - LNG(wxLANGUAGE_TSONGA, "ts" , 0 , 0 , wxLayout_LeftToRight, "Tsonga") - LNG(wxLANGUAGE_TURKISH, "tr_TR", LANG_TURKISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Turkish") - LNG(wxLANGUAGE_TURKMEN, "tk" , 0 , 0 , wxLayout_LeftToRight, "Turkmen") - LNG(wxLANGUAGE_TWI, "tw" , 0 , 0 , wxLayout_LeftToRight, "Twi") - LNG(wxLANGUAGE_UIGHUR, "ug" , 0 , 0 , wxLayout_LeftToRight, "Uighur") - LNG(wxLANGUAGE_UKRAINIAN, "uk_UA", LANG_UKRAINIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Ukrainian") - LNG(wxLANGUAGE_URDU, "ur" , LANG_URDU , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Urdu") - LNG(wxLANGUAGE_URDU_INDIA, "ur_IN", LANG_URDU , SUBLANG_URDU_INDIA , wxLayout_LeftToRight, "Urdu (India)") - LNG(wxLANGUAGE_URDU_PAKISTAN, "ur_PK", LANG_URDU , SUBLANG_URDU_PAKISTAN , wxLayout_LeftToRight, "Urdu (Pakistan)") - LNG(wxLANGUAGE_UZBEK, "uz" , LANG_UZBEK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Uzbek") - LNG(wxLANGUAGE_UZBEK_CYRILLIC, "uz" , LANG_UZBEK , SUBLANG_UZBEK_CYRILLIC , wxLayout_LeftToRight, "Uzbek (Cyrillic)") - LNG(wxLANGUAGE_UZBEK_LATIN, "uz" , LANG_UZBEK , SUBLANG_UZBEK_LATIN , wxLayout_LeftToRight, "Uzbek (Latin)") - LNG(wxLANGUAGE_VALENCIAN, "ca_ES@valencia", LANG_VALENCIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Valencian") - LNG(wxLANGUAGE_VIETNAMESE, "vi_VN", LANG_VIETNAMESE, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Vietnamese") - LNG(wxLANGUAGE_VOLAPUK, "vo" , 0 , 0 , wxLayout_LeftToRight, "Volapuk") - LNG(wxLANGUAGE_WELSH, "cy" , 0 , 0 , wxLayout_LeftToRight, "Welsh") - LNG(wxLANGUAGE_WOLOF, "wo" , 0 , 0 , wxLayout_LeftToRight, "Wolof") - LNG(wxLANGUAGE_XHOSA, "xh" , 0 , 0 , wxLayout_LeftToRight, "Xhosa") - LNG(wxLANGUAGE_YIDDISH, "yi" , 0 , 0 , wxLayout_LeftToRight, "Yiddish") - LNG(wxLANGUAGE_YORUBA, "yo" , 0 , 0 , wxLayout_LeftToRight, "Yoruba") - LNG(wxLANGUAGE_ZHUANG, "za" , 0 , 0 , wxLayout_LeftToRight, "Zhuang") - LNG(wxLANGUAGE_ZULU, "zu" , 0 , 0 , wxLayout_LeftToRight, "Zulu") -} -#undef LNG - -// --- --- --- generated code ends here --- --- --- - -#endif // wxUSE_INTL +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/intl.cpp +// Purpose: Internationalization and localisation for wxWidgets +// Author: Vadim Zeitlin +// Modified by: Michael N. Filippov +// (2003/09/30 - PluralForms support) +// Created: 29/01/98 +// RCS-ID: $Id: intl.cpp 61340 2009-07-06 21:19:58Z VZ $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declaration +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifdef __EMX__ +// The following define is needed by Innotek's libc to +// make the definition of struct localeconv available. +#define __INTERNAL_DEFS +#endif + +#if wxUSE_INTL + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" + #include "wx/app.h" + #include "wx/hashmap.h" + #include "wx/module.h" +#endif // WX_PRECOMP + +#ifndef __WXWINCE__ + #include +#endif + +// standard headers +#include +#include +#ifdef HAVE_LANGINFO_H + #include +#endif + +#ifdef __WIN32__ + #include "wx/msw/private.h" +#elif defined(__UNIX_LIKE__) + #include "wx/fontmap.h" // for CharsetToEncoding() +#endif + +#include "wx/file.h" +#include "wx/filename.h" +#include "wx/tokenzr.h" +#include "wx/fontmap.h" +#include "wx/encconv.h" +#include "wx/ptr_scpd.h" +#include "wx/apptrait.h" +#include "wx/stdpaths.h" + +#if defined(__WXMAC__) + #include "wx/mac/private.h" // includes mac headers +#endif + +#if defined(__DARWIN__) + #include "wx/mac/corefoundation/cfref.h" + #include + #include "wx/mac/corefoundation/cfstring.h" +#endif + +// ---------------------------------------------------------------------------- +// simple types +// ---------------------------------------------------------------------------- + +// this should *not* be wxChar, this type must have exactly 8 bits! +typedef wxUint8 size_t8; +typedef wxUint32 size_t32; + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// magic number identifying the .mo format file +const size_t32 MSGCATALOG_MAGIC = 0x950412de; +const size_t32 MSGCATALOG_MAGIC_SW = 0xde120495; + +// the constants describing the format of lang_LANG locale string +static const size_t LEN_LANG = 2; +static const size_t LEN_SUBLANG = 2; +static const size_t LEN_FULL = LEN_LANG + 1 + LEN_SUBLANG; // 1 for '_' + +#define TRACE_I18N _T("i18n") + +// ---------------------------------------------------------------------------- +// global functions +// ---------------------------------------------------------------------------- + +#ifdef __WXDEBUG__ + +// small class to suppress the translation erros until exit from current scope +class NoTransErr +{ +public: + NoTransErr() { ms_suppressCount++; } + ~NoTransErr() { ms_suppressCount--; } + + static bool Suppress() { return ms_suppressCount > 0; } + +private: + static size_t ms_suppressCount; +}; + +size_t NoTransErr::ms_suppressCount = 0; + +#else // !Debug + +class NoTransErr +{ +public: + NoTransErr() { } + ~NoTransErr() { } +}; + +#endif // Debug/!Debug + +static wxLocale *wxSetLocale(wxLocale *pLocale); + +// helper functions of GetSystemLanguage() +#ifdef __UNIX__ + +// get just the language part +static inline wxString ExtractLang(const wxString& langFull) +{ + return langFull.Left(LEN_LANG); +} + +// get everything else (including the leading '_') +static inline wxString ExtractNotLang(const wxString& langFull) +{ + return langFull.Mid(LEN_LANG); +} + +#endif // __UNIX__ + + +// ---------------------------------------------------------------------------- +// Plural forms parser +// ---------------------------------------------------------------------------- + +/* + Simplified Grammar + +Expression: + LogicalOrExpression '?' Expression ':' Expression + LogicalOrExpression + +LogicalOrExpression: + LogicalAndExpression "||" LogicalOrExpression // to (a || b) || c + LogicalAndExpression + +LogicalAndExpression: + EqualityExpression "&&" LogicalAndExpression // to (a && b) && c + EqualityExpression + +EqualityExpression: + RelationalExpression "==" RelationalExperession + RelationalExpression "!=" RelationalExperession + RelationalExpression + +RelationalExpression: + MultiplicativeExpression '>' MultiplicativeExpression + MultiplicativeExpression '<' MultiplicativeExpression + MultiplicativeExpression ">=" MultiplicativeExpression + MultiplicativeExpression "<=" MultiplicativeExpression + MultiplicativeExpression + +MultiplicativeExpression: + PmExpression '%' PmExpression + PmExpression + +PmExpression: + N + Number + '(' Expression ')' +*/ + +class wxPluralFormsToken +{ +public: + enum Type + { + T_ERROR, T_EOF, T_NUMBER, T_N, T_PLURAL, T_NPLURALS, T_EQUAL, T_ASSIGN, + T_GREATER, T_GREATER_OR_EQUAL, T_LESS, T_LESS_OR_EQUAL, + T_REMINDER, T_NOT_EQUAL, + T_LOGICAL_AND, T_LOGICAL_OR, T_QUESTION, T_COLON, T_SEMICOLON, + T_LEFT_BRACKET, T_RIGHT_BRACKET + }; + Type type() const { return m_type; } + void setType(Type type) { m_type = type; } + // for T_NUMBER only + typedef int Number; + Number number() const { return m_number; } + void setNumber(Number num) { m_number = num; } +private: + Type m_type; + Number m_number; +}; + + +class wxPluralFormsScanner +{ +public: + wxPluralFormsScanner(const char* s); + const wxPluralFormsToken& token() const { return m_token; } + bool nextToken(); // returns false if error +private: + const char* m_s; + wxPluralFormsToken m_token; +}; + +wxPluralFormsScanner::wxPluralFormsScanner(const char* s) : m_s(s) +{ + nextToken(); +} + +bool wxPluralFormsScanner::nextToken() +{ + wxPluralFormsToken::Type type = wxPluralFormsToken::T_ERROR; + while (isspace((unsigned char) *m_s)) + { + ++m_s; + } + if (*m_s == 0) + { + type = wxPluralFormsToken::T_EOF; + } + else if (isdigit((unsigned char) *m_s)) + { + wxPluralFormsToken::Number number = *m_s++ - '0'; + while (isdigit((unsigned char) *m_s)) + { + number = number * 10 + (*m_s++ - '0'); + } + m_token.setNumber(number); + type = wxPluralFormsToken::T_NUMBER; + } + else if (isalpha((unsigned char) *m_s)) + { + const char* begin = m_s++; + while (isalnum((unsigned char) *m_s)) + { + ++m_s; + } + size_t size = m_s - begin; + if (size == 1 && memcmp(begin, "n", size) == 0) + { + type = wxPluralFormsToken::T_N; + } + else if (size == 6 && memcmp(begin, "plural", size) == 0) + { + type = wxPluralFormsToken::T_PLURAL; + } + else if (size == 8 && memcmp(begin, "nplurals", size) == 0) + { + type = wxPluralFormsToken::T_NPLURALS; + } + } + else if (*m_s == '=') + { + ++m_s; + if (*m_s == '=') + { + ++m_s; + type = wxPluralFormsToken::T_EQUAL; + } + else + { + type = wxPluralFormsToken::T_ASSIGN; + } + } + else if (*m_s == '>') + { + ++m_s; + if (*m_s == '=') + { + ++m_s; + type = wxPluralFormsToken::T_GREATER_OR_EQUAL; + } + else + { + type = wxPluralFormsToken::T_GREATER; + } + } + else if (*m_s == '<') + { + ++m_s; + if (*m_s == '=') + { + ++m_s; + type = wxPluralFormsToken::T_LESS_OR_EQUAL; + } + else + { + type = wxPluralFormsToken::T_LESS; + } + } + else if (*m_s == '%') + { + ++m_s; + type = wxPluralFormsToken::T_REMINDER; + } + else if (*m_s == '!' && m_s[1] == '=') + { + m_s += 2; + type = wxPluralFormsToken::T_NOT_EQUAL; + } + else if (*m_s == '&' && m_s[1] == '&') + { + m_s += 2; + type = wxPluralFormsToken::T_LOGICAL_AND; + } + else if (*m_s == '|' && m_s[1] == '|') + { + m_s += 2; + type = wxPluralFormsToken::T_LOGICAL_OR; + } + else if (*m_s == '?') + { + ++m_s; + type = wxPluralFormsToken::T_QUESTION; + } + else if (*m_s == ':') + { + ++m_s; + type = wxPluralFormsToken::T_COLON; + } else if (*m_s == ';') { + ++m_s; + type = wxPluralFormsToken::T_SEMICOLON; + } + else if (*m_s == '(') + { + ++m_s; + type = wxPluralFormsToken::T_LEFT_BRACKET; + } + else if (*m_s == ')') + { + ++m_s; + type = wxPluralFormsToken::T_RIGHT_BRACKET; + } + m_token.setType(type); + return type != wxPluralFormsToken::T_ERROR; +} + +class wxPluralFormsNode; + +// NB: Can't use wxDEFINE_SCOPED_PTR_TYPE because wxPluralFormsNode is not +// fully defined yet: +class wxPluralFormsNodePtr +{ +public: + wxPluralFormsNodePtr(wxPluralFormsNode *p = NULL) : m_p(p) {} + ~wxPluralFormsNodePtr(); + wxPluralFormsNode& operator*() const { return *m_p; } + wxPluralFormsNode* operator->() const { return m_p; } + wxPluralFormsNode* get() const { return m_p; } + wxPluralFormsNode* release(); + void reset(wxPluralFormsNode *p); + +private: + wxPluralFormsNode *m_p; +}; + +class wxPluralFormsNode +{ +public: + wxPluralFormsNode(const wxPluralFormsToken& token) : m_token(token) {} + const wxPluralFormsToken& token() const { return m_token; } + const wxPluralFormsNode* node(size_t i) const + { return m_nodes[i].get(); } + void setNode(size_t i, wxPluralFormsNode* n); + wxPluralFormsNode* releaseNode(size_t i); + wxPluralFormsToken::Number evaluate(wxPluralFormsToken::Number n) const; + +private: + wxPluralFormsToken m_token; + wxPluralFormsNodePtr m_nodes[3]; +}; + +wxPluralFormsNodePtr::~wxPluralFormsNodePtr() +{ + delete m_p; +} +wxPluralFormsNode* wxPluralFormsNodePtr::release() +{ + wxPluralFormsNode *p = m_p; + m_p = NULL; + return p; +} +void wxPluralFormsNodePtr::reset(wxPluralFormsNode *p) +{ + if (p != m_p) + { + delete m_p; + m_p = p; + } +} + + +void wxPluralFormsNode::setNode(size_t i, wxPluralFormsNode* n) +{ + m_nodes[i].reset(n); +} + +wxPluralFormsNode* wxPluralFormsNode::releaseNode(size_t i) +{ + return m_nodes[i].release(); +} + +wxPluralFormsToken::Number +wxPluralFormsNode::evaluate(wxPluralFormsToken::Number n) const +{ + switch (token().type()) + { + // leaf + case wxPluralFormsToken::T_NUMBER: + return token().number(); + case wxPluralFormsToken::T_N: + return n; + // 2 args + case wxPluralFormsToken::T_EQUAL: + return node(0)->evaluate(n) == node(1)->evaluate(n); + case wxPluralFormsToken::T_NOT_EQUAL: + return node(0)->evaluate(n) != node(1)->evaluate(n); + case wxPluralFormsToken::T_GREATER: + return node(0)->evaluate(n) > node(1)->evaluate(n); + case wxPluralFormsToken::T_GREATER_OR_EQUAL: + return node(0)->evaluate(n) >= node(1)->evaluate(n); + case wxPluralFormsToken::T_LESS: + return node(0)->evaluate(n) < node(1)->evaluate(n); + case wxPluralFormsToken::T_LESS_OR_EQUAL: + return node(0)->evaluate(n) <= node(1)->evaluate(n); + case wxPluralFormsToken::T_REMINDER: + { + wxPluralFormsToken::Number number = node(1)->evaluate(n); + if (number != 0) + { + return node(0)->evaluate(n) % number; + } + else + { + return 0; + } + } + case wxPluralFormsToken::T_LOGICAL_AND: + return node(0)->evaluate(n) && node(1)->evaluate(n); + case wxPluralFormsToken::T_LOGICAL_OR: + return node(0)->evaluate(n) || node(1)->evaluate(n); + // 3 args + case wxPluralFormsToken::T_QUESTION: + return node(0)->evaluate(n) + ? node(1)->evaluate(n) + : node(2)->evaluate(n); + default: + return 0; + } +} + + +class wxPluralFormsCalculator +{ +public: + wxPluralFormsCalculator() : m_nplurals(0), m_plural(0) {} + + // input: number, returns msgstr index + int evaluate(int n) const; + + // input: text after "Plural-Forms:" (e.g. "nplurals=2; plural=(n != 1);"), + // if s == 0, creates default handler + // returns 0 if error + static wxPluralFormsCalculator* make(const char* s = 0); + + ~wxPluralFormsCalculator() {} + + void init(wxPluralFormsToken::Number nplurals, wxPluralFormsNode* plural); + +private: + wxPluralFormsToken::Number m_nplurals; + wxPluralFormsNodePtr m_plural; +}; + +wxDEFINE_SCOPED_PTR_TYPE(wxPluralFormsCalculator) + +void wxPluralFormsCalculator::init(wxPluralFormsToken::Number nplurals, + wxPluralFormsNode* plural) +{ + m_nplurals = nplurals; + m_plural.reset(plural); +} + +int wxPluralFormsCalculator::evaluate(int n) const +{ + if (m_plural.get() == 0) + { + return 0; + } + wxPluralFormsToken::Number number = m_plural->evaluate(n); + if (number < 0 || number > m_nplurals) + { + return 0; + } + return number; +} + + +class wxPluralFormsParser +{ +public: + wxPluralFormsParser(wxPluralFormsScanner& scanner) : m_scanner(scanner) {} + bool parse(wxPluralFormsCalculator& rCalculator); + +private: + wxPluralFormsNode* parsePlural(); + // stops at T_SEMICOLON, returns 0 if error + wxPluralFormsScanner& m_scanner; + const wxPluralFormsToken& token() const; + bool nextToken(); + + wxPluralFormsNode* expression(); + wxPluralFormsNode* logicalOrExpression(); + wxPluralFormsNode* logicalAndExpression(); + wxPluralFormsNode* equalityExpression(); + wxPluralFormsNode* multiplicativeExpression(); + wxPluralFormsNode* relationalExpression(); + wxPluralFormsNode* pmExpression(); +}; + +bool wxPluralFormsParser::parse(wxPluralFormsCalculator& rCalculator) +{ + if (token().type() != wxPluralFormsToken::T_NPLURALS) + return false; + if (!nextToken()) + return false; + if (token().type() != wxPluralFormsToken::T_ASSIGN) + return false; + if (!nextToken()) + return false; + if (token().type() != wxPluralFormsToken::T_NUMBER) + return false; + wxPluralFormsToken::Number nplurals = token().number(); + if (!nextToken()) + return false; + if (token().type() != wxPluralFormsToken::T_SEMICOLON) + return false; + if (!nextToken()) + return false; + if (token().type() != wxPluralFormsToken::T_PLURAL) + return false; + if (!nextToken()) + return false; + if (token().type() != wxPluralFormsToken::T_ASSIGN) + return false; + if (!nextToken()) + return false; + wxPluralFormsNode* plural = parsePlural(); + if (plural == 0) + return false; + if (token().type() != wxPluralFormsToken::T_SEMICOLON) + return false; + if (!nextToken()) + return false; + if (token().type() != wxPluralFormsToken::T_EOF) + return false; + rCalculator.init(nplurals, plural); + return true; +} + +wxPluralFormsNode* wxPluralFormsParser::parsePlural() +{ + wxPluralFormsNode* p = expression(); + if (p == NULL) + { + return NULL; + } + wxPluralFormsNodePtr n(p); + if (token().type() != wxPluralFormsToken::T_SEMICOLON) + { + return NULL; + } + return n.release(); +} + +const wxPluralFormsToken& wxPluralFormsParser::token() const +{ + return m_scanner.token(); +} + +bool wxPluralFormsParser::nextToken() +{ + if (!m_scanner.nextToken()) + return false; + return true; +} + +wxPluralFormsNode* wxPluralFormsParser::expression() +{ + wxPluralFormsNode* p = logicalOrExpression(); + if (p == NULL) + return NULL; + wxPluralFormsNodePtr n(p); + if (token().type() == wxPluralFormsToken::T_QUESTION) + { + wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); + if (!nextToken()) + { + return 0; + } + p = expression(); + if (p == 0) + { + return 0; + } + qn->setNode(1, p); + if (token().type() != wxPluralFormsToken::T_COLON) + { + return 0; + } + if (!nextToken()) + { + return 0; + } + p = expression(); + if (p == 0) + { + return 0; + } + qn->setNode(2, p); + qn->setNode(0, n.release()); + return qn.release(); + } + return n.release(); +} + +wxPluralFormsNode*wxPluralFormsParser::logicalOrExpression() +{ + wxPluralFormsNode* p = logicalAndExpression(); + if (p == NULL) + return NULL; + wxPluralFormsNodePtr ln(p); + if (token().type() == wxPluralFormsToken::T_LOGICAL_OR) + { + wxPluralFormsNodePtr un(new wxPluralFormsNode(token())); + if (!nextToken()) + { + return 0; + } + p = logicalOrExpression(); + if (p == 0) + { + return 0; + } + wxPluralFormsNodePtr rn(p); // right + if (rn->token().type() == wxPluralFormsToken::T_LOGICAL_OR) + { + // see logicalAndExpression comment + un->setNode(0, ln.release()); + un->setNode(1, rn->releaseNode(0)); + rn->setNode(0, un.release()); + return rn.release(); + } + + + un->setNode(0, ln.release()); + un->setNode(1, rn.release()); + return un.release(); + } + return ln.release(); +} + +wxPluralFormsNode* wxPluralFormsParser::logicalAndExpression() +{ + wxPluralFormsNode* p = equalityExpression(); + if (p == NULL) + return NULL; + wxPluralFormsNodePtr ln(p); // left + if (token().type() == wxPluralFormsToken::T_LOGICAL_AND) + { + wxPluralFormsNodePtr un(new wxPluralFormsNode(token())); // up + if (!nextToken()) + { + return NULL; + } + p = logicalAndExpression(); + if (p == 0) + { + return NULL; + } + wxPluralFormsNodePtr rn(p); // right + if (rn->token().type() == wxPluralFormsToken::T_LOGICAL_AND) + { +// transform 1 && (2 && 3) -> (1 && 2) && 3 +// u r +// l r -> u 3 +// 2 3 l 2 + un->setNode(0, ln.release()); + un->setNode(1, rn->releaseNode(0)); + rn->setNode(0, un.release()); + return rn.release(); + } + + un->setNode(0, ln.release()); + un->setNode(1, rn.release()); + return un.release(); + } + return ln.release(); +} + +wxPluralFormsNode* wxPluralFormsParser::equalityExpression() +{ + wxPluralFormsNode* p = relationalExpression(); + if (p == NULL) + return NULL; + wxPluralFormsNodePtr n(p); + if (token().type() == wxPluralFormsToken::T_EQUAL + || token().type() == wxPluralFormsToken::T_NOT_EQUAL) + { + wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); + if (!nextToken()) + { + return NULL; + } + p = relationalExpression(); + if (p == NULL) + { + return NULL; + } + qn->setNode(1, p); + qn->setNode(0, n.release()); + return qn.release(); + } + return n.release(); +} + +wxPluralFormsNode* wxPluralFormsParser::relationalExpression() +{ + wxPluralFormsNode* p = multiplicativeExpression(); + if (p == NULL) + return NULL; + wxPluralFormsNodePtr n(p); + if (token().type() == wxPluralFormsToken::T_GREATER + || token().type() == wxPluralFormsToken::T_LESS + || token().type() == wxPluralFormsToken::T_GREATER_OR_EQUAL + || token().type() == wxPluralFormsToken::T_LESS_OR_EQUAL) + { + wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); + if (!nextToken()) + { + return NULL; + } + p = multiplicativeExpression(); + if (p == NULL) + { + return NULL; + } + qn->setNode(1, p); + qn->setNode(0, n.release()); + return qn.release(); + } + return n.release(); +} + +wxPluralFormsNode* wxPluralFormsParser::multiplicativeExpression() +{ + wxPluralFormsNode* p = pmExpression(); + if (p == NULL) + return NULL; + wxPluralFormsNodePtr n(p); + if (token().type() == wxPluralFormsToken::T_REMINDER) + { + wxPluralFormsNodePtr qn(new wxPluralFormsNode(token())); + if (!nextToken()) + { + return NULL; + } + p = pmExpression(); + if (p == NULL) + { + return NULL; + } + qn->setNode(1, p); + qn->setNode(0, n.release()); + return qn.release(); + } + return n.release(); +} + +wxPluralFormsNode* wxPluralFormsParser::pmExpression() +{ + wxPluralFormsNodePtr n; + if (token().type() == wxPluralFormsToken::T_N + || token().type() == wxPluralFormsToken::T_NUMBER) + { + n.reset(new wxPluralFormsNode(token())); + if (!nextToken()) + { + return NULL; + } + } + else if (token().type() == wxPluralFormsToken::T_LEFT_BRACKET) { + if (!nextToken()) + { + return NULL; + } + wxPluralFormsNode* p = expression(); + if (p == NULL) + { + return NULL; + } + n.reset(p); + if (token().type() != wxPluralFormsToken::T_RIGHT_BRACKET) + { + return NULL; + } + if (!nextToken()) + { + return NULL; + } + } + else + { + return NULL; + } + return n.release(); +} + +wxPluralFormsCalculator* wxPluralFormsCalculator::make(const char* s) +{ + wxPluralFormsCalculatorPtr calculator(new wxPluralFormsCalculator); + if (s != NULL) + { + wxPluralFormsScanner scanner(s); + wxPluralFormsParser p(scanner); + if (!p.parse(*calculator)) + { + return NULL; + } + } + return calculator.release(); +} + + + + +// ---------------------------------------------------------------------------- +// wxMsgCatalogFile corresponds to one disk-file message catalog. +// +// This is a "low-level" class and is used only by wxMsgCatalog +// ---------------------------------------------------------------------------- + +WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxString, wxMessagesHash); + +class wxMsgCatalogFile +{ +public: + // ctor & dtor + wxMsgCatalogFile(); + ~wxMsgCatalogFile(); + + // load the catalog from disk (szDirPrefix corresponds to language) + bool Load(const wxChar *szDirPrefix, const wxChar *szName, + wxPluralFormsCalculatorPtr& rPluralFormsCalculator); + + // fills the hash with string-translation pairs + void FillHash(wxMessagesHash& hash, + const wxString& msgIdCharset, + bool convertEncoding) const; + + // return the charset of the strings in this catalog or empty string if + // none/unknown + wxString GetCharset() const { return m_charset; } + +private: + // this implementation is binary compatible with GNU gettext() version 0.10 + + // an entry in the string table + struct wxMsgTableEntry + { + size_t32 nLen; // length of the string + size_t32 ofsString; // pointer to the string + }; + + // header of a .mo file + struct wxMsgCatalogHeader + { + size_t32 magic, // offset +00: magic id + revision, // +04: revision + numStrings; // +08: number of strings in the file + size_t32 ofsOrigTable, // +0C: start of original string table + ofsTransTable; // +10: start of translated string table + size_t32 nHashSize, // +14: hash table size + ofsHashTable; // +18: offset of hash table start + }; + + // all data is stored here, NULL if no data loaded + size_t8 *m_pData; + + // amount of memory pointed to by m_pData. + size_t32 m_nSize; + + // data description + size_t32 m_numStrings; // number of strings in this domain + wxMsgTableEntry *m_pOrigTable, // pointer to original strings + *m_pTransTable; // translated + + wxString m_charset; // from the message catalog header + + + // swap the 2 halves of 32 bit integer if needed + size_t32 Swap(size_t32 ui) const + { + return m_bSwapped ? (ui << 24) | ((ui & 0xff00) << 8) | + ((ui >> 8) & 0xff00) | (ui >> 24) + : ui; + } + + const char *StringAtOfs(wxMsgTableEntry *pTable, size_t32 n) const + { + const wxMsgTableEntry * const ent = pTable + n; + + // this check could fail for a corrupt message catalog + size_t32 ofsString = Swap(ent->ofsString); + if ( ofsString + Swap(ent->nLen) > m_nSize) + { + return NULL; + } + + return (const char *)(m_pData + ofsString); + } + + bool m_bSwapped; // wrong endianness? + + DECLARE_NO_COPY_CLASS(wxMsgCatalogFile) +}; + + +// ---------------------------------------------------------------------------- +// wxMsgCatalog corresponds to one loaded message catalog. +// +// This is a "low-level" class and is used only by wxLocale (that's why +// it's designed to be stored in a linked list) +// ---------------------------------------------------------------------------- + +class wxMsgCatalog +{ +public: +#if !wxUSE_UNICODE + wxMsgCatalog() { m_conv = NULL; } + ~wxMsgCatalog(); +#endif + + // load the catalog from disk (szDirPrefix corresponds to language) + bool Load(const wxChar *szDirPrefix, const wxChar *szName, + const wxChar *msgIdCharset = NULL, bool bConvertEncoding = false); + + // get name of the catalog + wxString GetName() const { return m_name; } + + // get the translated string: returns NULL if not found + const wxChar *GetString(const wxChar *sz, size_t n = size_t(-1)) const; + + // public variable pointing to the next element in a linked list (or NULL) + wxMsgCatalog *m_pNext; + +private: + wxMessagesHash m_messages; // all messages in the catalog + wxString m_name; // name of the domain + +#if !wxUSE_UNICODE + // the conversion corresponding to this catalog charset if we installed it + // as the global one + wxCSConv *m_conv; +#endif + + wxPluralFormsCalculatorPtr m_pluralFormsCalculator; +}; + +// ---------------------------------------------------------------------------- +// global variables +// ---------------------------------------------------------------------------- + +// the list of the directories to search for message catalog files +static wxArrayString gs_searchPrefixes; + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxMsgCatalogFile class +// ---------------------------------------------------------------------------- + +wxMsgCatalogFile::wxMsgCatalogFile() +{ + m_pData = NULL; + m_nSize = 0; +} + +wxMsgCatalogFile::~wxMsgCatalogFile() +{ + delete [] m_pData; +} + +// return the directories to search for message catalogs under the given +// prefix, separated by wxPATH_SEP +static +wxString GetMsgCatalogSubdirs(const wxChar *prefix, const wxChar *lang) +{ + // Search first in Unix-standard prefix/lang/LC_MESSAGES, then in + // prefix/lang and finally in just prefix. + // + // Note that we use LC_MESSAGES on all platforms and not just Unix, because + // it doesn't cost much to look into one more directory and doing it this + // way has two important benefits: + // a) we don't break compatibility with wx-2.6 and older by stopping to + // look in a directory where the catalogs used to be and thus silently + // breaking apps after they are recompiled against the latest wx + // b) it makes it possible to package app's support files in the same + // way on all target platforms + wxString pathPrefix; + pathPrefix << prefix << wxFILE_SEP_PATH << lang; + + wxString searchPath; + searchPath.reserve(4*pathPrefix.length()); + searchPath << pathPrefix << wxFILE_SEP_PATH << wxT("LC_MESSAGES") << wxPATH_SEP + << prefix << wxFILE_SEP_PATH << wxPATH_SEP + << pathPrefix; + + return searchPath; +} + +// construct the search path for the given language +static wxString GetFullSearchPath(const wxChar *lang) +{ + // first take the entries explicitly added by the program + wxArrayString paths; + paths.reserve(gs_searchPrefixes.size() + 1); + size_t n, + count = gs_searchPrefixes.size(); + for ( n = 0; n < count; n++ ) + { + paths.Add(GetMsgCatalogSubdirs(gs_searchPrefixes[n], lang)); + } + + +#if wxUSE_STDPATHS + // then look in the standard location + const wxString stdp = wxStandardPaths::Get(). + GetLocalizedResourcesDir(lang, wxStandardPaths::ResourceCat_Messages); + + if ( paths.Index(stdp) == wxNOT_FOUND ) + paths.Add(stdp); +#endif // wxUSE_STDPATHS + + // last look in default locations +#ifdef __UNIX__ + // LC_PATH is a standard env var containing the search path for the .mo + // files + const wxChar *pszLcPath = wxGetenv(wxT("LC_PATH")); + if ( pszLcPath ) + { + const wxString lcp = GetMsgCatalogSubdirs(pszLcPath, lang); + if ( paths.Index(lcp) == wxNOT_FOUND ) + paths.Add(lcp); + } + + // also add the one from where wxWin was installed: + wxString wxp = wxGetInstallPrefix(); + if ( !wxp.empty() ) + { + wxp = GetMsgCatalogSubdirs(wxp + _T("/share/locale"), lang); + if ( paths.Index(wxp) == wxNOT_FOUND ) + paths.Add(wxp); + } +#endif // __UNIX__ + + + // finally construct the full search path + wxString searchPath; + searchPath.reserve(500); + count = paths.size(); + for ( n = 0; n < count; n++ ) + { + searchPath += paths[n]; + if ( n != count - 1 ) + searchPath += wxPATH_SEP; + } + + return searchPath; +} + +// open disk file and read in it's contents +bool wxMsgCatalogFile::Load(const wxChar *szDirPrefix, const wxChar *szName, + wxPluralFormsCalculatorPtr& rPluralFormsCalculator) +{ + wxString searchPath; + +#if wxUSE_FONTMAP + // first look for the catalog for this language and the current locale: + // notice that we don't use the system name for the locale as this would + // force us to install catalogs in different locations depending on the + // system but always use the canonical name + wxFontEncoding encSys = wxLocale::GetSystemEncoding(); + if ( encSys != wxFONTENCODING_SYSTEM ) + { + wxString fullname(szDirPrefix); + fullname << _T('.') << wxFontMapperBase::GetEncodingName(encSys); + searchPath << GetFullSearchPath(fullname) << wxPATH_SEP; + } +#endif // wxUSE_FONTMAP + + + searchPath += GetFullSearchPath(szDirPrefix); + const wxChar *sublocale = wxStrchr(szDirPrefix, wxT('_')); + if ( sublocale ) + { + // also add just base locale name: for things like "fr_BE" (belgium + // french) we should use "fr" if no belgium specific message catalogs + // exist + searchPath << wxPATH_SEP + << GetFullSearchPath(wxString(szDirPrefix). + Left((size_t)(sublocale - szDirPrefix))); + } + + // don't give translation errors here because the wxstd catalog might + // not yet be loaded (and it's normal) + // + // (we're using an object because we have several return paths) + + NoTransErr noTransErr; + wxLogVerbose(_("looking for catalog '%s' in path '%s'."), + szName, searchPath.c_str()); + wxLogTrace(TRACE_I18N, _T("Looking for \"%s.mo\" in \"%s\""), + szName, searchPath.c_str()); + + wxFileName fn(szName); + fn.SetExt(_T("mo")); + wxString strFullName; + if ( !wxFindFileInPath(&strFullName, searchPath, fn.GetFullPath()) ) { + wxLogVerbose(_("catalog file for domain '%s' not found."), szName); + wxLogTrace(TRACE_I18N, _T("Catalog \"%s.mo\" not found"), szName); + return false; + } + + // open file + wxLogVerbose(_("using catalog '%s' from '%s'."), szName, strFullName.c_str()); + wxLogTrace(TRACE_I18N, _T("Using catalog \"%s\"."), strFullName.c_str()); + + wxFile fileMsg(strFullName); + if ( !fileMsg.IsOpened() ) + return false; + + // get the file size (assume it is less than 4Gb...) + wxFileOffset lenFile = fileMsg.Length(); + if ( lenFile == wxInvalidOffset ) + return false; + + size_t nSize = wx_truncate_cast(size_t, lenFile); + wxASSERT_MSG( nSize == lenFile + size_t(0), _T("message catalog bigger than 4GB?") ); + + // read the whole file in memory + m_pData = new size_t8[nSize]; + if ( fileMsg.Read(m_pData, nSize) != lenFile ) { + wxDELETEA(m_pData); + return false; + } + + // examine header + bool bValid = nSize + (size_t)0 > sizeof(wxMsgCatalogHeader); + + wxMsgCatalogHeader *pHeader = (wxMsgCatalogHeader *)m_pData; + if ( bValid ) { + // we'll have to swap all the integers if it's true + m_bSwapped = pHeader->magic == MSGCATALOG_MAGIC_SW; + + // check the magic number + bValid = m_bSwapped || pHeader->magic == MSGCATALOG_MAGIC; + } + + if ( !bValid ) { + // it's either too short or has incorrect magic number + wxLogWarning(_("'%s' is not a valid message catalog."), strFullName.c_str()); + + wxDELETEA(m_pData); + return false; + } + + // initialize + m_numStrings = Swap(pHeader->numStrings); + m_pOrigTable = (wxMsgTableEntry *)(m_pData + + Swap(pHeader->ofsOrigTable)); + m_pTransTable = (wxMsgTableEntry *)(m_pData + + Swap(pHeader->ofsTransTable)); + m_nSize = (size_t32)nSize; + + // now parse catalog's header and try to extract catalog charset and + // plural forms formula from it: + + const char* headerData = StringAtOfs(m_pOrigTable, 0); + if (headerData && headerData[0] == 0) + { + // Extract the charset: + wxString header = wxString::FromAscii(StringAtOfs(m_pTransTable, 0)); + int begin = header.Find(wxT("Content-Type: text/plain; charset=")); + if (begin != wxNOT_FOUND) + { + begin += 34; //strlen("Content-Type: text/plain; charset=") + size_t end = header.find('\n', begin); + if (end != size_t(-1)) + { + m_charset.assign(header, begin, end - begin); + if (m_charset == wxT("CHARSET")) + { + // "CHARSET" is not valid charset, but lazy translator + m_charset.Clear(); + } + } + } + // else: incorrectly filled Content-Type header + + // Extract plural forms: + begin = header.Find(wxT("Plural-Forms:")); + if (begin != wxNOT_FOUND) + { + begin += 13; + size_t end = header.find('\n', begin); + if (end != size_t(-1)) + { + wxString pfs(header, begin, end - begin); + wxPluralFormsCalculator* pCalculator = wxPluralFormsCalculator + ::make(pfs.ToAscii()); + if (pCalculator != 0) + { + rPluralFormsCalculator.reset(pCalculator); + } + else + { + wxLogVerbose(_("Cannot parse Plural-Forms:'%s'"), pfs.c_str()); + } + } + } + if (rPluralFormsCalculator.get() == NULL) + { + rPluralFormsCalculator.reset(wxPluralFormsCalculator::make()); + } + } + + // everything is fine + return true; +} + +void wxMsgCatalogFile::FillHash(wxMessagesHash& hash, + const wxString& msgIdCharset, + bool convertEncoding) const +{ +#if wxUSE_UNICODE + // this parameter doesn't make sense, we always must convert encoding in + // Unicode build + convertEncoding = true; +#elif wxUSE_FONTMAP + if ( convertEncoding ) + { + // determine if we need any conversion at all + wxFontEncoding encCat = wxFontMapperBase::GetEncodingFromName(m_charset); + if ( encCat == wxLocale::GetSystemEncoding() ) + { + // no need to convert + convertEncoding = false; + } + } +#endif // wxUSE_UNICODE/wxUSE_FONTMAP + +#if wxUSE_WCHAR_T + // conversion to use to convert catalog strings to the GUI encoding + wxMBConv *inputConv, + *inputConvPtr = NULL; // same as inputConv but safely deleteable + if ( convertEncoding && !m_charset.empty() ) + { + inputConvPtr = + inputConv = new wxCSConv(m_charset); + } + else // no need or not possible to convert the encoding + { +#if wxUSE_UNICODE + // we must somehow convert the narrow strings in the message catalog to + // wide strings, so use the default conversion if we have no charset + inputConv = wxConvCurrent; +#else // !wxUSE_UNICODE + inputConv = NULL; +#endif // wxUSE_UNICODE/!wxUSE_UNICODE + } + + // conversion to apply to msgid strings before looking them up: we only + // need it if the msgids are neither in 7 bit ASCII nor in the same + // encoding as the catalog + wxCSConv *sourceConv = msgIdCharset.empty() || (msgIdCharset == m_charset) + ? NULL + : new wxCSConv(msgIdCharset); + +#elif wxUSE_FONTMAP + wxASSERT_MSG( msgIdCharset.empty(), + _T("non-ASCII msgid languages only supported if wxUSE_WCHAR_T=1") ); + + wxEncodingConverter converter; + if ( convertEncoding ) + { + wxFontEncoding targetEnc = wxFONTENCODING_SYSTEM; + wxFontEncoding enc = wxFontMapperBase::Get()->CharsetToEncoding(m_charset, false); + if ( enc == wxFONTENCODING_SYSTEM ) + { + convertEncoding = false; // unknown encoding + } + else + { + targetEnc = wxLocale::GetSystemEncoding(); + if (targetEnc == wxFONTENCODING_SYSTEM) + { + wxFontEncodingArray a = wxEncodingConverter::GetPlatformEquivalents(enc); + if (a[0] == enc) + // no conversion needed, locale uses native encoding + convertEncoding = false; + if (a.GetCount() == 0) + // we don't know common equiv. under this platform + convertEncoding = false; + targetEnc = a[0]; + } + } + + if ( convertEncoding ) + { + converter.Init(enc, targetEnc); + } + } +#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T + (void)convertEncoding; // get rid of warnings about unused parameter + + for (size_t32 i = 0; i < m_numStrings; i++) + { + const char *data = StringAtOfs(m_pOrigTable, i); + + wxString msgid; +#if wxUSE_UNICODE + msgid = wxString(data, *inputConv); +#else // ASCII + #if wxUSE_WCHAR_T + if ( inputConv && sourceConv ) + msgid = wxString(inputConv->cMB2WC(data), *sourceConv); + else + #endif + msgid = data; +#endif // wxUSE_UNICODE + + data = StringAtOfs(m_pTransTable, i); + size_t length = Swap(m_pTransTable[i].nLen); + size_t offset = 0; + size_t index = 0; + while (offset < length) + { + const char * const str = data + offset; + + wxString msgstr; +#if wxUSE_UNICODE + msgstr = wxString(str, *inputConv); +#elif wxUSE_WCHAR_T + if ( inputConv ) + msgstr = wxString(inputConv->cMB2WC(str), *wxConvUI); + else + msgstr = str; +#else // !wxUSE_WCHAR_T + #if wxUSE_FONTMAP + if ( convertEncoding ) + msgstr = wxString(converter.Convert(str)); + else + #endif + msgstr = str; +#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T + + if ( !msgstr.empty() ) + { + hash[index == 0 ? msgid : msgid + wxChar(index)] = msgstr; + } + + // skip this string + offset += strlen(str) + 1; + ++index; + } + } + +#if wxUSE_WCHAR_T + delete sourceConv; + delete inputConvPtr; +#endif // wxUSE_WCHAR_T +} + + +// ---------------------------------------------------------------------------- +// wxMsgCatalog class +// ---------------------------------------------------------------------------- + +#if !wxUSE_UNICODE +wxMsgCatalog::~wxMsgCatalog() +{ + if ( m_conv ) + { + if ( wxConvUI == m_conv ) + { + // we only change wxConvUI if it points to wxConvLocal so we reset + // it back to it too + wxConvUI = &wxConvLocal; + } + + delete m_conv; + } +} +#endif // !wxUSE_UNICODE + +bool wxMsgCatalog::Load(const wxChar *szDirPrefix, const wxChar *szName, + const wxChar *msgIdCharset, bool bConvertEncoding) +{ + wxMsgCatalogFile file; + + m_name = szName; + + if ( !file.Load(szDirPrefix, szName, m_pluralFormsCalculator) ) + return false; + + file.FillHash(m_messages, msgIdCharset, bConvertEncoding); + +#if !wxUSE_UNICODE && wxUSE_WCHAR_T + // we should use a conversion compatible with the message catalog encoding + // in the GUI if we don't convert the strings to the current conversion but + // as the encoding is global, only change it once, otherwise we could get + // into trouble if we use several message catalogs with different encodings + // + // this is, of course, a hack but it at least allows the program to use + // message catalogs in any encodings without asking the user to change his + // locale + if ( !bConvertEncoding && + !file.GetCharset().empty() && + wxConvUI == &wxConvLocal ) + { + wxConvUI = + m_conv = new wxCSConv(file.GetCharset()); + } +#endif // !wxUSE_UNICODE && wxUSE_WCHAR_T + + return true; +} + +const wxChar *wxMsgCatalog::GetString(const wxChar *sz, size_t n) const +{ + int index = 0; + if (n != size_t(-1)) + { + index = m_pluralFormsCalculator->evaluate(n); + } + wxMessagesHash::const_iterator i; + if (index != 0) + { + i = m_messages.find(wxString(sz) + wxChar(index)); // plural + } + else + { + i = m_messages.find(sz); + } + + if ( i != m_messages.end() ) + { + return i->second.c_str(); + } + else + return NULL; +} + +// ---------------------------------------------------------------------------- +// wxLocale +// ---------------------------------------------------------------------------- + +#include "wx/arrimpl.cpp" +WX_DECLARE_EXPORTED_OBJARRAY(wxLanguageInfo, wxLanguageInfoArray); +WX_DEFINE_OBJARRAY(wxLanguageInfoArray) + +wxLanguageInfoArray *wxLocale::ms_languagesDB = NULL; + +/*static*/ void wxLocale::CreateLanguagesDB() +{ + if (ms_languagesDB == NULL) + { + ms_languagesDB = new wxLanguageInfoArray; + InitLanguagesDB(); + } +} + +/*static*/ void wxLocale::DestroyLanguagesDB() +{ + delete ms_languagesDB; + ms_languagesDB = NULL; +} + + +void wxLocale::DoCommonInit() +{ + m_pszOldLocale = NULL; + + m_pOldLocale = wxSetLocale(this); + + m_pMsgCat = NULL; + m_language = wxLANGUAGE_UNKNOWN; + m_initialized = false; +} + +// NB: this function has (desired) side effect of changing current locale +bool wxLocale::Init(const wxChar *szName, + const wxChar *szShort, + const wxChar *szLocale, + bool bLoadDefault, + bool bConvertEncoding) +{ + wxASSERT_MSG( !m_initialized, + _T("you can't call wxLocale::Init more than once") ); + + m_initialized = true; + m_strLocale = szName; + m_strShort = szShort; + m_bConvertEncoding = bConvertEncoding; + m_language = wxLANGUAGE_UNKNOWN; + + // change current locale (default: same as long name) + if ( szLocale == NULL ) + { + // the argument to setlocale() + szLocale = szShort; + + wxCHECK_MSG( szLocale, false, _T("no locale to set in wxLocale::Init()") ); + } + +#ifdef __WXWINCE__ + // FIXME: I'm guessing here + wxChar localeName[256]; + int ret = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SLANGUAGE, localeName, + 256); + if (ret != 0) + { + m_pszOldLocale = wxStrdup(localeName); + } + else + m_pszOldLocale = NULL; + + // TODO: how to find languageId + // SetLocaleInfo(languageId, SORT_DEFAULT, localeName); +#else + wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, szLocale); + if ( oldLocale ) + m_pszOldLocale = wxStrdup(oldLocale); + else + m_pszOldLocale = NULL; +#endif + + if ( m_pszOldLocale == NULL ) + wxLogError(_("locale '%s' can not be set."), szLocale); + + // the short name will be used to look for catalog files as well, + // so we need something here + if ( m_strShort.empty() ) { + // FIXME I don't know how these 2 letter abbreviations are formed, + // this wild guess is surely wrong + if ( szLocale && szLocale[0] ) + { + m_strShort += (wxChar)wxTolower(szLocale[0]); + if ( szLocale[1] ) + m_strShort += (wxChar)wxTolower(szLocale[1]); + } + } + + // load the default catalog with wxWidgets standard messages + m_pMsgCat = NULL; + bool bOk = true; + if ( bLoadDefault ) + { + bOk = AddCatalog(wxT("wxstd")); + + // there may be a catalog with toolkit specific overrides, it is not + // an error if this does not exist + if ( bOk ) + { + wxString port(wxPlatformInfo::Get().GetPortIdName()); + if ( !port.empty() ) + { + AddCatalog(port.BeforeFirst(wxT('/')).MakeLower()); + } + } + } + + return bOk; +} + + +#if defined(__UNIX__) && wxUSE_UNICODE && !defined(__WXMAC__) +static wxWCharBuffer wxSetlocaleTryUTF(int c, const wxChar *lc) +{ + wxMB2WXbuf l = wxSetlocale(c, lc); + if ( !l && lc && lc[0] != 0 ) + { + wxString buf(lc); + wxString buf2; + buf2 = buf + wxT(".UTF-8"); + l = wxSetlocale(c, buf2.c_str()); + if ( !l ) + { + buf2 = buf + wxT(".utf-8"); + l = wxSetlocale(c, buf2.c_str()); + } + if ( !l ) + { + buf2 = buf + wxT(".UTF8"); + l = wxSetlocale(c, buf2.c_str()); + } + if ( !l ) + { + buf2 = buf + wxT(".utf8"); + l = wxSetlocale(c, buf2.c_str()); + } + } + return l; +} +#else +#define wxSetlocaleTryUTF(c, lc) wxSetlocale(c, lc) +#endif + +bool wxLocale::Init(int language, int flags) +{ + int lang = language; + if (lang == wxLANGUAGE_DEFAULT) + { + // auto detect the language + lang = GetSystemLanguage(); + } + + // We failed to detect system language, so we will use English: + if (lang == wxLANGUAGE_UNKNOWN) + { + return false; + } + + const wxLanguageInfo *info = GetLanguageInfo(lang); + + // Unknown language: + if (info == NULL) + { + wxLogError(wxT("Unknown language %i."), lang); + return false; + } + + wxString name = info->Description; + wxString canonical = info->CanonicalName; + wxString locale; + + // Set the locale: +#if defined(__OS2__) + wxMB2WXbuf retloc = wxSetlocale(LC_ALL , wxEmptyString); +#elif defined(__UNIX__) && !defined(__WXMAC__) + if (language != wxLANGUAGE_DEFAULT) + locale = info->CanonicalName; + + wxMB2WXbuf retloc = wxSetlocaleTryUTF(LC_ALL, locale); + + const wxString langOnly = locale.Left(2); + if ( !retloc ) + { + // Some C libraries don't like xx_YY form and require xx only + retloc = wxSetlocaleTryUTF(LC_ALL, langOnly); + } + +#if wxUSE_FONTMAP + // some systems (e.g. FreeBSD and HP-UX) don't have xx_YY aliases but + // require the full xx_YY.encoding form, so try using UTF-8 because this is + // the only thing we can do generically + // + // TODO: add encodings applicable to each language to the lang DB and try + // them all in turn here + if ( !retloc ) + { + const wxChar **names = + wxFontMapperBase::GetAllEncodingNames(wxFONTENCODING_UTF8); + while ( *names ) + { + retloc = wxSetlocale(LC_ALL, locale + _T('.') + *names++); + if ( retloc ) + break; + } + } +#endif // wxUSE_FONTMAP + + if ( !retloc ) + { + // Some C libraries (namely glibc) still use old ISO 639, + // so will translate the abbrev for them + wxString localeAlt; + if ( langOnly == wxT("he") ) + localeAlt = wxT("iw") + locale.Mid(3); + else if ( langOnly == wxT("id") ) + localeAlt = wxT("in") + locale.Mid(3); + else if ( langOnly == wxT("yi") ) + localeAlt = wxT("ji") + locale.Mid(3); + else if ( langOnly == wxT("nb") ) + localeAlt = wxT("no_NO"); + else if ( langOnly == wxT("nn") ) + localeAlt = wxT("no_NY"); + + if ( !localeAlt.empty() ) + { + retloc = wxSetlocaleTryUTF(LC_ALL, localeAlt); + if ( !retloc ) + retloc = wxSetlocaleTryUTF(LC_ALL, localeAlt.Left(2)); + } + } + + if ( !retloc ) + { + wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str()); + return false; + } + +#ifdef __AIX__ + // at least in AIX 5.2 libc is buggy and the string returned from setlocale(LC_ALL) + // can't be passed back to it because it returns 6 strings (one for each locale + // category), i.e. for C locale we get back "C C C C C C" + // + // this contradicts IBM own docs but this is not of much help, so just work around + // it in the crudest possible manner + wxChar *p = wxStrchr((wxChar *)retloc, _T(' ')); + if ( p ) + *p = _T('\0'); +#endif // __AIX__ + +#elif defined(__WIN32__) + + #if wxUSE_UNICODE && (defined(__VISUALC__) || defined(__MINGW32__)) + // NB: setlocale() from msvcrt.dll (used by VC++ and Mingw) + // can't set locale to language that can only be written using + // Unicode. Therefore wxSetlocale call failed, but we don't want + // to report it as an error -- so that at least message catalogs + // can be used. Watch for code marked with + // #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS bellow. + #define SETLOCALE_FAILS_ON_UNICODE_LANGS + #endif + +#if !wxUSE_UNICODE + const +#endif + wxMB2WXbuf retloc = wxT("C"); + if (language != wxLANGUAGE_DEFAULT) + { + if (info->WinLang == 0) + { + wxLogWarning(wxT("Locale '%s' not supported by OS."), name.c_str()); + // retloc already set to "C" + } + else + { + int codepage + #ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS + = -1 + #endif + ; + wxUint32 lcid = MAKELCID(MAKELANGID(info->WinLang, info->WinSublang), + SORT_DEFAULT); + // FIXME +#ifndef __WXWINCE__ + SetThreadLocale(lcid); +#endif + // NB: we must translate LCID to CRT's setlocale string ourselves, + // because SetThreadLocale does not modify change the + // interpretation of setlocale(LC_ALL, "") call: + wxChar buffer[256]; + buffer[0] = wxT('\0'); + GetLocaleInfo(lcid, LOCALE_SENGLANGUAGE, buffer, 256); + locale << buffer; + if (GetLocaleInfo(lcid, LOCALE_SENGCOUNTRY, buffer, 256) > 0) + locale << wxT("_") << buffer; + if (GetLocaleInfo(lcid, LOCALE_IDEFAULTANSICODEPAGE, buffer, 256) > 0) + { + codepage = wxAtoi(buffer); + if (codepage != 0) + locale << wxT(".") << buffer; + } + if (locale.empty()) + { + wxLogLastError(wxT("SetThreadLocale")); + wxLogError(wxT("Cannot set locale to language %s."), name.c_str()); + return false; + } + else + { + // FIXME +#ifndef __WXWINCE__ + retloc = wxSetlocale(LC_ALL, locale); +#endif +#ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS + if (codepage == 0 && (const wxChar*)retloc == NULL) + { + retloc = wxT("C"); + } +#endif + } + } + } + else + { + // FIXME +#ifndef __WXWINCE__ + retloc = wxSetlocale(LC_ALL, wxEmptyString); +#else + retloc = NULL; +#endif +#ifdef SETLOCALE_FAILS_ON_UNICODE_LANGS + if ((const wxChar*)retloc == NULL) + { + wxChar buffer[16]; + if (GetLocaleInfo(LOCALE_USER_DEFAULT, + LOCALE_IDEFAULTANSICODEPAGE, buffer, 16) > 0 && + wxStrcmp(buffer, wxT("0")) == 0) + { + retloc = wxT("C"); + } + } +#endif + } + + if ( !retloc ) + { + wxLogError(wxT("Cannot set locale to language %s."), name.c_str()); + return false; + } +#elif defined(__WXMAC__) + if (lang == wxLANGUAGE_DEFAULT) + locale = wxEmptyString; + else + locale = info->CanonicalName; + + wxMB2WXbuf retloc = wxSetlocale(LC_ALL, locale); + + if ( !retloc ) + { + // Some C libraries don't like xx_YY form and require xx only + retloc = wxSetlocale(LC_ALL, locale.Mid(0,2)); + } + if ( !retloc ) + { + wxLogError(wxT("Cannot set locale to '%s'."), locale.c_str()); + return false; + } +#else + wxUnusedVar(flags); + return false; + #define WX_NO_LOCALE_SUPPORT +#endif + +#ifndef WX_NO_LOCALE_SUPPORT + wxChar *szLocale = retloc ? wxStrdup(retloc) : NULL; + bool ret = Init(name, canonical, szLocale, + (flags & wxLOCALE_LOAD_DEFAULT) != 0, + (flags & wxLOCALE_CONV_ENCODING) != 0); + free(szLocale); + + if (IsOk()) // setlocale() succeeded + m_language = lang; + + return ret; +#endif // !WX_NO_LOCALE_SUPPORT +} + + + +void wxLocale::AddCatalogLookupPathPrefix(const wxString& prefix) +{ + if ( gs_searchPrefixes.Index(prefix) == wxNOT_FOUND ) + { + gs_searchPrefixes.Add(prefix); + } + //else: already have it +} + +/*static*/ int wxLocale::GetSystemLanguage() +{ + CreateLanguagesDB(); + + // init i to avoid compiler warning + size_t i = 0, + count = ms_languagesDB->GetCount(); + +#if defined(__UNIX__) && !defined(__WXMAC__) + // first get the string identifying the language from the environment + wxString langFull; + if (!wxGetEnv(wxT("LC_ALL"), &langFull) && + !wxGetEnv(wxT("LC_MESSAGES"), &langFull) && + !wxGetEnv(wxT("LANG"), &langFull)) + { + // no language specified, treat it as English + return wxLANGUAGE_ENGLISH_US; + } + + if ( langFull == _T("C") || langFull == _T("POSIX") ) + { + // default C locale is English too + return wxLANGUAGE_ENGLISH_US; + } + + // the language string has the following form + // + // lang[_LANG][.encoding][@modifier] + // + // (see environ(5) in the Open Unix specification) + // + // where lang is the primary language, LANG is a sublang/territory, + // encoding is the charset to use and modifier "allows the user to select + // a specific instance of localization data within a single category" + // + // for example, the following strings are valid: + // fr + // fr_FR + // de_DE.iso88591 + // de_DE@euro + // de_DE.iso88591@euro + + // for now we don't use the encoding, although we probably should (doing + // translations of the msg catalogs on the fly as required) (TODO) + // + // we need the modified for languages like Valencian: ca_ES@valencia + // though, remember it + wxString modifier; + size_t posModifier = langFull.find_first_of(_T("@")); + if ( posModifier != wxString::npos ) + modifier = langFull.Mid(posModifier); + + size_t posEndLang = langFull.find_first_of(_T("@.")); + if ( posEndLang != wxString::npos ) + { + langFull.Truncate(posEndLang); + } + + // in addition to the format above, we also can have full language names + // in LANG env var - for example, SuSE is known to use LANG="german" - so + // check for this + + // do we have just the language (or sublang too)? + bool justLang = langFull.length() == LEN_LANG; + if ( justLang || + (langFull.length() == LEN_FULL && langFull[LEN_LANG] == wxT('_')) ) + { + // 0. Make sure the lang is according to latest ISO 639 + // (this is necessary because glibc uses iw and in instead + // of he and id respectively). + + // the language itself (second part is the dialect/sublang) + wxString langOrig = ExtractLang(langFull); + + wxString lang; + if ( langOrig == wxT("iw")) + lang = _T("he"); + else if (langOrig == wxT("in")) + lang = wxT("id"); + else if (langOrig == wxT("ji")) + lang = wxT("yi"); + else if (langOrig == wxT("no_NO")) + lang = wxT("nb_NO"); + else if (langOrig == wxT("no_NY")) + lang = wxT("nn_NO"); + else if (langOrig == wxT("no")) + lang = wxT("nb_NO"); + else + lang = langOrig; + + // did we change it? + if ( lang != langOrig ) + { + langFull = lang + ExtractNotLang(langFull); + } + + // 1. Try to find the language either as is: + // a) With modifier if set + if ( !modifier.empty() ) + { + wxString langFullWithModifier = langFull + modifier; + for ( i = 0; i < count; i++ ) + { + if ( ms_languagesDB->Item(i).CanonicalName == langFullWithModifier ) + break; + } + } + + // b) Without modifier + if ( modifier.empty() || i == count ) + { + for ( i = 0; i < count; i++ ) + { + if ( ms_languagesDB->Item(i).CanonicalName == langFull ) + break; + } + } + + // 2. If langFull is of the form xx_YY, try to find xx: + if ( i == count && !justLang ) + { + for ( i = 0; i < count; i++ ) + { + if ( ms_languagesDB->Item(i).CanonicalName == lang ) + { + break; + } + } + } + + // 3. If langFull is of the form xx, try to find any xx_YY record: + if ( i == count && justLang ) + { + for ( i = 0; i < count; i++ ) + { + if ( ExtractLang(ms_languagesDB->Item(i).CanonicalName) + == langFull ) + { + break; + } + } + } + } + else // not standard format + { + // try to find the name in verbose description + for ( i = 0; i < count; i++ ) + { + if (ms_languagesDB->Item(i).Description.CmpNoCase(langFull) == 0) + { + break; + } + } + } +#elif defined(__WXMAC__) + const wxChar * lc = NULL ; + long lang = GetScriptVariable( smSystemScript, smScriptLang) ; + switch( GetScriptManagerVariable( smRegionCode ) ) { + case verUS : + lc = wxT("en_US") ; + break ; + case verFrance : + lc = wxT("fr_FR") ; + break ; + case verBritain : + lc = wxT("en_GB") ; + break ; + case verGermany : + lc = wxT("de_DE") ; + break ; + case verItaly : + lc = wxT("it_IT") ; + break ; + case verNetherlands : + lc = wxT("nl_NL") ; + break ; + case verFlemish : + lc = wxT("nl_BE") ; + break ; + case verSweden : + lc = wxT("sv_SE" ); + break ; + case verSpain : + lc = wxT("es_ES" ); + break ; + case verDenmark : + lc = wxT("da_DK") ; + break ; + case verPortugal : + lc = wxT("pt_PT") ; + break ; + case verFrCanada: + lc = wxT("fr_CA") ; + break ; + case verNorway: + lc = wxT("nb_NO") ; + break ; + case verIsrael: + lc = wxT("iw_IL") ; + break ; + case verJapan: + lc = wxT("ja_JP") ; + break ; + case verAustralia: + lc = wxT("en_AU") ; + break ; + case verArabic: + lc = wxT("ar") ; + break ; + case verFinland: + lc = wxT("fi_FI") ; + break ; + case verFrSwiss: + lc = wxT("fr_CH") ; + break ; + case verGrSwiss: + lc = wxT("de_CH") ; + break ; + case verGreece: + lc = wxT("el_GR") ; + break ; + case verIceland: + lc = wxT("is_IS") ; + break ; + case verMalta: + lc = wxT("mt_MT") ; + break ; + case verCyprus: + // _CY is not part of wx, so we have to translate according to the system language + if ( lang == langGreek ) { + lc = wxT("el_GR") ; + } + else if ( lang == langTurkish ) { + lc = wxT("tr_TR") ; + } + break ; + case verTurkey: + lc = wxT("tr_TR") ; + break ; + case verYugoCroatian: + lc = wxT("hr_HR") ; + break ; + case verIndiaHindi: + lc = wxT("hi_IN") ; + break ; + case verPakistanUrdu: + lc = wxT("ur_PK") ; + break ; + case verTurkishModified: + lc = wxT("tr_TR") ; + break ; + case verItalianSwiss: + lc = wxT("it_CH") ; + break ; + case verInternational: + lc = wxT("en") ; + break ; + case verRomania: + lc = wxT("ro_RO") ; + break ; + case verGreecePoly: + lc = wxT("el_GR") ; + break ; + case verLithuania: + lc = wxT("lt_LT") ; + break ; + case verPoland: + lc = wxT("pl_PL") ; + break ; + case verMagyar : + case verHungary: + lc = wxT("hu_HU") ; + break ; + case verEstonia: + lc = wxT("et_EE") ; + break ; + case verLatvia: + lc = wxT("lv_LV") ; + break ; + case verSami: + lc = wxT("se_NO") ; + break ; + case verFaroeIsl: + lc = wxT("fo_FO") ; + break ; + case verIran: + lc = wxT("fa_IR") ; + break ; + case verRussia: + lc = wxT("ru_RU") ; + break ; + case verIreland: + lc = wxT("ga_IE") ; + break ; + case verKorea: + lc = wxT("ko_KR") ; + break ; + case verChina: + lc = wxT("zh_CN") ; + break ; + case verTaiwan: + lc = wxT("zh_TW") ; + break ; + case verThailand: + lc = wxT("th_TH") ; + break ; + case verCzech: + lc = wxT("cs_CZ") ; + break ; + case verSlovak: + lc = wxT("sk_SK") ; + break ; + case verBengali: + lc = wxT("bn") ; + break ; + case verByeloRussian: + lc = wxT("be_BY") ; + break ; + case verUkraine: + lc = wxT("uk_UA") ; + break ; + case verGreeceAlt: + lc = wxT("el_GR") ; + break ; + case verSerbian: + lc = wxT("sr_YU") ; + break ; + case verSlovenian: + lc = wxT("sl_SI") ; + break ; + case verMacedonian: + lc = wxT("mk_MK") ; + break ; + case verCroatia: + lc = wxT("hr_HR") ; + break ; + case verBrazil: + lc = wxT("pt_BR ") ; + break ; + case verBulgaria: + lc = wxT("bg_BG") ; + break ; + case verCatalonia: + lc = wxT("ca_ES") ; + break ; + case verScottishGaelic: + lc = wxT("gd") ; + break ; + case verManxGaelic: + lc = wxT("gv") ; + break ; + case verBreton: + lc = wxT("br") ; + break ; + case verNunavut: + lc = wxT("iu_CA") ; + break ; + case verWelsh: + lc = wxT("cy") ; + break ; + case verIrishGaelicScript: + lc = wxT("ga_IE") ; + break ; + case verEngCanada: + lc = wxT("en_CA") ; + break ; + case verBhutan: + lc = wxT("dz_BT") ; + break ; + case verArmenian: + lc = wxT("hy_AM") ; + break ; + case verGeorgian: + lc = wxT("ka_GE") ; + break ; + case verSpLatinAmerica: + lc = wxT("es_AR") ; + break ; + case verTonga: + lc = wxT("to_TO" ); + break ; + case verFrenchUniversal: + lc = wxT("fr_FR") ; + break ; + case verAustria: + lc = wxT("de_AT") ; + break ; + case verGujarati: + lc = wxT("gu_IN") ; + break ; + case verPunjabi: + lc = wxT("pa") ; + break ; + case verIndiaUrdu: + lc = wxT("ur_IN") ; + break ; + case verVietnam: + lc = wxT("vi_VN") ; + break ; + case verFrBelgium: + lc = wxT("fr_BE") ; + break ; + case verUzbek: + lc = wxT("uz_UZ") ; + break ; + case verSingapore: + lc = wxT("zh_SG") ; + break ; + case verNynorsk: + lc = wxT("nn_NO") ; + break ; + case verAfrikaans: + lc = wxT("af_ZA") ; + break ; + case verEsperanto: + lc = wxT("eo") ; + break ; + case verMarathi: + lc = wxT("mr_IN") ; + break ; + case verTibetan: + lc = wxT("bo") ; + break ; + case verNepal: + lc = wxT("ne_NP") ; + break ; + case verGreenland: + lc = wxT("kl_GL") ; + break ; + default : + break ; + } + if ( !lc ) + return wxLANGUAGE_UNKNOWN; + for ( i = 0; i < count; i++ ) + { + if ( ms_languagesDB->Item(i).CanonicalName == lc ) + { + break; + } + } + +#elif defined(__WIN32__) + LCID lcid = GetUserDefaultLCID(); + if ( lcid != 0 ) + { + wxUint32 lang = PRIMARYLANGID(LANGIDFROMLCID(lcid)); + wxUint32 sublang = SUBLANGID(LANGIDFROMLCID(lcid)); + + for ( i = 0; i < count; i++ ) + { + if (ms_languagesDB->Item(i).WinLang == lang && + ms_languagesDB->Item(i).WinSublang == sublang) + { + break; + } + } + } + //else: leave wxlang == wxLANGUAGE_UNKNOWN +#endif // Unix/Win32 + + if ( i < count ) + { + // we did find a matching entry, use it + return ms_languagesDB->Item(i).Language; + } + + // no info about this language in the database + return wxLANGUAGE_UNKNOWN; +} + +// ---------------------------------------------------------------------------- +// encoding stuff +// ---------------------------------------------------------------------------- + +// this is a bit strange as under Windows we get the encoding name using its +// numeric value and under Unix we do it the other way round, but this just +// reflects the way different systems provide the encoding info + +/* static */ +wxString wxLocale::GetSystemEncodingName() +{ + wxString encname; + +#if defined(__WIN32__) && !defined(__WXMICROWIN__) + // FIXME: what is the error return value for GetACP()? + UINT codepage = ::GetACP(); + encname.Printf(_T("windows-%u"), codepage); +#elif defined(__WXMAC__) + // default is just empty string, this resolves to the default system + // encoding later +#elif defined(__UNIX_LIKE__) + +#if defined(HAVE_LANGINFO_H) && defined(CODESET) + // GNU libc provides current character set this way (this conforms + // to Unix98) + char *oldLocale = strdup(setlocale(LC_CTYPE, NULL)); + setlocale(LC_CTYPE, ""); + const char *alang = nl_langinfo(CODESET); + setlocale(LC_CTYPE, oldLocale); + free(oldLocale); + + if ( alang ) + { + encname = wxString::FromAscii( alang ); + } + else // nl_langinfo() failed +#endif // HAVE_LANGINFO_H + { + // if we can't get at the character set directly, try to see if it's in + // the environment variables (in most cases this won't work, but I was + // out of ideas) + char *lang = getenv( "LC_ALL"); + char *dot = lang ? strchr(lang, '.') : (char *)NULL; + if (!dot) + { + lang = getenv( "LC_CTYPE" ); + if ( lang ) + dot = strchr(lang, '.' ); + } + if (!dot) + { + lang = getenv( "LANG"); + if ( lang ) + dot = strchr(lang, '.'); + } + + if ( dot ) + { + encname = wxString::FromAscii( dot+1 ); + } + } +#endif // Win32/Unix + + return encname; +} + +/* static */ +wxFontEncoding wxLocale::GetSystemEncoding() +{ +#if defined(__WIN32__) && !defined(__WXMICROWIN__) + UINT codepage = ::GetACP(); + + // wxWidgets only knows about CP1250-1257, 874, 932, 936, 949, 950 + if ( codepage >= 1250 && codepage <= 1257 ) + { + return (wxFontEncoding)(wxFONTENCODING_CP1250 + codepage - 1250); + } + + if ( codepage == 874 ) + { + return wxFONTENCODING_CP874; + } + + if ( codepage == 932 ) + { + return wxFONTENCODING_CP932; + } + + if ( codepage == 936 ) + { + return wxFONTENCODING_CP936; + } + + if ( codepage == 949 ) + { + return wxFONTENCODING_CP949; + } + + if ( codepage == 950 ) + { + return wxFONTENCODING_CP950; + } +#elif defined(__WXMAC__) + TextEncoding encoding = 0 ; +#if TARGET_CARBON + encoding = CFStringGetSystemEncoding() ; +#else + UpgradeScriptInfoToTextEncoding ( smSystemScript , kTextLanguageDontCare , kTextRegionDontCare , NULL , &encoding ) ; +#endif + return wxMacGetFontEncFromSystemEnc( encoding ) ; +#elif defined(__UNIX_LIKE__) && wxUSE_FONTMAP + const wxString encname = GetSystemEncodingName(); + if ( !encname.empty() ) + { + wxFontEncoding enc = wxFontMapperBase::GetEncodingFromName(encname); + + // on some modern Linux systems (RedHat 8) the default system locale + // is UTF8 -- but it isn't supported by wxGTK1 in ANSI build at all so + // don't even try to use it in this case +#if !wxUSE_UNICODE && \ + ((defined(__WXGTK__) && !defined(__WXGTK20__)) || defined(__WXMOTIF__)) + if ( enc == wxFONTENCODING_UTF8 ) + { + // the most similar supported encoding... + enc = wxFONTENCODING_ISO8859_1; + } +#endif // !wxUSE_UNICODE + + // GetEncodingFromName() returns wxFONTENCODING_DEFAULT for C locale + // (a.k.a. US-ASCII) which is arguably a bug but keep it like this for + // backwards compatibility and just take care to not return + // wxFONTENCODING_DEFAULT from here as this surely doesn't make sense + if ( enc == wxFONTENCODING_DEFAULT ) + { + // we don't have wxFONTENCODING_ASCII, so use the closest one + return wxFONTENCODING_ISO8859_1; + } + + if ( enc != wxFONTENCODING_MAX ) + { + return enc; + } + //else: return wxFONTENCODING_SYSTEM below + } +#endif // Win32/Unix + + return wxFONTENCODING_SYSTEM; +} + +/* static */ +void wxLocale::AddLanguage(const wxLanguageInfo& info) +{ + CreateLanguagesDB(); + ms_languagesDB->Add(info); +} + +/* static */ +const wxLanguageInfo *wxLocale::GetLanguageInfo(int lang) +{ + CreateLanguagesDB(); + + // calling GetLanguageInfo(wxLANGUAGE_DEFAULT) is a natural thing to do, so + // make it work + if ( lang == wxLANGUAGE_DEFAULT ) + lang = GetSystemLanguage(); + + const size_t count = ms_languagesDB->GetCount(); + for ( size_t i = 0; i < count; i++ ) + { + if ( ms_languagesDB->Item(i).Language == lang ) + { + // We need to create a temporary here in order to make this work with BCC in final build mode + wxLanguageInfo *ptr = &ms_languagesDB->Item(i); + return ptr; + } + } + + return NULL; +} + +/* static */ +wxString wxLocale::GetLanguageName(int lang) +{ + const wxLanguageInfo *info = GetLanguageInfo(lang); + if ( !info ) + return wxEmptyString; + else + return info->Description; +} + +/* static */ +const wxLanguageInfo *wxLocale::FindLanguageInfo(const wxString& locale) +{ + CreateLanguagesDB(); + + const wxLanguageInfo *infoRet = NULL; + + const size_t count = ms_languagesDB->GetCount(); + for ( size_t i = 0; i < count; i++ ) + { + const wxLanguageInfo *info = &ms_languagesDB->Item(i); + + if ( wxStricmp(locale, info->CanonicalName) == 0 || + wxStricmp(locale, info->Description) == 0 ) + { + // exact match, stop searching + infoRet = info; + break; + } + + if ( wxStricmp(locale, info->CanonicalName.BeforeFirst(_T('_'))) == 0 ) + { + // a match -- but maybe we'll find an exact one later, so continue + // looking + // + // OTOH, maybe we had already found a language match and in this + // case don't overwrite it becauce the entry for the default + // country always appears first in ms_languagesDB + if ( !infoRet ) + infoRet = info; + } + } + + return infoRet; +} + +wxString wxLocale::GetSysName() const +{ + // FIXME +#ifndef __WXWINCE__ + return wxSetlocale(LC_ALL, NULL); +#else + return wxEmptyString; +#endif +} + +// clean up +wxLocale::~wxLocale() +{ + // free memory + wxMsgCatalog *pTmpCat; + while ( m_pMsgCat != NULL ) { + pTmpCat = m_pMsgCat; + m_pMsgCat = m_pMsgCat->m_pNext; + delete pTmpCat; + } + + // restore old locale pointer + wxSetLocale(m_pOldLocale); + + // FIXME +#ifndef __WXWINCE__ + wxSetlocale(LC_ALL, m_pszOldLocale); +#endif + free((wxChar *)m_pszOldLocale); // const_cast +} + +// get the translation of given string in current locale +const wxChar *wxLocale::GetString(const wxChar *szOrigString, + const wxChar *szDomain) const +{ + return GetString(szOrigString, szOrigString, size_t(-1), szDomain); +} + +const wxChar *wxLocale::GetString(const wxChar *szOrigString, + const wxChar *szOrigString2, + size_t n, + const wxChar *szDomain) const +{ + if ( wxIsEmpty(szOrigString) ) + return wxEmptyString; + + const wxChar *pszTrans = NULL; + wxMsgCatalog *pMsgCat; + + if ( szDomain != NULL && szDomain[0] ) + { + pMsgCat = FindCatalog(szDomain); + + // does the catalog exist? + if ( pMsgCat != NULL ) + pszTrans = pMsgCat->GetString(szOrigString, n); + } + else + { + // search in all domains + for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) + { + pszTrans = pMsgCat->GetString(szOrigString, n); + if ( pszTrans != NULL ) // take the first found + break; + } + } + + if ( pszTrans == NULL ) + { +#ifdef __WXDEBUG__ + if ( !NoTransErr::Suppress() ) + { + NoTransErr noTransErr; + + wxLogTrace(TRACE_I18N, + _T("string \"%s\"[%ld] not found in %slocale '%s'."), + szOrigString, (long)n, + szDomain ? wxString::Format(_T("domain '%s' "), szDomain).c_str() + : _T(""), + m_strLocale.c_str()); + } +#endif // __WXDEBUG__ + + if (n == size_t(-1)) + return szOrigString; + else + return n == 1 ? szOrigString : szOrigString2; + } + + return pszTrans; +} + +wxString wxLocale::GetHeaderValue( const wxChar* szHeader, + const wxChar* szDomain ) const +{ + if ( wxIsEmpty(szHeader) ) + return wxEmptyString; + + wxChar const * pszTrans = NULL; + wxMsgCatalog *pMsgCat; + + if ( szDomain != NULL ) + { + pMsgCat = FindCatalog(szDomain); + + // does the catalog exist? + if ( pMsgCat == NULL ) + return wxEmptyString; + + pszTrans = pMsgCat->GetString(wxEmptyString, (size_t)-1); + } + else + { + // search in all domains + for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) + { + pszTrans = pMsgCat->GetString(wxEmptyString, (size_t)-1); + if ( pszTrans != NULL ) // take the first found + break; + } + } + + if ( wxIsEmpty(pszTrans) ) + return wxEmptyString; + + wxChar const * pszFound = wxStrstr(pszTrans, szHeader); + if ( pszFound == NULL ) + return wxEmptyString; + + pszFound += wxStrlen(szHeader) + 2 /* ': ' */; + + // Every header is separated by \n + + wxChar const * pszEndLine = wxStrchr(pszFound, wxT('\n')); + if ( pszEndLine == NULL ) pszEndLine = pszFound + wxStrlen(pszFound); + + + // wxString( wxChar*, length); + wxString retVal( pszFound, pszEndLine - pszFound ); + + return retVal; +} + + +// find catalog by name in a linked list, return NULL if !found +wxMsgCatalog *wxLocale::FindCatalog(const wxChar *szDomain) const +{ + // linear search in the linked list + wxMsgCatalog *pMsgCat; + for ( pMsgCat = m_pMsgCat; pMsgCat != NULL; pMsgCat = pMsgCat->m_pNext ) + { + if ( wxStricmp(pMsgCat->GetName(), szDomain) == 0 ) + return pMsgCat; + } + + return NULL; +} + +// check if the given locale is provided by OS and C run time +/* static */ +bool wxLocale::IsAvailable(int lang) +{ + const wxLanguageInfo *info = wxLocale::GetLanguageInfo(lang); + wxCHECK_MSG( info, false, _T("invalid language") ); + +#if defined(__WIN32__) + if ( !info->WinLang ) + return false; + + if ( !::IsValidLocale + ( + MAKELCID(MAKELANGID(info->WinLang, info->WinSublang), + SORT_DEFAULT), + LCID_INSTALLED + ) ) + return false; + +#elif defined(__UNIX__) + + // Test if setting the locale works, then set it back. + wxMB2WXbuf oldLocale = wxSetlocale(LC_ALL, wxEmptyString); + wxMB2WXbuf tmp = wxSetlocaleTryUTF(LC_ALL, info->CanonicalName); + if ( !tmp ) + { + // Some C libraries don't like xx_YY form and require xx only + tmp = wxSetlocaleTryUTF(LC_ALL, info->CanonicalName.Left(2)); + if ( !tmp ) + return false; + } + // restore the original locale + wxSetlocale(LC_ALL, oldLocale); +#endif + + return true; +} + +// check if the given catalog is loaded +bool wxLocale::IsLoaded(const wxChar *szDomain) const +{ + return FindCatalog(szDomain) != NULL; +} + +// add a catalog to our linked list +bool wxLocale::AddCatalog(const wxChar *szDomain) +{ + return AddCatalog(szDomain, wxLANGUAGE_ENGLISH_US, NULL); +} + +// add a catalog to our linked list +bool wxLocale::AddCatalog(const wxChar *szDomain, + wxLanguage msgIdLanguage, + const wxChar *msgIdCharset) + +{ + wxMsgCatalog *pMsgCat = new wxMsgCatalog; + + if ( pMsgCat->Load(m_strShort, szDomain, msgIdCharset, m_bConvertEncoding) ) { + // add it to the head of the list so that in GetString it will + // be searched before the catalogs added earlier + pMsgCat->m_pNext = m_pMsgCat; + m_pMsgCat = pMsgCat; + + return true; + } + else { + // don't add it because it couldn't be loaded anyway + delete pMsgCat; + + // It is OK to not load catalog if the msgid language and m_language match, + // in which case we can directly display the texts embedded in program's + // source code: + if (m_language == msgIdLanguage) + return true; + + // If there's no exact match, we may still get partial match where the + // (basic) language is same, but the country differs. For example, it's + // permitted to use en_US strings from sources even if m_language is en_GB: + const wxLanguageInfo *msgIdLangInfo = GetLanguageInfo(msgIdLanguage); + if ( msgIdLangInfo && + msgIdLangInfo->CanonicalName.Mid(0, 2) == m_strShort.Mid(0, 2) ) + { + return true; + } + + return false; + } +} + +// ---------------------------------------------------------------------------- +// accessors for locale-dependent data +// ---------------------------------------------------------------------------- + +#ifdef __WXMSW__ + +/* static */ +wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) +{ + wxUint32 lcid = LOCALE_USER_DEFAULT; + + if (wxGetLocale()) + { + const wxLanguageInfo *info = GetLanguageInfo(wxGetLocale()->GetLanguage()); + if (info) + { ; + lcid = MAKELCID(MAKELANGID(info->WinLang, info->WinSublang), + SORT_DEFAULT); + } + } + + wxString str; + wxChar buffer[256]; + size_t count; + buffer[0] = wxT('\0'); + switch (index) + { + case wxLOCALE_DECIMAL_POINT: + count = ::GetLocaleInfo(lcid, LOCALE_SDECIMAL, buffer, 256); + if (!count) + str << wxT("."); + else + str << buffer; + break; +#if 0 + case wxSYS_LIST_SEPARATOR: + count = ::GetLocaleInfo(lcid, LOCALE_SLIST, buffer, 256); + if (!count) + str << wxT(","); + else + str << buffer; + break; + case wxSYS_LEADING_ZERO: // 0 means no leading zero, 1 means leading zero + count = ::GetLocaleInfo(lcid, LOCALE_ILZERO, buffer, 256); + if (!count) + str << wxT("0"); + else + str << buffer; + break; +#endif + default: + wxFAIL_MSG(wxT("Unknown System String !")); + } + return str; +} + +#elif defined(__DARWIN__) + +/* static */ +wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory WXUNUSED(cat)) +{ + CFLocaleRef userLocaleRefRaw; + if ( wxGetLocale() ) + { + userLocaleRefRaw = CFLocaleCreate + ( + kCFAllocatorDefault, + wxMacCFStringHolder(wxGetLocale()->GetCanonicalName()) + ); + } + else // no current locale, use the default one + { + userLocaleRefRaw = CFLocaleCopyCurrent(); + } + + wxCFRef userLocaleRef(userLocaleRefRaw); + + CFTypeRef cfstr; + switch ( index ) + { + case wxLOCALE_THOUSANDS_SEP: + cfstr = CFLocaleGetValue(userLocaleRef, kCFLocaleGroupingSeparator); + break; + + case wxLOCALE_DECIMAL_POINT: + cfstr = CFLocaleGetValue(userLocaleRef, kCFLocaleDecimalSeparator); + break; + + default: + wxFAIL_MSG( _T("Unknown locale info") ); + } + + wxMacCFStringHolder + str(CFStringCreateCopy(NULL, static_cast(cfstr))); + return str.AsString(); +} + +#else // !__WXMSW__ && !__DARWIN__ + +/* static */ +wxString wxLocale::GetInfo(wxLocaleInfo index, wxLocaleCategory cat) +{ + struct lconv *locale_info = localeconv(); + switch (cat) + { + case wxLOCALE_CAT_NUMBER: + switch (index) + { + case wxLOCALE_THOUSANDS_SEP: + return wxString(locale_info->thousands_sep, + *wxConvCurrent); + case wxLOCALE_DECIMAL_POINT: + return wxString(locale_info->decimal_point, + *wxConvCurrent); + default: + return wxEmptyString; + } + case wxLOCALE_CAT_MONEY: + switch (index) + { + case wxLOCALE_THOUSANDS_SEP: + return wxString(locale_info->mon_thousands_sep, + *wxConvCurrent); + case wxLOCALE_DECIMAL_POINT: + return wxString(locale_info->mon_decimal_point, + *wxConvCurrent); + default: + return wxEmptyString; + } + default: + return wxEmptyString; + } +} + +#endif // __WXMSW__/!__WXMSW__ + +// ---------------------------------------------------------------------------- +// global functions and variables +// ---------------------------------------------------------------------------- + +// retrieve/change current locale +// ------------------------------ + +// the current locale object +static wxLocale *g_pLocale = NULL; + +wxLocale *wxGetLocale() +{ + return g_pLocale; +} + +wxLocale *wxSetLocale(wxLocale *pLocale) +{ + wxLocale *pOld = g_pLocale; + g_pLocale = pLocale; + return pOld; +} + + + +// ---------------------------------------------------------------------------- +// wxLocale module (for lazy destruction of languagesDB) +// ---------------------------------------------------------------------------- + +class wxLocaleModule: public wxModule +{ + DECLARE_DYNAMIC_CLASS(wxLocaleModule) + public: + wxLocaleModule() {} + bool OnInit() { return true; } + void OnExit() { wxLocale::DestroyLanguagesDB(); } +}; + +IMPLEMENT_DYNAMIC_CLASS(wxLocaleModule, wxModule) + + + +// ---------------------------------------------------------------------------- +// default languages table & initialization +// ---------------------------------------------------------------------------- + + + +// --- --- --- generated code begins here --- --- --- + +// This table is generated by misc/languages/genlang.py +// When making changes, please put them into misc/languages/langtabl.txt + +#if !defined(__WIN32__) || defined(__WXMICROWIN__) + +#define SETWINLANG(info,lang,sublang) + +#else + +#define SETWINLANG(info,lang,sublang) \ + info.WinLang = lang, info.WinSublang = sublang; + +#ifndef LANG_AFRIKAANS +#define LANG_AFRIKAANS (0) +#endif +#ifndef LANG_ALBANIAN +#define LANG_ALBANIAN (0) +#endif +#ifndef LANG_ARABIC +#define LANG_ARABIC (0) +#endif +#ifndef LANG_ARMENIAN +#define LANG_ARMENIAN (0) +#endif +#ifndef LANG_ASSAMESE +#define LANG_ASSAMESE (0) +#endif +#ifndef LANG_AZERI +#define LANG_AZERI (0) +#endif +#ifndef LANG_BASQUE +#define LANG_BASQUE (0) +#endif +#ifndef LANG_BELARUSIAN +#define LANG_BELARUSIAN (0) +#endif +#ifndef LANG_BENGALI +#define LANG_BENGALI (0) +#endif +#ifndef LANG_BULGARIAN +#define LANG_BULGARIAN (0) +#endif +#ifndef LANG_CATALAN +#define LANG_CATALAN (0) +#endif +#ifndef LANG_CHINESE +#define LANG_CHINESE (0) +#endif +#ifndef LANG_CROATIAN +#define LANG_CROATIAN (0) +#endif +#ifndef LANG_CZECH +#define LANG_CZECH (0) +#endif +#ifndef LANG_DANISH +#define LANG_DANISH (0) +#endif +#ifndef LANG_DUTCH +#define LANG_DUTCH (0) +#endif +#ifndef LANG_ENGLISH +#define LANG_ENGLISH (0) +#endif +#ifndef LANG_ESTONIAN +#define LANG_ESTONIAN (0) +#endif +#ifndef LANG_FAEROESE +#define LANG_FAEROESE (0) +#endif +#ifndef LANG_FARSI +#define LANG_FARSI (0) +#endif +#ifndef LANG_FINNISH +#define LANG_FINNISH (0) +#endif +#ifndef LANG_FRENCH +#define LANG_FRENCH (0) +#endif +#ifndef LANG_GEORGIAN +#define LANG_GEORGIAN (0) +#endif +#ifndef LANG_GERMAN +#define LANG_GERMAN (0) +#endif +#ifndef LANG_GREEK +#define LANG_GREEK (0) +#endif +#ifndef LANG_GUJARATI +#define LANG_GUJARATI (0) +#endif +#ifndef LANG_HEBREW +#define LANG_HEBREW (0) +#endif +#ifndef LANG_HINDI +#define LANG_HINDI (0) +#endif +#ifndef LANG_HUNGARIAN +#define LANG_HUNGARIAN (0) +#endif +#ifndef LANG_ICELANDIC +#define LANG_ICELANDIC (0) +#endif +#ifndef LANG_INDONESIAN +#define LANG_INDONESIAN (0) +#endif +#ifndef LANG_ITALIAN +#define LANG_ITALIAN (0) +#endif +#ifndef LANG_JAPANESE +#define LANG_JAPANESE (0) +#endif +#ifndef LANG_KANNADA +#define LANG_KANNADA (0) +#endif +#ifndef LANG_KASHMIRI +#define LANG_KASHMIRI (0) +#endif +#ifndef LANG_KAZAK +#define LANG_KAZAK (0) +#endif +#ifndef LANG_KONKANI +#define LANG_KONKANI (0) +#endif +#ifndef LANG_KOREAN +#define LANG_KOREAN (0) +#endif +#ifndef LANG_LATVIAN +#define LANG_LATVIAN (0) +#endif +#ifndef LANG_LITHUANIAN +#define LANG_LITHUANIAN (0) +#endif +#ifndef LANG_MACEDONIAN +#define LANG_MACEDONIAN (0) +#endif +#ifndef LANG_MALAY +#define LANG_MALAY (0) +#endif +#ifndef LANG_MALAYALAM +#define LANG_MALAYALAM (0) +#endif +#ifndef LANG_MANIPURI +#define LANG_MANIPURI (0) +#endif +#ifndef LANG_MARATHI +#define LANG_MARATHI (0) +#endif +#ifndef LANG_NEPALI +#define LANG_NEPALI (0) +#endif +#ifndef LANG_NORWEGIAN +#define LANG_NORWEGIAN (0) +#endif +#ifndef LANG_ORIYA +#define LANG_ORIYA (0) +#endif +#ifndef LANG_POLISH +#define LANG_POLISH (0) +#endif +#ifndef LANG_PORTUGUESE +#define LANG_PORTUGUESE (0) +#endif +#ifndef LANG_PUNJABI +#define LANG_PUNJABI (0) +#endif +#ifndef LANG_ROMANIAN +#define LANG_ROMANIAN (0) +#endif +#ifndef LANG_RUSSIAN +#define LANG_RUSSIAN (0) +#endif +#ifndef LANG_SAMI +#define LANG_SAMI (0) +#endif +#ifndef LANG_SANSKRIT +#define LANG_SANSKRIT (0) +#endif +#ifndef LANG_SERBIAN +#define LANG_SERBIAN (0) +#endif +#ifndef LANG_SINDHI +#define LANG_SINDHI (0) +#endif +#ifndef LANG_SLOVAK +#define LANG_SLOVAK (0) +#endif +#ifndef LANG_SLOVENIAN +#define LANG_SLOVENIAN (0) +#endif +#ifndef LANG_SPANISH +#define LANG_SPANISH (0) +#endif +#ifndef LANG_SWAHILI +#define LANG_SWAHILI (0) +#endif +#ifndef LANG_SWEDISH +#define LANG_SWEDISH (0) +#endif +#ifndef LANG_TAMIL +#define LANG_TAMIL (0) +#endif +#ifndef LANG_TATAR +#define LANG_TATAR (0) +#endif +#ifndef LANG_TELUGU +#define LANG_TELUGU (0) +#endif +#ifndef LANG_THAI +#define LANG_THAI (0) +#endif +#ifndef LANG_TURKISH +#define LANG_TURKISH (0) +#endif +#ifndef LANG_UKRAINIAN +#define LANG_UKRAINIAN (0) +#endif +#ifndef LANG_URDU +#define LANG_URDU (0) +#endif +#ifndef LANG_UZBEK +#define LANG_UZBEK (0) +#endif +#ifndef LANG_VALENCIAN +#define LANG_VALENCIAN (0) +#endif +#ifndef LANG_VIETNAMESE +#define LANG_VIETNAMESE (0) +#endif +#ifndef SUBLANG_ARABIC_ALGERIA +#define SUBLANG_ARABIC_ALGERIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_BAHRAIN +#define SUBLANG_ARABIC_BAHRAIN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_EGYPT +#define SUBLANG_ARABIC_EGYPT SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_IRAQ +#define SUBLANG_ARABIC_IRAQ SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_JORDAN +#define SUBLANG_ARABIC_JORDAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_KUWAIT +#define SUBLANG_ARABIC_KUWAIT SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_LEBANON +#define SUBLANG_ARABIC_LEBANON SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_LIBYA +#define SUBLANG_ARABIC_LIBYA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_MOROCCO +#define SUBLANG_ARABIC_MOROCCO SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_OMAN +#define SUBLANG_ARABIC_OMAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_QATAR +#define SUBLANG_ARABIC_QATAR SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_SAUDI_ARABIA +#define SUBLANG_ARABIC_SAUDI_ARABIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_SYRIA +#define SUBLANG_ARABIC_SYRIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_TUNISIA +#define SUBLANG_ARABIC_TUNISIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_UAE +#define SUBLANG_ARABIC_UAE SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ARABIC_YEMEN +#define SUBLANG_ARABIC_YEMEN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_AZERI_CYRILLIC +#define SUBLANG_AZERI_CYRILLIC SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_AZERI_LATIN +#define SUBLANG_AZERI_LATIN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_CHINESE_SIMPLIFIED +#define SUBLANG_CHINESE_SIMPLIFIED SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_CHINESE_TRADITIONAL +#define SUBLANG_CHINESE_TRADITIONAL SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_CHINESE_HONGKONG +#define SUBLANG_CHINESE_HONGKONG SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_CHINESE_MACAU +#define SUBLANG_CHINESE_MACAU SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_CHINESE_SINGAPORE +#define SUBLANG_CHINESE_SINGAPORE SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_DUTCH +#define SUBLANG_DUTCH SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_DUTCH_BELGIAN +#define SUBLANG_DUTCH_BELGIAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_UK +#define SUBLANG_ENGLISH_UK SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_US +#define SUBLANG_ENGLISH_US SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_AUS +#define SUBLANG_ENGLISH_AUS SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_BELIZE +#define SUBLANG_ENGLISH_BELIZE SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_CAN +#define SUBLANG_ENGLISH_CAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_CARIBBEAN +#define SUBLANG_ENGLISH_CARIBBEAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_EIRE +#define SUBLANG_ENGLISH_EIRE SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_JAMAICA +#define SUBLANG_ENGLISH_JAMAICA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_NZ +#define SUBLANG_ENGLISH_NZ SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_PHILIPPINES +#define SUBLANG_ENGLISH_PHILIPPINES SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_SOUTH_AFRICA +#define SUBLANG_ENGLISH_SOUTH_AFRICA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_TRINIDAD +#define SUBLANG_ENGLISH_TRINIDAD SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ENGLISH_ZIMBABWE +#define SUBLANG_ENGLISH_ZIMBABWE SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_FRENCH +#define SUBLANG_FRENCH SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_FRENCH_BELGIAN +#define SUBLANG_FRENCH_BELGIAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_FRENCH_CANADIAN +#define SUBLANG_FRENCH_CANADIAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_FRENCH_LUXEMBOURG +#define SUBLANG_FRENCH_LUXEMBOURG SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_FRENCH_MONACO +#define SUBLANG_FRENCH_MONACO SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_FRENCH_SWISS +#define SUBLANG_FRENCH_SWISS SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_GERMAN +#define SUBLANG_GERMAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_GERMAN_AUSTRIAN +#define SUBLANG_GERMAN_AUSTRIAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_GERMAN_LIECHTENSTEIN +#define SUBLANG_GERMAN_LIECHTENSTEIN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_GERMAN_LUXEMBOURG +#define SUBLANG_GERMAN_LUXEMBOURG SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_GERMAN_SWISS +#define SUBLANG_GERMAN_SWISS SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ITALIAN +#define SUBLANG_ITALIAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_ITALIAN_SWISS +#define SUBLANG_ITALIAN_SWISS SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_KASHMIRI_INDIA +#define SUBLANG_KASHMIRI_INDIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_KOREAN +#define SUBLANG_KOREAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_LITHUANIAN +#define SUBLANG_LITHUANIAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM +#define SUBLANG_MALAY_BRUNEI_DARUSSALAM SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_MALAY_MALAYSIA +#define SUBLANG_MALAY_MALAYSIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_NEPALI_INDIA +#define SUBLANG_NEPALI_INDIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_NORWEGIAN_BOKMAL +#define SUBLANG_NORWEGIAN_BOKMAL SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_NORWEGIAN_NYNORSK +#define SUBLANG_NORWEGIAN_NYNORSK SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_PORTUGUESE +#define SUBLANG_PORTUGUESE SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_PORTUGUESE_BRAZILIAN +#define SUBLANG_PORTUGUESE_BRAZILIAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SERBIAN_CYRILLIC +#define SUBLANG_SERBIAN_CYRILLIC SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SERBIAN_LATIN +#define SUBLANG_SERBIAN_LATIN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH +#define SUBLANG_SPANISH SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_ARGENTINA +#define SUBLANG_SPANISH_ARGENTINA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_BOLIVIA +#define SUBLANG_SPANISH_BOLIVIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_CHILE +#define SUBLANG_SPANISH_CHILE SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_COLOMBIA +#define SUBLANG_SPANISH_COLOMBIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_COSTA_RICA +#define SUBLANG_SPANISH_COSTA_RICA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_DOMINICAN_REPUBLIC +#define SUBLANG_SPANISH_DOMINICAN_REPUBLIC SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_ECUADOR +#define SUBLANG_SPANISH_ECUADOR SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_EL_SALVADOR +#define SUBLANG_SPANISH_EL_SALVADOR SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_GUATEMALA +#define SUBLANG_SPANISH_GUATEMALA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_HONDURAS +#define SUBLANG_SPANISH_HONDURAS SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_MEXICAN +#define SUBLANG_SPANISH_MEXICAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_MODERN +#define SUBLANG_SPANISH_MODERN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_NICARAGUA +#define SUBLANG_SPANISH_NICARAGUA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_PANAMA +#define SUBLANG_SPANISH_PANAMA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_PARAGUAY +#define SUBLANG_SPANISH_PARAGUAY SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_PERU +#define SUBLANG_SPANISH_PERU SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_PUERTO_RICO +#define SUBLANG_SPANISH_PUERTO_RICO SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_URUGUAY +#define SUBLANG_SPANISH_URUGUAY SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SPANISH_VENEZUELA +#define SUBLANG_SPANISH_VENEZUELA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SWEDISH +#define SUBLANG_SWEDISH SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_SWEDISH_FINLAND +#define SUBLANG_SWEDISH_FINLAND SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_URDU_INDIA +#define SUBLANG_URDU_INDIA SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_URDU_PAKISTAN +#define SUBLANG_URDU_PAKISTAN SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_UZBEK_CYRILLIC +#define SUBLANG_UZBEK_CYRILLIC SUBLANG_DEFAULT +#endif +#ifndef SUBLANG_UZBEK_LATIN +#define SUBLANG_UZBEK_LATIN SUBLANG_DEFAULT +#endif + + +#endif // __WIN32__ + +#define LNG(wxlang, canonical, winlang, winsublang, layout, desc) \ + info.Language = wxlang; \ + info.CanonicalName = wxT(canonical); \ + info.LayoutDirection = layout; \ + info.Description = wxT(desc); \ + SETWINLANG(info, winlang, winsublang) \ + AddLanguage(info); + +void wxLocale::InitLanguagesDB() +{ + wxLanguageInfo info; + wxStringTokenizer tkn; + + LNG(wxLANGUAGE_ABKHAZIAN, "ab" , 0 , 0 , wxLayout_LeftToRight, "Abkhazian") + LNG(wxLANGUAGE_AFAR, "aa" , 0 , 0 , wxLayout_LeftToRight, "Afar") + LNG(wxLANGUAGE_AFRIKAANS, "af_ZA", LANG_AFRIKAANS , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Afrikaans") + LNG(wxLANGUAGE_ALBANIAN, "sq_AL", LANG_ALBANIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Albanian") + LNG(wxLANGUAGE_AMHARIC, "am" , 0 , 0 , wxLayout_LeftToRight, "Amharic") + LNG(wxLANGUAGE_ARABIC, "ar" , LANG_ARABIC , SUBLANG_DEFAULT , wxLayout_RightToLeft, "Arabic") + LNG(wxLANGUAGE_ARABIC_ALGERIA, "ar_DZ", LANG_ARABIC , SUBLANG_ARABIC_ALGERIA , wxLayout_RightToLeft, "Arabic (Algeria)") + LNG(wxLANGUAGE_ARABIC_BAHRAIN, "ar_BH", LANG_ARABIC , SUBLANG_ARABIC_BAHRAIN , wxLayout_RightToLeft, "Arabic (Bahrain)") + LNG(wxLANGUAGE_ARABIC_EGYPT, "ar_EG", LANG_ARABIC , SUBLANG_ARABIC_EGYPT , wxLayout_RightToLeft, "Arabic (Egypt)") + LNG(wxLANGUAGE_ARABIC_IRAQ, "ar_IQ", LANG_ARABIC , SUBLANG_ARABIC_IRAQ , wxLayout_RightToLeft, "Arabic (Iraq)") + LNG(wxLANGUAGE_ARABIC_JORDAN, "ar_JO", LANG_ARABIC , SUBLANG_ARABIC_JORDAN , wxLayout_RightToLeft, "Arabic (Jordan)") + LNG(wxLANGUAGE_ARABIC_KUWAIT, "ar_KW", LANG_ARABIC , SUBLANG_ARABIC_KUWAIT , wxLayout_RightToLeft, "Arabic (Kuwait)") + LNG(wxLANGUAGE_ARABIC_LEBANON, "ar_LB", LANG_ARABIC , SUBLANG_ARABIC_LEBANON , wxLayout_RightToLeft, "Arabic (Lebanon)") + LNG(wxLANGUAGE_ARABIC_LIBYA, "ar_LY", LANG_ARABIC , SUBLANG_ARABIC_LIBYA , wxLayout_RightToLeft, "Arabic (Libya)") + LNG(wxLANGUAGE_ARABIC_MOROCCO, "ar_MA", LANG_ARABIC , SUBLANG_ARABIC_MOROCCO , wxLayout_RightToLeft, "Arabic (Morocco)") + LNG(wxLANGUAGE_ARABIC_OMAN, "ar_OM", LANG_ARABIC , SUBLANG_ARABIC_OMAN , wxLayout_RightToLeft, "Arabic (Oman)") + LNG(wxLANGUAGE_ARABIC_QATAR, "ar_QA", LANG_ARABIC , SUBLANG_ARABIC_QATAR , wxLayout_RightToLeft, "Arabic (Qatar)") + LNG(wxLANGUAGE_ARABIC_SAUDI_ARABIA, "ar_SA", LANG_ARABIC , SUBLANG_ARABIC_SAUDI_ARABIA , wxLayout_RightToLeft, "Arabic (Saudi Arabia)") + LNG(wxLANGUAGE_ARABIC_SUDAN, "ar_SD", 0 , 0 , wxLayout_RightToLeft, "Arabic (Sudan)") + LNG(wxLANGUAGE_ARABIC_SYRIA, "ar_SY", LANG_ARABIC , SUBLANG_ARABIC_SYRIA , wxLayout_RightToLeft, "Arabic (Syria)") + LNG(wxLANGUAGE_ARABIC_TUNISIA, "ar_TN", LANG_ARABIC , SUBLANG_ARABIC_TUNISIA , wxLayout_RightToLeft, "Arabic (Tunisia)") + LNG(wxLANGUAGE_ARABIC_UAE, "ar_AE", LANG_ARABIC , SUBLANG_ARABIC_UAE , wxLayout_RightToLeft, "Arabic (Uae)") + LNG(wxLANGUAGE_ARABIC_YEMEN, "ar_YE", LANG_ARABIC , SUBLANG_ARABIC_YEMEN , wxLayout_RightToLeft, "Arabic (Yemen)") + LNG(wxLANGUAGE_ARMENIAN, "hy" , LANG_ARMENIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Armenian") + LNG(wxLANGUAGE_ASSAMESE, "as" , LANG_ASSAMESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Assamese") + LNG(wxLANGUAGE_AYMARA, "ay" , 0 , 0 , wxLayout_LeftToRight, "Aymara") + LNG(wxLANGUAGE_AZERI, "az" , LANG_AZERI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Azeri") + LNG(wxLANGUAGE_AZERI_CYRILLIC, "az" , LANG_AZERI , SUBLANG_AZERI_CYRILLIC , wxLayout_LeftToRight, "Azeri (Cyrillic)") + LNG(wxLANGUAGE_AZERI_LATIN, "az" , LANG_AZERI , SUBLANG_AZERI_LATIN , wxLayout_LeftToRight, "Azeri (Latin)") + LNG(wxLANGUAGE_BASHKIR, "ba" , 0 , 0 , wxLayout_LeftToRight, "Bashkir") + LNG(wxLANGUAGE_BASQUE, "eu_ES", LANG_BASQUE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Basque") + LNG(wxLANGUAGE_BELARUSIAN, "be_BY", LANG_BELARUSIAN, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Belarusian") + LNG(wxLANGUAGE_BENGALI, "bn" , LANG_BENGALI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Bengali") + LNG(wxLANGUAGE_BHUTANI, "dz" , 0 , 0 , wxLayout_LeftToRight, "Bhutani") + LNG(wxLANGUAGE_BIHARI, "bh" , 0 , 0 , wxLayout_LeftToRight, "Bihari") + LNG(wxLANGUAGE_BISLAMA, "bi" , 0 , 0 , wxLayout_LeftToRight, "Bislama") + LNG(wxLANGUAGE_BRETON, "br" , 0 , 0 , wxLayout_LeftToRight, "Breton") + LNG(wxLANGUAGE_BULGARIAN, "bg_BG", LANG_BULGARIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Bulgarian") + LNG(wxLANGUAGE_BURMESE, "my" , 0 , 0 , wxLayout_LeftToRight, "Burmese") + LNG(wxLANGUAGE_CAMBODIAN, "km" , 0 , 0 , wxLayout_LeftToRight, "Cambodian") + LNG(wxLANGUAGE_CATALAN, "ca_ES", LANG_CATALAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Catalan") + LNG(wxLANGUAGE_CHINESE, "zh_TW", LANG_CHINESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Chinese") + LNG(wxLANGUAGE_CHINESE_SIMPLIFIED, "zh_CN", LANG_CHINESE , SUBLANG_CHINESE_SIMPLIFIED , wxLayout_LeftToRight, "Chinese (Simplified)") + LNG(wxLANGUAGE_CHINESE_TRADITIONAL, "zh_TW", LANG_CHINESE , SUBLANG_CHINESE_TRADITIONAL , wxLayout_LeftToRight, "Chinese (Traditional)") + LNG(wxLANGUAGE_CHINESE_HONGKONG, "zh_HK", LANG_CHINESE , SUBLANG_CHINESE_HONGKONG , wxLayout_LeftToRight, "Chinese (Hongkong)") + LNG(wxLANGUAGE_CHINESE_MACAU, "zh_MO", LANG_CHINESE , SUBLANG_CHINESE_MACAU , wxLayout_LeftToRight, "Chinese (Macau)") + LNG(wxLANGUAGE_CHINESE_SINGAPORE, "zh_SG", LANG_CHINESE , SUBLANG_CHINESE_SINGAPORE , wxLayout_LeftToRight, "Chinese (Singapore)") + LNG(wxLANGUAGE_CHINESE_TAIWAN, "zh_TW", LANG_CHINESE , SUBLANG_CHINESE_TRADITIONAL , wxLayout_LeftToRight, "Chinese (Taiwan)") + LNG(wxLANGUAGE_CORSICAN, "co" , 0 , 0 , wxLayout_LeftToRight, "Corsican") + LNG(wxLANGUAGE_CROATIAN, "hr_HR", LANG_CROATIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Croatian") + LNG(wxLANGUAGE_CZECH, "cs_CZ", LANG_CZECH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Czech") + LNG(wxLANGUAGE_DANISH, "da_DK", LANG_DANISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Danish") + LNG(wxLANGUAGE_DUTCH, "nl_NL", LANG_DUTCH , SUBLANG_DUTCH , wxLayout_LeftToRight, "Dutch") + LNG(wxLANGUAGE_DUTCH_BELGIAN, "nl_BE", LANG_DUTCH , SUBLANG_DUTCH_BELGIAN , wxLayout_LeftToRight, "Dutch (Belgian)") + LNG(wxLANGUAGE_ENGLISH, "en_GB", LANG_ENGLISH , SUBLANG_ENGLISH_UK , wxLayout_LeftToRight, "English") + LNG(wxLANGUAGE_ENGLISH_UK, "en_GB", LANG_ENGLISH , SUBLANG_ENGLISH_UK , wxLayout_LeftToRight, "English (U.K.)") + LNG(wxLANGUAGE_ENGLISH_US, "en_US", LANG_ENGLISH , SUBLANG_ENGLISH_US , wxLayout_LeftToRight, "English (U.S.)") + LNG(wxLANGUAGE_ENGLISH_AUSTRALIA, "en_AU", LANG_ENGLISH , SUBLANG_ENGLISH_AUS , wxLayout_LeftToRight, "English (Australia)") + LNG(wxLANGUAGE_ENGLISH_BELIZE, "en_BZ", LANG_ENGLISH , SUBLANG_ENGLISH_BELIZE , wxLayout_LeftToRight, "English (Belize)") + LNG(wxLANGUAGE_ENGLISH_BOTSWANA, "en_BW", 0 , 0 , wxLayout_LeftToRight, "English (Botswana)") + LNG(wxLANGUAGE_ENGLISH_CANADA, "en_CA", LANG_ENGLISH , SUBLANG_ENGLISH_CAN , wxLayout_LeftToRight, "English (Canada)") + LNG(wxLANGUAGE_ENGLISH_CARIBBEAN, "en_CB", LANG_ENGLISH , SUBLANG_ENGLISH_CARIBBEAN , wxLayout_LeftToRight, "English (Caribbean)") + LNG(wxLANGUAGE_ENGLISH_DENMARK, "en_DK", 0 , 0 , wxLayout_LeftToRight, "English (Denmark)") + LNG(wxLANGUAGE_ENGLISH_EIRE, "en_IE", LANG_ENGLISH , SUBLANG_ENGLISH_EIRE , wxLayout_LeftToRight, "English (Eire)") + LNG(wxLANGUAGE_ENGLISH_JAMAICA, "en_JM", LANG_ENGLISH , SUBLANG_ENGLISH_JAMAICA , wxLayout_LeftToRight, "English (Jamaica)") + LNG(wxLANGUAGE_ENGLISH_NEW_ZEALAND, "en_NZ", LANG_ENGLISH , SUBLANG_ENGLISH_NZ , wxLayout_LeftToRight, "English (New Zealand)") + LNG(wxLANGUAGE_ENGLISH_PHILIPPINES, "en_PH", LANG_ENGLISH , SUBLANG_ENGLISH_PHILIPPINES , wxLayout_LeftToRight, "English (Philippines)") + LNG(wxLANGUAGE_ENGLISH_SOUTH_AFRICA, "en_ZA", LANG_ENGLISH , SUBLANG_ENGLISH_SOUTH_AFRICA , wxLayout_LeftToRight, "English (South Africa)") + LNG(wxLANGUAGE_ENGLISH_TRINIDAD, "en_TT", LANG_ENGLISH , SUBLANG_ENGLISH_TRINIDAD , wxLayout_LeftToRight, "English (Trinidad)") + LNG(wxLANGUAGE_ENGLISH_ZIMBABWE, "en_ZW", LANG_ENGLISH , SUBLANG_ENGLISH_ZIMBABWE , wxLayout_LeftToRight, "English (Zimbabwe)") + LNG(wxLANGUAGE_ESPERANTO, "eo" , 0 , 0 , wxLayout_LeftToRight, "Esperanto") + LNG(wxLANGUAGE_ESTONIAN, "et_EE", LANG_ESTONIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Estonian") + LNG(wxLANGUAGE_FAEROESE, "fo_FO", LANG_FAEROESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Faeroese") + LNG(wxLANGUAGE_FARSI, "fa_IR", LANG_FARSI , SUBLANG_DEFAULT , wxLayout_RightToLeft, "Farsi") + LNG(wxLANGUAGE_FIJI, "fj" , 0 , 0 , wxLayout_LeftToRight, "Fiji") + LNG(wxLANGUAGE_FINNISH, "fi_FI", LANG_FINNISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Finnish") + LNG(wxLANGUAGE_FRENCH, "fr_FR", LANG_FRENCH , SUBLANG_FRENCH , wxLayout_LeftToRight, "French") + LNG(wxLANGUAGE_FRENCH_BELGIAN, "fr_BE", LANG_FRENCH , SUBLANG_FRENCH_BELGIAN , wxLayout_LeftToRight, "French (Belgian)") + LNG(wxLANGUAGE_FRENCH_CANADIAN, "fr_CA", LANG_FRENCH , SUBLANG_FRENCH_CANADIAN , wxLayout_LeftToRight, "French (Canadian)") + LNG(wxLANGUAGE_FRENCH_LUXEMBOURG, "fr_LU", LANG_FRENCH , SUBLANG_FRENCH_LUXEMBOURG , wxLayout_LeftToRight, "French (Luxembourg)") + LNG(wxLANGUAGE_FRENCH_MONACO, "fr_MC", LANG_FRENCH , SUBLANG_FRENCH_MONACO , wxLayout_LeftToRight, "French (Monaco)") + LNG(wxLANGUAGE_FRENCH_SWISS, "fr_CH", LANG_FRENCH , SUBLANG_FRENCH_SWISS , wxLayout_LeftToRight, "French (Swiss)") + LNG(wxLANGUAGE_FRISIAN, "fy" , 0 , 0 , wxLayout_LeftToRight, "Frisian") + LNG(wxLANGUAGE_GALICIAN, "gl_ES", 0 , 0 , wxLayout_LeftToRight, "Galician") + LNG(wxLANGUAGE_GEORGIAN, "ka_GE", LANG_GEORGIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Georgian") + LNG(wxLANGUAGE_GERMAN, "de_DE", LANG_GERMAN , SUBLANG_GERMAN , wxLayout_LeftToRight, "German") + LNG(wxLANGUAGE_GERMAN_AUSTRIAN, "de_AT", LANG_GERMAN , SUBLANG_GERMAN_AUSTRIAN , wxLayout_LeftToRight, "German (Austrian)") + LNG(wxLANGUAGE_GERMAN_BELGIUM, "de_BE", 0 , 0 , wxLayout_LeftToRight, "German (Belgium)") + LNG(wxLANGUAGE_GERMAN_LIECHTENSTEIN, "de_LI", LANG_GERMAN , SUBLANG_GERMAN_LIECHTENSTEIN , wxLayout_LeftToRight, "German (Liechtenstein)") + LNG(wxLANGUAGE_GERMAN_LUXEMBOURG, "de_LU", LANG_GERMAN , SUBLANG_GERMAN_LUXEMBOURG , wxLayout_LeftToRight, "German (Luxembourg)") + LNG(wxLANGUAGE_GERMAN_SWISS, "de_CH", LANG_GERMAN , SUBLANG_GERMAN_SWISS , wxLayout_LeftToRight, "German (Swiss)") + LNG(wxLANGUAGE_GREEK, "el_GR", LANG_GREEK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Greek") + LNG(wxLANGUAGE_GREENLANDIC, "kl_GL", 0 , 0 , wxLayout_LeftToRight, "Greenlandic") + LNG(wxLANGUAGE_GUARANI, "gn" , 0 , 0 , wxLayout_LeftToRight, "Guarani") + LNG(wxLANGUAGE_GUJARATI, "gu" , LANG_GUJARATI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Gujarati") + LNG(wxLANGUAGE_HAUSA, "ha" , 0 , 0 , wxLayout_LeftToRight, "Hausa") + LNG(wxLANGUAGE_HEBREW, "he_IL", LANG_HEBREW , SUBLANG_DEFAULT , wxLayout_RightToLeft, "Hebrew") + LNG(wxLANGUAGE_HINDI, "hi_IN", LANG_HINDI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Hindi") + LNG(wxLANGUAGE_HUNGARIAN, "hu_HU", LANG_HUNGARIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Hungarian") + LNG(wxLANGUAGE_ICELANDIC, "is_IS", LANG_ICELANDIC , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Icelandic") + LNG(wxLANGUAGE_INDONESIAN, "id_ID", LANG_INDONESIAN, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Indonesian") + LNG(wxLANGUAGE_INTERLINGUA, "ia" , 0 , 0 , wxLayout_LeftToRight, "Interlingua") + LNG(wxLANGUAGE_INTERLINGUE, "ie" , 0 , 0 , wxLayout_LeftToRight, "Interlingue") + LNG(wxLANGUAGE_INUKTITUT, "iu" , 0 , 0 , wxLayout_LeftToRight, "Inuktitut") + LNG(wxLANGUAGE_INUPIAK, "ik" , 0 , 0 , wxLayout_LeftToRight, "Inupiak") + LNG(wxLANGUAGE_IRISH, "ga_IE", 0 , 0 , wxLayout_LeftToRight, "Irish") + LNG(wxLANGUAGE_ITALIAN, "it_IT", LANG_ITALIAN , SUBLANG_ITALIAN , wxLayout_LeftToRight, "Italian") + LNG(wxLANGUAGE_ITALIAN_SWISS, "it_CH", LANG_ITALIAN , SUBLANG_ITALIAN_SWISS , wxLayout_LeftToRight, "Italian (Swiss)") + LNG(wxLANGUAGE_JAPANESE, "ja_JP", LANG_JAPANESE , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Japanese") + LNG(wxLANGUAGE_JAVANESE, "jw" , 0 , 0 , wxLayout_LeftToRight, "Javanese") + LNG(wxLANGUAGE_KANNADA, "kn" , LANG_KANNADA , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kannada") + LNG(wxLANGUAGE_KASHMIRI, "ks" , LANG_KASHMIRI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kashmiri") + LNG(wxLANGUAGE_KASHMIRI_INDIA, "ks_IN", LANG_KASHMIRI , SUBLANG_KASHMIRI_INDIA , wxLayout_LeftToRight, "Kashmiri (India)") + LNG(wxLANGUAGE_KAZAKH, "kk" , LANG_KAZAK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Kazakh") + LNG(wxLANGUAGE_KERNEWEK, "kw_GB", 0 , 0 , wxLayout_LeftToRight, "Kernewek") + LNG(wxLANGUAGE_KINYARWANDA, "rw" , 0 , 0 , wxLayout_LeftToRight, "Kinyarwanda") + LNG(wxLANGUAGE_KIRGHIZ, "ky" , 0 , 0 , wxLayout_LeftToRight, "Kirghiz") + LNG(wxLANGUAGE_KIRUNDI, "rn" , 0 , 0 , wxLayout_LeftToRight, "Kirundi") + LNG(wxLANGUAGE_KONKANI, "" , LANG_KONKANI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Konkani") + LNG(wxLANGUAGE_KOREAN, "ko_KR", LANG_KOREAN , SUBLANG_KOREAN , wxLayout_LeftToRight, "Korean") + LNG(wxLANGUAGE_KURDISH, "ku_TR", 0 , 0 , wxLayout_LeftToRight, "Kurdish") + LNG(wxLANGUAGE_LAOTHIAN, "lo" , 0 , 0 , wxLayout_LeftToRight, "Laothian") + LNG(wxLANGUAGE_LATIN, "la" , 0 , 0 , wxLayout_LeftToRight, "Latin") + LNG(wxLANGUAGE_LATVIAN, "lv_LV", LANG_LATVIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Latvian") + LNG(wxLANGUAGE_LINGALA, "ln" , 0 , 0 , wxLayout_LeftToRight, "Lingala") + LNG(wxLANGUAGE_LITHUANIAN, "lt_LT", LANG_LITHUANIAN, SUBLANG_LITHUANIAN , wxLayout_LeftToRight, "Lithuanian") + LNG(wxLANGUAGE_MACEDONIAN, "mk_MK", LANG_MACEDONIAN, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Macedonian") + LNG(wxLANGUAGE_MALAGASY, "mg" , 0 , 0 , wxLayout_LeftToRight, "Malagasy") + LNG(wxLANGUAGE_MALAY, "ms_MY", LANG_MALAY , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Malay") + LNG(wxLANGUAGE_MALAYALAM, "ml" , LANG_MALAYALAM , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Malayalam") + LNG(wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM, "ms_BN", LANG_MALAY , SUBLANG_MALAY_BRUNEI_DARUSSALAM , wxLayout_LeftToRight, "Malay (Brunei Darussalam)") + LNG(wxLANGUAGE_MALAY_MALAYSIA, "ms_MY", LANG_MALAY , SUBLANG_MALAY_MALAYSIA , wxLayout_LeftToRight, "Malay (Malaysia)") + LNG(wxLANGUAGE_MALTESE, "mt_MT", 0 , 0 , wxLayout_LeftToRight, "Maltese") + LNG(wxLANGUAGE_MANIPURI, "" , LANG_MANIPURI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Manipuri") + LNG(wxLANGUAGE_MAORI, "mi" , 0 , 0 , wxLayout_LeftToRight, "Maori") + LNG(wxLANGUAGE_MARATHI, "mr_IN", LANG_MARATHI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Marathi") + LNG(wxLANGUAGE_MOLDAVIAN, "mo" , 0 , 0 , wxLayout_LeftToRight, "Moldavian") + LNG(wxLANGUAGE_MONGOLIAN, "mn" , 0 , 0 , wxLayout_LeftToRight, "Mongolian") + LNG(wxLANGUAGE_NAURU, "na" , 0 , 0 , wxLayout_LeftToRight, "Nauru") + LNG(wxLANGUAGE_NEPALI, "ne_NP", LANG_NEPALI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Nepali") + LNG(wxLANGUAGE_NEPALI_INDIA, "ne_IN", LANG_NEPALI , SUBLANG_NEPALI_INDIA , wxLayout_LeftToRight, "Nepali (India)") + LNG(wxLANGUAGE_NORWEGIAN_BOKMAL, "nb_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_BOKMAL , wxLayout_LeftToRight, "Norwegian (Bokmal)") + LNG(wxLANGUAGE_NORWEGIAN_NYNORSK, "nn_NO", LANG_NORWEGIAN , SUBLANG_NORWEGIAN_NYNORSK , wxLayout_LeftToRight, "Norwegian (Nynorsk)") + LNG(wxLANGUAGE_OCCITAN, "oc" , 0 , 0 , wxLayout_LeftToRight, "Occitan") + LNG(wxLANGUAGE_ORIYA, "or" , LANG_ORIYA , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Oriya") + LNG(wxLANGUAGE_OROMO, "om" , 0 , 0 , wxLayout_LeftToRight, "(Afan) Oromo") + LNG(wxLANGUAGE_PASHTO, "ps" , 0 , 0 , wxLayout_LeftToRight, "Pashto, Pushto") + LNG(wxLANGUAGE_POLISH, "pl_PL", LANG_POLISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Polish") + LNG(wxLANGUAGE_PORTUGUESE, "pt_PT", LANG_PORTUGUESE, SUBLANG_PORTUGUESE , wxLayout_LeftToRight, "Portuguese") + LNG(wxLANGUAGE_PORTUGUESE_BRAZILIAN, "pt_BR", LANG_PORTUGUESE, SUBLANG_PORTUGUESE_BRAZILIAN , wxLayout_LeftToRight, "Portuguese (Brazilian)") + LNG(wxLANGUAGE_PUNJABI, "pa" , LANG_PUNJABI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Punjabi") + LNG(wxLANGUAGE_QUECHUA, "qu" , 0 , 0 , wxLayout_LeftToRight, "Quechua") + LNG(wxLANGUAGE_RHAETO_ROMANCE, "rm" , 0 , 0 , wxLayout_LeftToRight, "Rhaeto-Romance") + LNG(wxLANGUAGE_ROMANIAN, "ro_RO", LANG_ROMANIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Romanian") + LNG(wxLANGUAGE_RUSSIAN, "ru_RU", LANG_RUSSIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Russian") + LNG(wxLANGUAGE_RUSSIAN_UKRAINE, "ru_UA", 0 , 0 , wxLayout_LeftToRight, "Russian (Ukraine)") + LNG(wxLANGUAGE_SAMI, "se_NO", LANG_SAMI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Northern Sami") + LNG(wxLANGUAGE_SAMOAN, "sm" , 0 , 0 , wxLayout_LeftToRight, "Samoan") + LNG(wxLANGUAGE_SANGHO, "sg" , 0 , 0 , wxLayout_LeftToRight, "Sangho") + LNG(wxLANGUAGE_SANSKRIT, "sa" , LANG_SANSKRIT , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Sanskrit") + LNG(wxLANGUAGE_SCOTS_GAELIC, "gd" , 0 , 0 , wxLayout_LeftToRight, "Scots Gaelic") + LNG(wxLANGUAGE_SERBIAN, "sr_RS", LANG_SERBIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Serbian") + LNG(wxLANGUAGE_SERBIAN_CYRILLIC, "sr_RS", LANG_SERBIAN , SUBLANG_SERBIAN_CYRILLIC , wxLayout_LeftToRight, "Serbian (Cyrillic)") + LNG(wxLANGUAGE_SERBIAN_LATIN, "sr_RS@latin", LANG_SERBIAN , SUBLANG_SERBIAN_LATIN , wxLayout_LeftToRight, "Serbian (Latin)") + LNG(wxLANGUAGE_SERBIAN_CYRILLIC, "sr_YU", LANG_SERBIAN , SUBLANG_SERBIAN_CYRILLIC , wxLayout_LeftToRight, "Serbian (Cyrillic)") + LNG(wxLANGUAGE_SERBIAN_LATIN, "sr_YU@latin", LANG_SERBIAN , SUBLANG_SERBIAN_LATIN , wxLayout_LeftToRight, "Serbian (Latin)") + LNG(wxLANGUAGE_SERBO_CROATIAN, "sh" , 0 , 0 , wxLayout_LeftToRight, "Serbo-Croatian") + LNG(wxLANGUAGE_SESOTHO, "st" , 0 , 0 , wxLayout_LeftToRight, "Sesotho") + LNG(wxLANGUAGE_SETSWANA, "tn" , 0 , 0 , wxLayout_LeftToRight, "Setswana") + LNG(wxLANGUAGE_SHONA, "sn" , 0 , 0 , wxLayout_LeftToRight, "Shona") + LNG(wxLANGUAGE_SINDHI, "sd" , LANG_SINDHI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Sindhi") + LNG(wxLANGUAGE_SINHALESE, "si" , 0 , 0 , wxLayout_LeftToRight, "Sinhalese") + LNG(wxLANGUAGE_SISWATI, "ss" , 0 , 0 , wxLayout_LeftToRight, "Siswati") + LNG(wxLANGUAGE_SLOVAK, "sk_SK", LANG_SLOVAK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Slovak") + LNG(wxLANGUAGE_SLOVENIAN, "sl_SI", LANG_SLOVENIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Slovenian") + LNG(wxLANGUAGE_SOMALI, "so" , 0 , 0 , wxLayout_LeftToRight, "Somali") + LNG(wxLANGUAGE_SPANISH, "es_ES", LANG_SPANISH , SUBLANG_SPANISH , wxLayout_LeftToRight, "Spanish") + LNG(wxLANGUAGE_SPANISH_ARGENTINA, "es_AR", LANG_SPANISH , SUBLANG_SPANISH_ARGENTINA , wxLayout_LeftToRight, "Spanish (Argentina)") + LNG(wxLANGUAGE_SPANISH_BOLIVIA, "es_BO", LANG_SPANISH , SUBLANG_SPANISH_BOLIVIA , wxLayout_LeftToRight, "Spanish (Bolivia)") + LNG(wxLANGUAGE_SPANISH_CHILE, "es_CL", LANG_SPANISH , SUBLANG_SPANISH_CHILE , wxLayout_LeftToRight, "Spanish (Chile)") + LNG(wxLANGUAGE_SPANISH_COLOMBIA, "es_CO", LANG_SPANISH , SUBLANG_SPANISH_COLOMBIA , wxLayout_LeftToRight, "Spanish (Colombia)") + LNG(wxLANGUAGE_SPANISH_COSTA_RICA, "es_CR", LANG_SPANISH , SUBLANG_SPANISH_COSTA_RICA , wxLayout_LeftToRight, "Spanish (Costa Rica)") + LNG(wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC, "es_DO", LANG_SPANISH , SUBLANG_SPANISH_DOMINICAN_REPUBLIC, wxLayout_LeftToRight, "Spanish (Dominican republic)") + LNG(wxLANGUAGE_SPANISH_ECUADOR, "es_EC", LANG_SPANISH , SUBLANG_SPANISH_ECUADOR , wxLayout_LeftToRight, "Spanish (Ecuador)") + LNG(wxLANGUAGE_SPANISH_EL_SALVADOR, "es_SV", LANG_SPANISH , SUBLANG_SPANISH_EL_SALVADOR , wxLayout_LeftToRight, "Spanish (El Salvador)") + LNG(wxLANGUAGE_SPANISH_GUATEMALA, "es_GT", LANG_SPANISH , SUBLANG_SPANISH_GUATEMALA , wxLayout_LeftToRight, "Spanish (Guatemala)") + LNG(wxLANGUAGE_SPANISH_HONDURAS, "es_HN", LANG_SPANISH , SUBLANG_SPANISH_HONDURAS , wxLayout_LeftToRight, "Spanish (Honduras)") + LNG(wxLANGUAGE_SPANISH_MEXICAN, "es_MX", LANG_SPANISH , SUBLANG_SPANISH_MEXICAN , wxLayout_LeftToRight, "Spanish (Mexican)") + LNG(wxLANGUAGE_SPANISH_MODERN, "es_ES", LANG_SPANISH , SUBLANG_SPANISH_MODERN , wxLayout_LeftToRight, "Spanish (Modern)") + LNG(wxLANGUAGE_SPANISH_NICARAGUA, "es_NI", LANG_SPANISH , SUBLANG_SPANISH_NICARAGUA , wxLayout_LeftToRight, "Spanish (Nicaragua)") + LNG(wxLANGUAGE_SPANISH_PANAMA, "es_PA", LANG_SPANISH , SUBLANG_SPANISH_PANAMA , wxLayout_LeftToRight, "Spanish (Panama)") + LNG(wxLANGUAGE_SPANISH_PARAGUAY, "es_PY", LANG_SPANISH , SUBLANG_SPANISH_PARAGUAY , wxLayout_LeftToRight, "Spanish (Paraguay)") + LNG(wxLANGUAGE_SPANISH_PERU, "es_PE", LANG_SPANISH , SUBLANG_SPANISH_PERU , wxLayout_LeftToRight, "Spanish (Peru)") + LNG(wxLANGUAGE_SPANISH_PUERTO_RICO, "es_PR", LANG_SPANISH , SUBLANG_SPANISH_PUERTO_RICO , wxLayout_LeftToRight, "Spanish (Puerto Rico)") + LNG(wxLANGUAGE_SPANISH_URUGUAY, "es_UY", LANG_SPANISH , SUBLANG_SPANISH_URUGUAY , wxLayout_LeftToRight, "Spanish (Uruguay)") + LNG(wxLANGUAGE_SPANISH_US, "es_US", 0 , 0 , wxLayout_LeftToRight, "Spanish (U.S.)") + LNG(wxLANGUAGE_SPANISH_VENEZUELA, "es_VE", LANG_SPANISH , SUBLANG_SPANISH_VENEZUELA , wxLayout_LeftToRight, "Spanish (Venezuela)") + LNG(wxLANGUAGE_SUNDANESE, "su" , 0 , 0 , wxLayout_LeftToRight, "Sundanese") + LNG(wxLANGUAGE_SWAHILI, "sw_KE", LANG_SWAHILI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Swahili") + LNG(wxLANGUAGE_SWEDISH, "sv_SE", LANG_SWEDISH , SUBLANG_SWEDISH , wxLayout_LeftToRight, "Swedish") + LNG(wxLANGUAGE_SWEDISH_FINLAND, "sv_FI", LANG_SWEDISH , SUBLANG_SWEDISH_FINLAND , wxLayout_LeftToRight, "Swedish (Finland)") + LNG(wxLANGUAGE_TAGALOG, "tl_PH", 0 , 0 , wxLayout_LeftToRight, "Tagalog") + LNG(wxLANGUAGE_TAJIK, "tg" , 0 , 0 , wxLayout_LeftToRight, "Tajik") + LNG(wxLANGUAGE_TAMIL, "ta" , LANG_TAMIL , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Tamil") + LNG(wxLANGUAGE_TATAR, "tt" , LANG_TATAR , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Tatar") + LNG(wxLANGUAGE_TELUGU, "te" , LANG_TELUGU , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Telugu") + LNG(wxLANGUAGE_THAI, "th_TH", LANG_THAI , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Thai") + LNG(wxLANGUAGE_TIBETAN, "bo" , 0 , 0 , wxLayout_LeftToRight, "Tibetan") + LNG(wxLANGUAGE_TIGRINYA, "ti" , 0 , 0 , wxLayout_LeftToRight, "Tigrinya") + LNG(wxLANGUAGE_TONGA, "to" , 0 , 0 , wxLayout_LeftToRight, "Tonga") + LNG(wxLANGUAGE_TSONGA, "ts" , 0 , 0 , wxLayout_LeftToRight, "Tsonga") + LNG(wxLANGUAGE_TURKISH, "tr_TR", LANG_TURKISH , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Turkish") + LNG(wxLANGUAGE_TURKMEN, "tk" , 0 , 0 , wxLayout_LeftToRight, "Turkmen") + LNG(wxLANGUAGE_TWI, "tw" , 0 , 0 , wxLayout_LeftToRight, "Twi") + LNG(wxLANGUAGE_UIGHUR, "ug" , 0 , 0 , wxLayout_LeftToRight, "Uighur") + LNG(wxLANGUAGE_UKRAINIAN, "uk_UA", LANG_UKRAINIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Ukrainian") + LNG(wxLANGUAGE_URDU, "ur" , LANG_URDU , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Urdu") + LNG(wxLANGUAGE_URDU_INDIA, "ur_IN", LANG_URDU , SUBLANG_URDU_INDIA , wxLayout_LeftToRight, "Urdu (India)") + LNG(wxLANGUAGE_URDU_PAKISTAN, "ur_PK", LANG_URDU , SUBLANG_URDU_PAKISTAN , wxLayout_LeftToRight, "Urdu (Pakistan)") + LNG(wxLANGUAGE_UZBEK, "uz" , LANG_UZBEK , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Uzbek") + LNG(wxLANGUAGE_UZBEK_CYRILLIC, "uz" , LANG_UZBEK , SUBLANG_UZBEK_CYRILLIC , wxLayout_LeftToRight, "Uzbek (Cyrillic)") + LNG(wxLANGUAGE_UZBEK_LATIN, "uz" , LANG_UZBEK , SUBLANG_UZBEK_LATIN , wxLayout_LeftToRight, "Uzbek (Latin)") + LNG(wxLANGUAGE_VALENCIAN, "ca_ES@valencia", LANG_VALENCIAN , SUBLANG_DEFAULT , wxLayout_LeftToRight, "Valencian") + LNG(wxLANGUAGE_VIETNAMESE, "vi_VN", LANG_VIETNAMESE, SUBLANG_DEFAULT , wxLayout_LeftToRight, "Vietnamese") + LNG(wxLANGUAGE_VOLAPUK, "vo" , 0 , 0 , wxLayout_LeftToRight, "Volapuk") + LNG(wxLANGUAGE_WELSH, "cy" , 0 , 0 , wxLayout_LeftToRight, "Welsh") + LNG(wxLANGUAGE_WOLOF, "wo" , 0 , 0 , wxLayout_LeftToRight, "Wolof") + LNG(wxLANGUAGE_XHOSA, "xh" , 0 , 0 , wxLayout_LeftToRight, "Xhosa") + LNG(wxLANGUAGE_YIDDISH, "yi" , 0 , 0 , wxLayout_LeftToRight, "Yiddish") + LNG(wxLANGUAGE_YORUBA, "yo" , 0 , 0 , wxLayout_LeftToRight, "Yoruba") + LNG(wxLANGUAGE_ZHUANG, "za" , 0 , 0 , wxLayout_LeftToRight, "Zhuang") + LNG(wxLANGUAGE_ZULU, "zu" , 0 , 0 , wxLayout_LeftToRight, "Zulu") +} +#undef LNG + +// --- --- --- generated code ends here --- --- --- + +#endif // wxUSE_INTL diff --git a/Source/3rd Party/wx/src/common/ipcbase.cpp b/Source/3rd Party/wx/src/common/ipcbase.cpp index 1a3894a0c..80fa9412d 100644 --- a/Source/3rd Party/wx/src/common/ipcbase.cpp +++ b/Source/3rd Party/wx/src/common/ipcbase.cpp @@ -1,87 +1,87 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/ipcbase.cpp -// Purpose: IPC base classes -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: ipcbase.cpp 54615 2008-07-14 02:34:29Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP -#endif - -#include "wx/ipcbase.h" - -IMPLEMENT_CLASS(wxServerBase, wxObject) -IMPLEMENT_CLASS(wxClientBase, wxObject) -IMPLEMENT_CLASS(wxConnectionBase, wxObject) - -wxConnectionBase::wxConnectionBase(wxChar *buffer, int bytes) - : m_connected(true), - m_buffer(buffer), - m_buffersize(bytes), - m_deletebufferwhendone(false) -{ - if ( buffer == (wxChar *)NULL ) - { // behave like next constructor - m_buffersize = 0; - m_deletebufferwhendone = true; - } -} - -wxConnectionBase::wxConnectionBase() - : m_connected(true), - m_buffer(NULL), - m_buffersize(0), - m_deletebufferwhendone(true) -{ -} - -wxConnectionBase::wxConnectionBase(const wxConnectionBase& copy) - : wxObject(), - m_connected(copy.m_connected), - m_buffer(copy.m_buffer), - m_buffersize(copy.m_buffersize), - m_deletebufferwhendone(false) - -{ - // copy constructor would require ref-counted pointer to buffer - wxFAIL_MSG( _T("Copy constructor of wxConnectionBase not implemented") ); -} - - -wxConnectionBase::~wxConnectionBase(void) -{ - if ( m_deletebufferwhendone ) - delete [] m_buffer; -} - -wxChar *wxConnectionBase::GetBufferAtLeast( size_t bytes ) -{ - if ( m_buffersize >= bytes ) - return m_buffer; - else - { // need to resize buffer - if ( m_deletebufferwhendone ) - { // we're in charge of buffer, increase it - delete [] m_buffer; - // the argument specifies **byte size**, but m_buffer is of type - // wxChar. Under unicode: sizeof(wxChar) > 1, so the buffer size is - // bytes / sizeof(wxChar) rounded upwards. - m_buffer = new wxChar[(bytes + sizeof(wxChar) - 1) / sizeof(wxChar)]; - m_buffersize = bytes; - return m_buffer; - } // user-supplied buffer, fail - else - return NULL; - } -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/ipcbase.cpp +// Purpose: IPC base classes +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: ipcbase.cpp 54615 2008-07-14 02:34:29Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#endif + +#include "wx/ipcbase.h" + +IMPLEMENT_CLASS(wxServerBase, wxObject) +IMPLEMENT_CLASS(wxClientBase, wxObject) +IMPLEMENT_CLASS(wxConnectionBase, wxObject) + +wxConnectionBase::wxConnectionBase(wxChar *buffer, int bytes) + : m_connected(true), + m_buffer(buffer), + m_buffersize(bytes), + m_deletebufferwhendone(false) +{ + if ( buffer == (wxChar *)NULL ) + { // behave like next constructor + m_buffersize = 0; + m_deletebufferwhendone = true; + } +} + +wxConnectionBase::wxConnectionBase() + : m_connected(true), + m_buffer(NULL), + m_buffersize(0), + m_deletebufferwhendone(true) +{ +} + +wxConnectionBase::wxConnectionBase(const wxConnectionBase& copy) + : wxObject(), + m_connected(copy.m_connected), + m_buffer(copy.m_buffer), + m_buffersize(copy.m_buffersize), + m_deletebufferwhendone(false) + +{ + // copy constructor would require ref-counted pointer to buffer + wxFAIL_MSG( _T("Copy constructor of wxConnectionBase not implemented") ); +} + + +wxConnectionBase::~wxConnectionBase(void) +{ + if ( m_deletebufferwhendone ) + delete [] m_buffer; +} + +wxChar *wxConnectionBase::GetBufferAtLeast( size_t bytes ) +{ + if ( m_buffersize >= bytes ) + return m_buffer; + else + { // need to resize buffer + if ( m_deletebufferwhendone ) + { // we're in charge of buffer, increase it + delete [] m_buffer; + // the argument specifies **byte size**, but m_buffer is of type + // wxChar. Under unicode: sizeof(wxChar) > 1, so the buffer size is + // bytes / sizeof(wxChar) rounded upwards. + m_buffer = new wxChar[(bytes + sizeof(wxChar) - 1) / sizeof(wxChar)]; + m_buffersize = bytes; + return m_buffer; + } // user-supplied buffer, fail + else + return NULL; + } +} diff --git a/Source/3rd Party/wx/src/common/layout.cpp b/Source/3rd Party/wx/src/common/layout.cpp index 9df71dce7..d796eee1f 100644 --- a/Source/3rd Party/wx/src/common/layout.cpp +++ b/Source/3rd Party/wx/src/common/layout.cpp @@ -1,1026 +1,1026 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/layout.cpp -// Purpose: Constraint layout system classes -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: layout.cpp 39627 2006-06-08 06:57:39Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================= -// declarations -// ============================================================================= - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_CONSTRAINTS - -#include "wx/layout.h" - -#ifndef WX_PRECOMP - #include "wx/window.h" - #include "wx/utils.h" - #include "wx/dialog.h" - #include "wx/msgdlg.h" - #include "wx/intl.h" -#endif - - -IMPLEMENT_DYNAMIC_CLASS(wxIndividualLayoutConstraint, wxObject) -IMPLEMENT_DYNAMIC_CLASS(wxLayoutConstraints, wxObject) - - -inline void wxGetAsIs(wxWindowBase* win, int* w, int* h) -{ -#if 1 - // The old way. Works for me. - win->GetSize(w, h); -#endif - -#if 0 - // Vadim's change. Breaks wxPython's LayoutAnchors - win->GetBestSize(w, h); -#endif - -#if 0 - // Proposed compromise. Doesn't work. - int sw, sh, bw, bh; - win->GetSize(&sw, &sh); - win->GetBestSize(&bw, &bh); - if (w) - *w = wxMax(sw, bw); - if (h) - *h = wxMax(sh, bh); -#endif -} - - -wxIndividualLayoutConstraint::wxIndividualLayoutConstraint() -{ - myEdge = wxTop; - relationship = wxUnconstrained; - margin = 0; - value = 0; - percent = 0; - otherEdge = wxTop; - done = false; - otherWin = (wxWindowBase *) NULL; -} - -void wxIndividualLayoutConstraint::Set(wxRelationship rel, wxWindowBase *otherW, wxEdge otherE, int val, int marg) -{ - if (rel == wxSameAs) - { - // If Set is called by the user with wxSameAs then call SameAs to do - // it since it will actually use wxPercent instead. - SameAs(otherW, otherE, marg); - return; - } - - relationship = rel; - otherWin = otherW; - otherEdge = otherE; - - if ( rel == wxPercentOf ) - { - percent = val; - } - else - { - value = val; - } - - margin = marg; -} - -void wxIndividualLayoutConstraint::LeftOf(wxWindowBase *sibling, int marg) -{ - Set(wxLeftOf, sibling, wxLeft, 0, marg); -} - -void wxIndividualLayoutConstraint::RightOf(wxWindowBase *sibling, int marg) -{ - Set(wxRightOf, sibling, wxRight, 0, marg); -} - -void wxIndividualLayoutConstraint::Above(wxWindowBase *sibling, int marg) -{ - Set(wxAbove, sibling, wxTop, 0, marg); -} - -void wxIndividualLayoutConstraint::Below(wxWindowBase *sibling, int marg) -{ - Set(wxBelow, sibling, wxBottom, 0, marg); -} - -// -// 'Same edge' alignment -// -void wxIndividualLayoutConstraint::SameAs(wxWindowBase *otherW, wxEdge edge, int marg) -{ - Set(wxPercentOf, otherW, edge, 100, marg); -} - -// The edge is a percentage of the other window's edge -void wxIndividualLayoutConstraint::PercentOf(wxWindowBase *otherW, wxEdge wh, int per) -{ - Set(wxPercentOf, otherW, wh, per); -} - -// -// Edge has absolute value -// -void wxIndividualLayoutConstraint::Absolute(int val) -{ - value = val; - relationship = wxAbsolute; -} - -// Reset constraint if it mentions otherWin -bool wxIndividualLayoutConstraint::ResetIfWin(wxWindowBase *otherW) -{ - if (otherW == otherWin) - { - myEdge = wxTop; - relationship = wxAsIs; - margin = 0; - value = 0; - percent = 0; - otherEdge = wxTop; - otherWin = (wxWindowBase *) NULL; - return true; - } - - return false; -} - -// Try to satisfy constraint -bool wxIndividualLayoutConstraint::SatisfyConstraint(wxLayoutConstraints *constraints, wxWindowBase *win) -{ - if (relationship == wxAbsolute) - { - done = true; - return true; - } - - switch (myEdge) - { - case wxLeft: - { - switch (relationship) - { - case wxLeftOf: - { - // We can know this edge if: otherWin is win's - // parent, or otherWin has a satisfied constraint, - // or otherWin has no constraint. - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos - margin; - done = true; - return true; - } - else - return false; - } - case wxRightOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos + margin; - done = true; - return true; - } - else - return false; - } - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01) + margin); - done = true; - return true; - } - else - return false; - } - case wxUnconstrained: - { - // We know the left-hand edge position if we know - // the right-hand edge and we know the width; OR if - // we know the centre and the width. - if (constraints->right.GetDone() && constraints->width.GetDone()) - { - value = (constraints->right.GetValue() - constraints->width.GetValue() + margin); - done = true; - return true; - } - else if (constraints->centreX.GetDone() && constraints->width.GetDone()) - { - value = (int)(constraints->centreX.GetValue() - (constraints->width.GetValue()/2) + margin); - done = true; - return true; - } - else - return false; - } - case wxAsIs: - { - int y; - win->GetPosition(&value, &y); - done = true; - return true; - } - default: - break; - } - break; - } - case wxRight: - { - switch (relationship) - { - case wxLeftOf: - { - // We can know this edge if: otherWin is win's - // parent, or otherWin has a satisfied constraint, - // or otherWin has no constraint. - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos - margin; - done = true; - return true; - } - else - return false; - } - case wxRightOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos + margin; - done = true; - return true; - } - else - return false; - } - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01) - margin); - done = true; - return true; - } - else - return false; - } - case wxUnconstrained: - { - // We know the right-hand edge position if we know the - // left-hand edge and we know the width, OR if we know the - // centre edge and the width. - if (constraints->left.GetDone() && constraints->width.GetDone()) - { - value = (constraints->left.GetValue() + constraints->width.GetValue() - margin); - done = true; - return true; - } - else if (constraints->centreX.GetDone() && constraints->width.GetDone()) - { - value = (int)(constraints->centreX.GetValue() + (constraints->width.GetValue()/2) - margin); - done = true; - return true; - } - else - return false; - } - case wxAsIs: - { - int x, y; - int w, h; - wxGetAsIs(win, &w, &h); - win->GetPosition(&x, &y); - value = x + w; - done = true; - return true; - } - default: - break; - } - break; - } - case wxTop: - { - switch (relationship) - { - case wxAbove: - { - // We can know this edge if: otherWin is win's - // parent, or otherWin has a satisfied constraint, - // or otherWin has no constraint. - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos - margin; - done = true; - return true; - } - else - return false; - } - case wxBelow: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos + margin; - done = true; - return true; - } - else - return false; - } - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01) + margin); - done = true; - return true; - } - else - return false; - } - case wxUnconstrained: - { - // We know the top edge position if we know the bottom edge - // and we know the height; OR if we know the centre edge and - // the height. - if (constraints->bottom.GetDone() && constraints->height.GetDone()) - { - value = (constraints->bottom.GetValue() - constraints->height.GetValue() + margin); - done = true; - return true; - } - else if (constraints->centreY.GetDone() && constraints->height.GetDone()) - { - value = (constraints->centreY.GetValue() - (constraints->height.GetValue()/2) + margin); - done = true; - return true; - } - else - return false; - } - case wxAsIs: - { - int x; - win->GetPosition(&x, &value); - done = true; - return true; - } - default: - break; - } - break; - } - case wxBottom: - { - switch (relationship) - { - case wxAbove: - { - // We can know this edge if: otherWin is win's parent, - // or otherWin has a satisfied constraint, or - // otherWin has no constraint. - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos + margin; - done = true; - return true; - } - else - return false; - } - case wxBelow: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos - margin; - done = true; - return true; - } - else - return false; - } - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01) - margin); - done = true; - return true; - } - else - return false; - } - case wxUnconstrained: - { - // We know the bottom edge position if we know the top edge - // and we know the height; OR if we know the centre edge and - // the height. - if (constraints->top.GetDone() && constraints->height.GetDone()) - { - value = (constraints->top.GetValue() + constraints->height.GetValue() - margin); - done = true; - return true; - } - else if (constraints->centreY.GetDone() && constraints->height.GetDone()) - { - value = (constraints->centreY.GetValue() + (constraints->height.GetValue()/2) - margin); - done = true; - return true; - } - else - return false; - } - case wxAsIs: - { - int x, y; - int w, h; - wxGetAsIs(win, &w, &h); - win->GetPosition(&x, &y); - value = h + y; - done = true; - return true; - } - default: - break; - } - break; - } - case wxCentreX: - { - switch (relationship) - { - case wxLeftOf: - { - // We can know this edge if: otherWin is win's parent, or - // otherWin has a satisfied constraint, or otherWin has no - // constraint. - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos - margin; - done = true; - return true; - } - else - return false; - } - case wxRightOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos + margin; - done = true; - return true; - } - else - return false; - } - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01) + margin); - done = true; - return true; - } - else - return false; - } - case wxUnconstrained: - { - // We know the centre position if we know - // the left-hand edge and we know the width, OR - // the right-hand edge and the width - if (constraints->left.GetDone() && constraints->width.GetDone()) - { - value = (int)(constraints->left.GetValue() + (constraints->width.GetValue()/2) + margin); - done = true; - return true; - } - else if (constraints->right.GetDone() && constraints->width.GetDone()) - { - value = (int)(constraints->left.GetValue() - (constraints->width.GetValue()/2) + margin); - done = true; - return true; - } - else - return false; - } - default: - break; - } - break; - } - case wxCentreY: - { - switch (relationship) - { - case wxAbove: - { - // We can know this edge if: otherWin is win's parent, - // or otherWin has a satisfied constraint, or otherWin - // has no constraint. - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos - margin; - done = true; - return true; - } - else - return false; - } - case wxBelow: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = edgePos + margin; - done = true; - return true; - } - else - return false; - } - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01) + margin); - done = true; - return true; - } - else - return false; - } - case wxUnconstrained: - { - // We know the centre position if we know - // the top edge and we know the height, OR - // the bottom edge and the height. - if (constraints->bottom.GetDone() && constraints->height.GetDone()) - { - value = (int)(constraints->bottom.GetValue() - (constraints->height.GetValue()/2) + margin); - done = true; - return true; - } - else if (constraints->top.GetDone() && constraints->height.GetDone()) - { - value = (int)(constraints->top.GetValue() + (constraints->height.GetValue()/2) + margin); - done = true; - return true; - } - else - return false; - } - default: - break; - } - break; - } - case wxWidth: - { - switch (relationship) - { - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01)); - done = true; - return true; - } - else - return false; - } - case wxAsIs: - { - if (win) - { - int h; - wxGetAsIs(win, &value, &h); - done = true; - return true; - } - else return false; - } - case wxUnconstrained: - { - // We know the width if we know the left edge and the right edge, OR - // if we know the left edge and the centre, OR - // if we know the right edge and the centre - if (constraints->left.GetDone() && constraints->right.GetDone()) - { - value = constraints->right.GetValue() - constraints->left.GetValue(); - done = true; - return true; - } - else if (constraints->centreX.GetDone() && constraints->left.GetDone()) - { - value = (int)(2*(constraints->centreX.GetValue() - constraints->left.GetValue())); - done = true; - return true; - } - else if (constraints->centreX.GetDone() && constraints->right.GetDone()) - { - value = (int)(2*(constraints->right.GetValue() - constraints->centreX.GetValue())); - done = true; - return true; - } - else - return false; - } - default: - break; - } - break; - } - case wxHeight: - { - switch (relationship) - { - case wxPercentOf: - { - int edgePos = GetEdge(otherEdge, win, otherWin); - if (edgePos != -1) - { - value = (int)(edgePos*(((float)percent)*0.01)); - done = true; - return true; - } - else - return false; - } - case wxAsIs: - { - if (win) - { - int w; - wxGetAsIs(win, &w, &value); - done = true; - return true; - } - else return false; - } - case wxUnconstrained: - { - // We know the height if we know the top edge and the bottom edge, OR - // if we know the top edge and the centre, OR - // if we know the bottom edge and the centre - if (constraints->top.GetDone() && constraints->bottom.GetDone()) - { - value = constraints->bottom.GetValue() - constraints->top.GetValue(); - done = true; - return true; - } - else if (constraints->top.GetDone() && constraints->centreY.GetDone()) - { - value = (int)(2*(constraints->centreY.GetValue() - constraints->top.GetValue())); - done = true; - return true; - } - else if (constraints->bottom.GetDone() && constraints->centreY.GetDone()) - { - value = (int)(2*(constraints->bottom.GetValue() - constraints->centreY.GetValue())); - done = true; - return true; - } - else - return false; - } - default: - break; - } - break; - } - default: - break; - } - return false; -} - -// Get the value of this edge or dimension, or if this is not determinable, -1. -int wxIndividualLayoutConstraint::GetEdge(wxEdge which, - wxWindowBase *thisWin, - wxWindowBase *other) const -{ - // If the edge or dimension belongs to the parent, then we know the - // dimension is obtainable immediately. E.g. a wxExpandSizer may contain a - // button (but the button's true parent is a panel, not the sizer) - if (other->GetChildren().Find((wxWindow*)thisWin)) - { - switch (which) - { - case wxLeft: - { - return 0; - } - case wxTop: - { - return 0; - } - case wxRight: - { - int w, h; - other->GetClientSizeConstraint(&w, &h); - return w; - } - case wxBottom: - { - int w, h; - other->GetClientSizeConstraint(&w, &h); - return h; - } - case wxWidth: - { - int w, h; - other->GetClientSizeConstraint(&w, &h); - return w; - } - case wxHeight: - { - int w, h; - other->GetClientSizeConstraint(&w, &h); - return h; - } - case wxCentreX: - case wxCentreY: - { - int w, h; - other->GetClientSizeConstraint(&w, &h); - if (which == wxCentreX) - return (int)(w/2); - else - return (int)(h/2); - } - default: - return -1; - } - } - switch (which) - { - case wxLeft: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->left.GetDone()) - return constr->left.GetValue(); - else - return -1; - } - else - { - int x, y; - other->GetPosition(&x, &y); - return x; - } - } - case wxTop: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->top.GetDone()) - return constr->top.GetValue(); - else - return -1; - } - else - { - int x, y; - other->GetPosition(&x, &y); - return y; - } - } - case wxRight: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->right.GetDone()) - return constr->right.GetValue(); - else - return -1; - } - else - { - int x, y, w, h; - other->GetPosition(&x, &y); - other->GetSize(&w, &h); - return (int)(x + w); - } - } - case wxBottom: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->bottom.GetDone()) - return constr->bottom.GetValue(); - else - return -1; - } - else - { - int x, y, w, h; - other->GetPosition(&x, &y); - other->GetSize(&w, &h); - return (int)(y + h); - } - } - case wxWidth: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->width.GetDone()) - return constr->width.GetValue(); - else - return -1; - } - else - { - int w, h; - other->GetSize(&w, &h); - return w; - } - } - case wxHeight: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->height.GetDone()) - return constr->height.GetValue(); - else - return -1; - } - else - { - int w, h; - other->GetSize(&w, &h); - return h; - } - } - case wxCentreX: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->centreX.GetDone()) - return constr->centreX.GetValue(); - else - return -1; - } - else - { - int x, y, w, h; - other->GetPosition(&x, &y); - other->GetSize(&w, &h); - return (int)(x + (w/2)); - } - } - case wxCentreY: - { - wxLayoutConstraints *constr = other->GetConstraints(); - // If no constraints, it means the window is not dependent - // on anything, and therefore we know its value immediately - if (constr) - { - if (constr->centreY.GetDone()) - return constr->centreY.GetValue(); - else - return -1; - } - else - { - int x, y, w, h; - other->GetPosition(&x, &y); - other->GetSize(&w, &h); - return (int)(y + (h/2)); - } - } - default: - break; - } - return -1; -} - -wxLayoutConstraints::wxLayoutConstraints() -{ - left.SetEdge(wxLeft); - top.SetEdge(wxTop); - right.SetEdge(wxRight); - bottom.SetEdge(wxBottom); - centreX.SetEdge(wxCentreX); - centreY.SetEdge(wxCentreY); - width.SetEdge(wxWidth); - height.SetEdge(wxHeight); -} - -bool wxLayoutConstraints::SatisfyConstraints(wxWindowBase *win, int *nChanges) -{ - int noChanges = 0; - - bool done = width.GetDone(); - bool newDone = (done ? true : width.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - done = height.GetDone(); - newDone = (done ? true : height.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - done = left.GetDone(); - newDone = (done ? true : left.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - done = top.GetDone(); - newDone = (done ? true : top.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - done = right.GetDone(); - newDone = (done ? true : right.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - done = bottom.GetDone(); - newDone = (done ? true : bottom.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - done = centreX.GetDone(); - newDone = (done ? true : centreX.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - done = centreY.GetDone(); - newDone = (done ? true : centreY.SatisfyConstraint(this, win)); - if (newDone != done) - noChanges ++; - - *nChanges = noChanges; - - return AreSatisfied(); -} - -#endif // wxUSE_CONSTRAINTS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/layout.cpp +// Purpose: Constraint layout system classes +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: layout.cpp 39627 2006-06-08 06:57:39Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================= +// declarations +// ============================================================================= + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_CONSTRAINTS + +#include "wx/layout.h" + +#ifndef WX_PRECOMP + #include "wx/window.h" + #include "wx/utils.h" + #include "wx/dialog.h" + #include "wx/msgdlg.h" + #include "wx/intl.h" +#endif + + +IMPLEMENT_DYNAMIC_CLASS(wxIndividualLayoutConstraint, wxObject) +IMPLEMENT_DYNAMIC_CLASS(wxLayoutConstraints, wxObject) + + +inline void wxGetAsIs(wxWindowBase* win, int* w, int* h) +{ +#if 1 + // The old way. Works for me. + win->GetSize(w, h); +#endif + +#if 0 + // Vadim's change. Breaks wxPython's LayoutAnchors + win->GetBestSize(w, h); +#endif + +#if 0 + // Proposed compromise. Doesn't work. + int sw, sh, bw, bh; + win->GetSize(&sw, &sh); + win->GetBestSize(&bw, &bh); + if (w) + *w = wxMax(sw, bw); + if (h) + *h = wxMax(sh, bh); +#endif +} + + +wxIndividualLayoutConstraint::wxIndividualLayoutConstraint() +{ + myEdge = wxTop; + relationship = wxUnconstrained; + margin = 0; + value = 0; + percent = 0; + otherEdge = wxTop; + done = false; + otherWin = (wxWindowBase *) NULL; +} + +void wxIndividualLayoutConstraint::Set(wxRelationship rel, wxWindowBase *otherW, wxEdge otherE, int val, int marg) +{ + if (rel == wxSameAs) + { + // If Set is called by the user with wxSameAs then call SameAs to do + // it since it will actually use wxPercent instead. + SameAs(otherW, otherE, marg); + return; + } + + relationship = rel; + otherWin = otherW; + otherEdge = otherE; + + if ( rel == wxPercentOf ) + { + percent = val; + } + else + { + value = val; + } + + margin = marg; +} + +void wxIndividualLayoutConstraint::LeftOf(wxWindowBase *sibling, int marg) +{ + Set(wxLeftOf, sibling, wxLeft, 0, marg); +} + +void wxIndividualLayoutConstraint::RightOf(wxWindowBase *sibling, int marg) +{ + Set(wxRightOf, sibling, wxRight, 0, marg); +} + +void wxIndividualLayoutConstraint::Above(wxWindowBase *sibling, int marg) +{ + Set(wxAbove, sibling, wxTop, 0, marg); +} + +void wxIndividualLayoutConstraint::Below(wxWindowBase *sibling, int marg) +{ + Set(wxBelow, sibling, wxBottom, 0, marg); +} + +// +// 'Same edge' alignment +// +void wxIndividualLayoutConstraint::SameAs(wxWindowBase *otherW, wxEdge edge, int marg) +{ + Set(wxPercentOf, otherW, edge, 100, marg); +} + +// The edge is a percentage of the other window's edge +void wxIndividualLayoutConstraint::PercentOf(wxWindowBase *otherW, wxEdge wh, int per) +{ + Set(wxPercentOf, otherW, wh, per); +} + +// +// Edge has absolute value +// +void wxIndividualLayoutConstraint::Absolute(int val) +{ + value = val; + relationship = wxAbsolute; +} + +// Reset constraint if it mentions otherWin +bool wxIndividualLayoutConstraint::ResetIfWin(wxWindowBase *otherW) +{ + if (otherW == otherWin) + { + myEdge = wxTop; + relationship = wxAsIs; + margin = 0; + value = 0; + percent = 0; + otherEdge = wxTop; + otherWin = (wxWindowBase *) NULL; + return true; + } + + return false; +} + +// Try to satisfy constraint +bool wxIndividualLayoutConstraint::SatisfyConstraint(wxLayoutConstraints *constraints, wxWindowBase *win) +{ + if (relationship == wxAbsolute) + { + done = true; + return true; + } + + switch (myEdge) + { + case wxLeft: + { + switch (relationship) + { + case wxLeftOf: + { + // We can know this edge if: otherWin is win's + // parent, or otherWin has a satisfied constraint, + // or otherWin has no constraint. + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos - margin; + done = true; + return true; + } + else + return false; + } + case wxRightOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos + margin; + done = true; + return true; + } + else + return false; + } + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01) + margin); + done = true; + return true; + } + else + return false; + } + case wxUnconstrained: + { + // We know the left-hand edge position if we know + // the right-hand edge and we know the width; OR if + // we know the centre and the width. + if (constraints->right.GetDone() && constraints->width.GetDone()) + { + value = (constraints->right.GetValue() - constraints->width.GetValue() + margin); + done = true; + return true; + } + else if (constraints->centreX.GetDone() && constraints->width.GetDone()) + { + value = (int)(constraints->centreX.GetValue() - (constraints->width.GetValue()/2) + margin); + done = true; + return true; + } + else + return false; + } + case wxAsIs: + { + int y; + win->GetPosition(&value, &y); + done = true; + return true; + } + default: + break; + } + break; + } + case wxRight: + { + switch (relationship) + { + case wxLeftOf: + { + // We can know this edge if: otherWin is win's + // parent, or otherWin has a satisfied constraint, + // or otherWin has no constraint. + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos - margin; + done = true; + return true; + } + else + return false; + } + case wxRightOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos + margin; + done = true; + return true; + } + else + return false; + } + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01) - margin); + done = true; + return true; + } + else + return false; + } + case wxUnconstrained: + { + // We know the right-hand edge position if we know the + // left-hand edge and we know the width, OR if we know the + // centre edge and the width. + if (constraints->left.GetDone() && constraints->width.GetDone()) + { + value = (constraints->left.GetValue() + constraints->width.GetValue() - margin); + done = true; + return true; + } + else if (constraints->centreX.GetDone() && constraints->width.GetDone()) + { + value = (int)(constraints->centreX.GetValue() + (constraints->width.GetValue()/2) - margin); + done = true; + return true; + } + else + return false; + } + case wxAsIs: + { + int x, y; + int w, h; + wxGetAsIs(win, &w, &h); + win->GetPosition(&x, &y); + value = x + w; + done = true; + return true; + } + default: + break; + } + break; + } + case wxTop: + { + switch (relationship) + { + case wxAbove: + { + // We can know this edge if: otherWin is win's + // parent, or otherWin has a satisfied constraint, + // or otherWin has no constraint. + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos - margin; + done = true; + return true; + } + else + return false; + } + case wxBelow: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos + margin; + done = true; + return true; + } + else + return false; + } + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01) + margin); + done = true; + return true; + } + else + return false; + } + case wxUnconstrained: + { + // We know the top edge position if we know the bottom edge + // and we know the height; OR if we know the centre edge and + // the height. + if (constraints->bottom.GetDone() && constraints->height.GetDone()) + { + value = (constraints->bottom.GetValue() - constraints->height.GetValue() + margin); + done = true; + return true; + } + else if (constraints->centreY.GetDone() && constraints->height.GetDone()) + { + value = (constraints->centreY.GetValue() - (constraints->height.GetValue()/2) + margin); + done = true; + return true; + } + else + return false; + } + case wxAsIs: + { + int x; + win->GetPosition(&x, &value); + done = true; + return true; + } + default: + break; + } + break; + } + case wxBottom: + { + switch (relationship) + { + case wxAbove: + { + // We can know this edge if: otherWin is win's parent, + // or otherWin has a satisfied constraint, or + // otherWin has no constraint. + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos + margin; + done = true; + return true; + } + else + return false; + } + case wxBelow: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos - margin; + done = true; + return true; + } + else + return false; + } + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01) - margin); + done = true; + return true; + } + else + return false; + } + case wxUnconstrained: + { + // We know the bottom edge position if we know the top edge + // and we know the height; OR if we know the centre edge and + // the height. + if (constraints->top.GetDone() && constraints->height.GetDone()) + { + value = (constraints->top.GetValue() + constraints->height.GetValue() - margin); + done = true; + return true; + } + else if (constraints->centreY.GetDone() && constraints->height.GetDone()) + { + value = (constraints->centreY.GetValue() + (constraints->height.GetValue()/2) - margin); + done = true; + return true; + } + else + return false; + } + case wxAsIs: + { + int x, y; + int w, h; + wxGetAsIs(win, &w, &h); + win->GetPosition(&x, &y); + value = h + y; + done = true; + return true; + } + default: + break; + } + break; + } + case wxCentreX: + { + switch (relationship) + { + case wxLeftOf: + { + // We can know this edge if: otherWin is win's parent, or + // otherWin has a satisfied constraint, or otherWin has no + // constraint. + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos - margin; + done = true; + return true; + } + else + return false; + } + case wxRightOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos + margin; + done = true; + return true; + } + else + return false; + } + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01) + margin); + done = true; + return true; + } + else + return false; + } + case wxUnconstrained: + { + // We know the centre position if we know + // the left-hand edge and we know the width, OR + // the right-hand edge and the width + if (constraints->left.GetDone() && constraints->width.GetDone()) + { + value = (int)(constraints->left.GetValue() + (constraints->width.GetValue()/2) + margin); + done = true; + return true; + } + else if (constraints->right.GetDone() && constraints->width.GetDone()) + { + value = (int)(constraints->left.GetValue() - (constraints->width.GetValue()/2) + margin); + done = true; + return true; + } + else + return false; + } + default: + break; + } + break; + } + case wxCentreY: + { + switch (relationship) + { + case wxAbove: + { + // We can know this edge if: otherWin is win's parent, + // or otherWin has a satisfied constraint, or otherWin + // has no constraint. + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos - margin; + done = true; + return true; + } + else + return false; + } + case wxBelow: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = edgePos + margin; + done = true; + return true; + } + else + return false; + } + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01) + margin); + done = true; + return true; + } + else + return false; + } + case wxUnconstrained: + { + // We know the centre position if we know + // the top edge and we know the height, OR + // the bottom edge and the height. + if (constraints->bottom.GetDone() && constraints->height.GetDone()) + { + value = (int)(constraints->bottom.GetValue() - (constraints->height.GetValue()/2) + margin); + done = true; + return true; + } + else if (constraints->top.GetDone() && constraints->height.GetDone()) + { + value = (int)(constraints->top.GetValue() + (constraints->height.GetValue()/2) + margin); + done = true; + return true; + } + else + return false; + } + default: + break; + } + break; + } + case wxWidth: + { + switch (relationship) + { + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01)); + done = true; + return true; + } + else + return false; + } + case wxAsIs: + { + if (win) + { + int h; + wxGetAsIs(win, &value, &h); + done = true; + return true; + } + else return false; + } + case wxUnconstrained: + { + // We know the width if we know the left edge and the right edge, OR + // if we know the left edge and the centre, OR + // if we know the right edge and the centre + if (constraints->left.GetDone() && constraints->right.GetDone()) + { + value = constraints->right.GetValue() - constraints->left.GetValue(); + done = true; + return true; + } + else if (constraints->centreX.GetDone() && constraints->left.GetDone()) + { + value = (int)(2*(constraints->centreX.GetValue() - constraints->left.GetValue())); + done = true; + return true; + } + else if (constraints->centreX.GetDone() && constraints->right.GetDone()) + { + value = (int)(2*(constraints->right.GetValue() - constraints->centreX.GetValue())); + done = true; + return true; + } + else + return false; + } + default: + break; + } + break; + } + case wxHeight: + { + switch (relationship) + { + case wxPercentOf: + { + int edgePos = GetEdge(otherEdge, win, otherWin); + if (edgePos != -1) + { + value = (int)(edgePos*(((float)percent)*0.01)); + done = true; + return true; + } + else + return false; + } + case wxAsIs: + { + if (win) + { + int w; + wxGetAsIs(win, &w, &value); + done = true; + return true; + } + else return false; + } + case wxUnconstrained: + { + // We know the height if we know the top edge and the bottom edge, OR + // if we know the top edge and the centre, OR + // if we know the bottom edge and the centre + if (constraints->top.GetDone() && constraints->bottom.GetDone()) + { + value = constraints->bottom.GetValue() - constraints->top.GetValue(); + done = true; + return true; + } + else if (constraints->top.GetDone() && constraints->centreY.GetDone()) + { + value = (int)(2*(constraints->centreY.GetValue() - constraints->top.GetValue())); + done = true; + return true; + } + else if (constraints->bottom.GetDone() && constraints->centreY.GetDone()) + { + value = (int)(2*(constraints->bottom.GetValue() - constraints->centreY.GetValue())); + done = true; + return true; + } + else + return false; + } + default: + break; + } + break; + } + default: + break; + } + return false; +} + +// Get the value of this edge or dimension, or if this is not determinable, -1. +int wxIndividualLayoutConstraint::GetEdge(wxEdge which, + wxWindowBase *thisWin, + wxWindowBase *other) const +{ + // If the edge or dimension belongs to the parent, then we know the + // dimension is obtainable immediately. E.g. a wxExpandSizer may contain a + // button (but the button's true parent is a panel, not the sizer) + if (other->GetChildren().Find((wxWindow*)thisWin)) + { + switch (which) + { + case wxLeft: + { + return 0; + } + case wxTop: + { + return 0; + } + case wxRight: + { + int w, h; + other->GetClientSizeConstraint(&w, &h); + return w; + } + case wxBottom: + { + int w, h; + other->GetClientSizeConstraint(&w, &h); + return h; + } + case wxWidth: + { + int w, h; + other->GetClientSizeConstraint(&w, &h); + return w; + } + case wxHeight: + { + int w, h; + other->GetClientSizeConstraint(&w, &h); + return h; + } + case wxCentreX: + case wxCentreY: + { + int w, h; + other->GetClientSizeConstraint(&w, &h); + if (which == wxCentreX) + return (int)(w/2); + else + return (int)(h/2); + } + default: + return -1; + } + } + switch (which) + { + case wxLeft: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->left.GetDone()) + return constr->left.GetValue(); + else + return -1; + } + else + { + int x, y; + other->GetPosition(&x, &y); + return x; + } + } + case wxTop: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->top.GetDone()) + return constr->top.GetValue(); + else + return -1; + } + else + { + int x, y; + other->GetPosition(&x, &y); + return y; + } + } + case wxRight: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->right.GetDone()) + return constr->right.GetValue(); + else + return -1; + } + else + { + int x, y, w, h; + other->GetPosition(&x, &y); + other->GetSize(&w, &h); + return (int)(x + w); + } + } + case wxBottom: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->bottom.GetDone()) + return constr->bottom.GetValue(); + else + return -1; + } + else + { + int x, y, w, h; + other->GetPosition(&x, &y); + other->GetSize(&w, &h); + return (int)(y + h); + } + } + case wxWidth: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->width.GetDone()) + return constr->width.GetValue(); + else + return -1; + } + else + { + int w, h; + other->GetSize(&w, &h); + return w; + } + } + case wxHeight: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->height.GetDone()) + return constr->height.GetValue(); + else + return -1; + } + else + { + int w, h; + other->GetSize(&w, &h); + return h; + } + } + case wxCentreX: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->centreX.GetDone()) + return constr->centreX.GetValue(); + else + return -1; + } + else + { + int x, y, w, h; + other->GetPosition(&x, &y); + other->GetSize(&w, &h); + return (int)(x + (w/2)); + } + } + case wxCentreY: + { + wxLayoutConstraints *constr = other->GetConstraints(); + // If no constraints, it means the window is not dependent + // on anything, and therefore we know its value immediately + if (constr) + { + if (constr->centreY.GetDone()) + return constr->centreY.GetValue(); + else + return -1; + } + else + { + int x, y, w, h; + other->GetPosition(&x, &y); + other->GetSize(&w, &h); + return (int)(y + (h/2)); + } + } + default: + break; + } + return -1; +} + +wxLayoutConstraints::wxLayoutConstraints() +{ + left.SetEdge(wxLeft); + top.SetEdge(wxTop); + right.SetEdge(wxRight); + bottom.SetEdge(wxBottom); + centreX.SetEdge(wxCentreX); + centreY.SetEdge(wxCentreY); + width.SetEdge(wxWidth); + height.SetEdge(wxHeight); +} + +bool wxLayoutConstraints::SatisfyConstraints(wxWindowBase *win, int *nChanges) +{ + int noChanges = 0; + + bool done = width.GetDone(); + bool newDone = (done ? true : width.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + done = height.GetDone(); + newDone = (done ? true : height.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + done = left.GetDone(); + newDone = (done ? true : left.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + done = top.GetDone(); + newDone = (done ? true : top.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + done = right.GetDone(); + newDone = (done ? true : right.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + done = bottom.GetDone(); + newDone = (done ? true : bottom.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + done = centreX.GetDone(); + newDone = (done ? true : centreX.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + done = centreY.GetDone(); + newDone = (done ? true : centreY.SatisfyConstraint(this, win)); + if (newDone != done) + noChanges ++; + + *nChanges = noChanges; + + return AreSatisfied(); +} + +#endif // wxUSE_CONSTRAINTS diff --git a/Source/3rd Party/wx/src/common/lboxcmn.cpp b/Source/3rd Party/wx/src/common/lboxcmn.cpp index f1787982a..883e4858c 100644 --- a/Source/3rd Party/wx/src/common/lboxcmn.cpp +++ b/Source/3rd Party/wx/src/common/lboxcmn.cpp @@ -1,147 +1,147 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/lboxcmn.cpp -// Purpose: wxListBox class methods common to all platforms -// Author: Vadim Zeitlin -// Modified by: -// Created: 22.10.99 -// RCS-ID: $Id: lboxcmn.cpp 39964 2006-07-04 00:31:52Z VZ $ -// Copyright: (c) 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_LISTBOX - -#include "wx/listbox.h" - -#ifndef WX_PRECOMP - #include "wx/dynarray.h" - #include "wx/arrstr.h" -#endif - -// ============================================================================ -// implementation -// ============================================================================ - -wxListBoxBase::~wxListBoxBase() -{ - // this destructor is required for Darwin -} - -// ---------------------------------------------------------------------------- -// adding items -// ---------------------------------------------------------------------------- - -void wxListBoxBase::InsertItems(unsigned int nItems, const wxString *items, unsigned int pos) -{ - wxArrayString aItems; - for ( unsigned int n = 0; n < nItems; n++ ) - { - aItems.Add(items[n]); - } - - DoInsertItems(aItems, pos); -} - - -void wxListBoxBase::Set(int nItems, const wxString* items, void **clientData) -{ - wxArrayString aItems; - for ( int n = 0; n < nItems; n++ ) - { - aItems.Add(items[n]); - } - - DoSetItems(aItems, clientData); -} - -// ---------------------------------------------------------------------------- -// selection -// ---------------------------------------------------------------------------- - -bool wxListBoxBase::SetStringSelection(const wxString& s, bool select) -{ - const int sel = FindString(s); - if ( sel == wxNOT_FOUND ) - return false; - - SetSelection(sel, select); - - return true; -} - -void wxListBoxBase::DeselectAll(int itemToLeaveSelected) -{ - if ( HasMultipleSelection() ) - { - wxArrayInt selections; - GetSelections(selections); - - size_t count = selections.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - int item = selections[n]; - if ( item != itemToLeaveSelected ) - Deselect(item); - } - } - else // single selection - { - int sel = GetSelection(); - if ( sel != wxNOT_FOUND && sel != itemToLeaveSelected ) - { - Deselect(sel); - } - } -} - -// ---------------------------------------------------------------------------- -// misc -// ---------------------------------------------------------------------------- - -void wxListBoxBase::Command(wxCommandEvent& event) -{ - SetSelection(event.GetInt(), event.GetExtraLong() != 0); - (void)ProcessEvent(event); -} - -// ---------------------------------------------------------------------------- -// SetFirstItem() and such -// ---------------------------------------------------------------------------- - -void wxListBoxBase::SetFirstItem(const wxString& s) -{ - int n = FindString(s); - - wxCHECK_RET( n != wxNOT_FOUND, wxT("invalid string in wxListBox::SetFirstItem") ); - - DoSetFirstItem(n); -} - -void wxListBoxBase::AppendAndEnsureVisible(const wxString& s) -{ - Append(s); - EnsureVisible(GetCount() - 1); -} - -void wxListBoxBase::EnsureVisible(int WXUNUSED(n)) -{ - // the base class version does nothing (the only alternative would be to - // call SetFirstItem() but this is probably even more stupid) -} - -#endif // wxUSE_LISTBOX +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/lboxcmn.cpp +// Purpose: wxListBox class methods common to all platforms +// Author: Vadim Zeitlin +// Modified by: +// Created: 22.10.99 +// RCS-ID: $Id: lboxcmn.cpp 39964 2006-07-04 00:31:52Z VZ $ +// Copyright: (c) 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_LISTBOX + +#include "wx/listbox.h" + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/arrstr.h" +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +wxListBoxBase::~wxListBoxBase() +{ + // this destructor is required for Darwin +} + +// ---------------------------------------------------------------------------- +// adding items +// ---------------------------------------------------------------------------- + +void wxListBoxBase::InsertItems(unsigned int nItems, const wxString *items, unsigned int pos) +{ + wxArrayString aItems; + for ( unsigned int n = 0; n < nItems; n++ ) + { + aItems.Add(items[n]); + } + + DoInsertItems(aItems, pos); +} + + +void wxListBoxBase::Set(int nItems, const wxString* items, void **clientData) +{ + wxArrayString aItems; + for ( int n = 0; n < nItems; n++ ) + { + aItems.Add(items[n]); + } + + DoSetItems(aItems, clientData); +} + +// ---------------------------------------------------------------------------- +// selection +// ---------------------------------------------------------------------------- + +bool wxListBoxBase::SetStringSelection(const wxString& s, bool select) +{ + const int sel = FindString(s); + if ( sel == wxNOT_FOUND ) + return false; + + SetSelection(sel, select); + + return true; +} + +void wxListBoxBase::DeselectAll(int itemToLeaveSelected) +{ + if ( HasMultipleSelection() ) + { + wxArrayInt selections; + GetSelections(selections); + + size_t count = selections.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + int item = selections[n]; + if ( item != itemToLeaveSelected ) + Deselect(item); + } + } + else // single selection + { + int sel = GetSelection(); + if ( sel != wxNOT_FOUND && sel != itemToLeaveSelected ) + { + Deselect(sel); + } + } +} + +// ---------------------------------------------------------------------------- +// misc +// ---------------------------------------------------------------------------- + +void wxListBoxBase::Command(wxCommandEvent& event) +{ + SetSelection(event.GetInt(), event.GetExtraLong() != 0); + (void)ProcessEvent(event); +} + +// ---------------------------------------------------------------------------- +// SetFirstItem() and such +// ---------------------------------------------------------------------------- + +void wxListBoxBase::SetFirstItem(const wxString& s) +{ + int n = FindString(s); + + wxCHECK_RET( n != wxNOT_FOUND, wxT("invalid string in wxListBox::SetFirstItem") ); + + DoSetFirstItem(n); +} + +void wxListBoxBase::AppendAndEnsureVisible(const wxString& s) +{ + Append(s); + EnsureVisible(GetCount() - 1); +} + +void wxListBoxBase::EnsureVisible(int WXUNUSED(n)) +{ + // the base class version does nothing (the only alternative would be to + // call SetFirstItem() but this is probably even more stupid) +} + +#endif // wxUSE_LISTBOX diff --git a/Source/3rd Party/wx/src/common/list.cpp b/Source/3rd Party/wx/src/common/list.cpp index 1a9f46a3a..6074a8fdd 100644 --- a/Source/3rd Party/wx/src/common/list.cpp +++ b/Source/3rd Party/wx/src/common/list.cpp @@ -1,768 +1,768 @@ -//////////////////////////////////////////////////////////////////////////////// -// Name: src/common/list.cpp -// Purpose: wxList implementation -// Author: Julian Smart -// Modified by: VZ at 16/11/98: WX_DECLARE_LIST() and typesafe lists added -// Created: 04/01/98 -// RCS-ID: $Id: list.cpp 43048 2006-11-04 18:14:50Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -//////////////////////////////////////////////////////////////////////////////// - -// ============================================================================= -// declarations -// ============================================================================= - -// ----------------------------------------------------------------------------- -// headers -// ----------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include -#include -#include - -#ifndef WX_PRECOMP - #include "wx/list.h" -#endif - -#if !wxUSE_STL - -// ============================================================================= -// implementation -// ============================================================================= - -// ----------------------------------------------------------------------------- -// wxListKey -// ----------------------------------------------------------------------------- -wxListKey wxDefaultListKey; - -bool wxListKey::operator==(wxListKeyValue value) const -{ - switch ( m_keyType ) - { - default: - wxFAIL_MSG(wxT("bad key type.")); - // let compiler optimize the line above away in release build - // by not putting return here... - - case wxKEY_STRING: - return wxStrcmp(m_key.string, value.string) == 0; - - case wxKEY_INTEGER: - return m_key.integer == value.integer; - } -} - -// ----------------------------------------------------------------------------- -// wxNodeBase -// ----------------------------------------------------------------------------- - -wxNodeBase::wxNodeBase(wxListBase *list, - wxNodeBase *previous, wxNodeBase *next, - void *data, const wxListKey& key) -{ - m_list = list; - m_data = data; - m_previous = previous; - m_next = next; - - switch ( key.GetKeyType() ) - { - case wxKEY_NONE: - break; - - case wxKEY_INTEGER: - m_key.integer = key.GetNumber(); - break; - - case wxKEY_STRING: - // to be free()d later - m_key.string = wxStrdup(key.GetString()); - break; - - default: - wxFAIL_MSG(wxT("invalid key type")); - } - - if ( previous ) - previous->m_next = this; - - if ( next ) - next->m_previous = this; -} - -wxNodeBase::~wxNodeBase() -{ - // handle the case when we're being deleted from the list by the user (i.e. - // not by the list itself from DeleteNode) - we must do it for - // compatibility with old code - if ( m_list != NULL ) - { - if ( m_list->m_keyType == wxKEY_STRING ) - { - free(m_key.string); - } - - m_list->DetachNode(this); - } -} - -int wxNodeBase::IndexOf() const -{ - wxCHECK_MSG( m_list, wxNOT_FOUND, wxT("node doesn't belong to a list in IndexOf")); - - // It would be more efficient to implement IndexOf() completely inside - // wxListBase (only traverse the list once), but this is probably a more - // reusable way of doing it. Can always be optimized at a later date (since - // IndexOf() resides in wxListBase as well) if efficiency is a problem. - int i; - wxNodeBase *prev = m_previous; - - for( i = 0; prev; i++ ) - { - prev = prev->m_previous; - } - - return i; -} - -// ----------------------------------------------------------------------------- -// wxListBase -// ----------------------------------------------------------------------------- - -void wxListBase::Init(wxKeyType keyType) -{ - m_nodeFirst = - m_nodeLast = (wxNodeBase *) NULL; - m_count = 0; - m_destroy = false; - m_keyType = keyType; -} - -wxListBase::wxListBase(size_t count, void *elements[]) -{ - Init(); - - for ( size_t n = 0; n < count; n++ ) - { - Append(elements[n]); - } -} - -void wxListBase::DoCopy(const wxListBase& list) -{ - wxASSERT_MSG( !list.m_destroy, - wxT("copying list which owns it's elements is a bad idea") ); - - m_destroy = list.m_destroy; - m_keyType = list.m_keyType; - m_nodeFirst = - m_nodeLast = (wxNodeBase *) NULL; - - switch (m_keyType) - { - case wxKEY_INTEGER: - { - long key; - for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() ) - { - key = node->GetKeyInteger(); - Append(key, node->GetData()); - } - break; - } - - case wxKEY_STRING: - { - const wxChar *key; - for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() ) - { - key = node->GetKeyString(); - Append(key, node->GetData()); - } - break; - } - - default: - { - for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() ) - { - Append(node->GetData()); - } - break; - } - } - - wxASSERT_MSG( m_count == list.m_count, _T("logic error in wxList::DoCopy") ); -} - -wxListBase::~wxListBase() -{ - wxNodeBase *each = m_nodeFirst; - while ( each != NULL ) - { - wxNodeBase *next = each->GetNext(); - DoDeleteNode(each); - each = next; - } -} - -wxNodeBase *wxListBase::AppendCommon(wxNodeBase *node) -{ - if ( !m_nodeFirst ) - { - m_nodeFirst = node; - m_nodeLast = m_nodeFirst; - } - else - { - m_nodeLast->m_next = node; - m_nodeLast = node; - } - - m_count++; - - return node; -} - -wxNodeBase *wxListBase::Append(void *object) -{ - // all objects in a keyed list should have a key - wxCHECK_MSG( m_keyType == wxKEY_NONE, (wxNodeBase *)NULL, - wxT("need a key for the object to append") ); - - // we use wxDefaultListKey even though it is the default parameter value - // because gcc under Mac OS X seems to miscompile this call otherwise - wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, - wxDefaultListKey); - - return AppendCommon(node); -} - -wxNodeBase *wxListBase::Append(long key, void *object) -{ - wxCHECK_MSG( (m_keyType == wxKEY_INTEGER) || - (m_keyType == wxKEY_NONE && m_count == 0), - (wxNodeBase *)NULL, - wxT("can't append object with numeric key to this list") ); - - wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, key); - return AppendCommon(node); -} - -wxNodeBase *wxListBase::Append (const wxChar *key, void *object) -{ - wxCHECK_MSG( (m_keyType == wxKEY_STRING) || - (m_keyType == wxKEY_NONE && m_count == 0), - (wxNodeBase *)NULL, - wxT("can't append object with string key to this list") ); - - wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, key); - return AppendCommon(node); -} - -wxNodeBase *wxListBase::Insert(wxNodeBase *position, void *object) -{ - // all objects in a keyed list should have a key - wxCHECK_MSG( m_keyType == wxKEY_NONE, (wxNodeBase *)NULL, - wxT("need a key for the object to insert") ); - - wxCHECK_MSG( !position || position->m_list == this, (wxNodeBase *)NULL, - wxT("can't insert before a node from another list") ); - - // previous and next node for the node being inserted - wxNodeBase *prev, *next; - if ( position ) - { - prev = position->GetPrevious(); - next = position; - } - else - { - // inserting in the beginning of the list - prev = (wxNodeBase *)NULL; - next = m_nodeFirst; - } - - // wxDefaultListKey: see comment in Append() above - wxNodeBase *node = CreateNode(prev, next, object, wxDefaultListKey); - if ( !m_nodeFirst ) - { - m_nodeLast = node; - } - - if ( prev == NULL ) - { - m_nodeFirst = node; - } - - m_count++; - - return node; -} - -wxNodeBase *wxListBase::Item(size_t n) const -{ - for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) - { - if ( n-- == 0 ) - { - return current; - } - } - - wxFAIL_MSG( wxT("invalid index in wxListBase::Item") ); - - return (wxNodeBase *)NULL; -} - -wxNodeBase *wxListBase::Find(const wxListKey& key) const -{ - wxASSERT_MSG( m_keyType == key.GetKeyType(), - wxT("this list is not keyed on the type of this key") ); - - for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) - { - if ( key == current->m_key ) - { - return current; - } - } - - // not found - return (wxNodeBase *)NULL; -} - -wxNodeBase *wxListBase::Find(const void *object) const -{ - for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) - { - if ( current->GetData() == object ) - return current; - } - - // not found - return (wxNodeBase *)NULL; -} - -int wxListBase::IndexOf(void *object) const -{ - wxNodeBase *node = Find( object ); - - return node ? node->IndexOf() : wxNOT_FOUND; -} - -void wxListBase::DoDeleteNode(wxNodeBase *node) -{ - // free node's data - if ( m_keyType == wxKEY_STRING ) - { - free(node->m_key.string); - } - - if ( m_destroy ) - { - node->DeleteData(); - } - - // so that the node knows that it's being deleted by the list - node->m_list = NULL; - delete node; -} - -wxNodeBase *wxListBase::DetachNode(wxNodeBase *node) -{ - wxCHECK_MSG( node, NULL, wxT("detaching NULL wxNodeBase") ); - wxCHECK_MSG( node->m_list == this, NULL, - wxT("detaching node which is not from this list") ); - - // update the list - wxNodeBase **prevNext = node->GetPrevious() ? &node->GetPrevious()->m_next - : &m_nodeFirst; - wxNodeBase **nextPrev = node->GetNext() ? &node->GetNext()->m_previous - : &m_nodeLast; - - *prevNext = node->GetNext(); - *nextPrev = node->GetPrevious(); - - m_count--; - - // mark the node as not belonging to this list any more - node->m_list = NULL; - - return node; -} - -bool wxListBase::DeleteNode(wxNodeBase *node) -{ - if ( !DetachNode(node) ) - return false; - - DoDeleteNode(node); - - return true; -} - -bool wxListBase::DeleteObject(void *object) -{ - for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) - { - if ( current->GetData() == object ) - { - DeleteNode(current); - return true; - } - } - - // not found - return false; -} - -void wxListBase::Clear() -{ - wxNodeBase *current = m_nodeFirst; - while ( current ) - { - wxNodeBase *next = current->GetNext(); - DoDeleteNode(current); - current = next; - } - - m_nodeFirst = - m_nodeLast = (wxNodeBase *)NULL; - - m_count = 0; -} - -void wxListBase::ForEach(wxListIterateFunction F) -{ - for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) - { - (*F)(current->GetData()); - } -} - -void *wxListBase::FirstThat(wxListIterateFunction F) -{ - for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) - { - if ( (*F)(current->GetData()) ) - return current->GetData(); - } - - return (wxNodeBase *)NULL; -} - -void *wxListBase::LastThat(wxListIterateFunction F) -{ - for ( wxNodeBase *current = GetLast(); current; current = current->GetPrevious() ) - { - if ( (*F)(current->GetData()) ) - return current->GetData(); - } - - return (wxNodeBase *)NULL; -} - -// (stefan.hammes@urz.uni-heidelberg.de) -// -// function for sorting lists. the concept is borrowed from 'qsort'. -// by giving a sort function, arbitrary lists can be sorted. -// method: -// - put wxObject pointers into an array -// - sort the array with qsort -// - put back the sorted wxObject pointers into the list -// -// CAVE: the sort function receives pointers to wxObject pointers (wxObject **), -// so dereference right! -// EXAMPLE: -// int listcompare(const void *arg1, const void *arg2) -// { -// return(compare(**(wxString **)arg1, -// **(wxString **)arg2)); -// } -// -// void main() -// { -// wxListBase list; -// -// list.Append(new wxString("DEF")); -// list.Append(new wxString("GHI")); -// list.Append(new wxString("ABC")); -// list.Sort(listcompare); -// } - -void wxListBase::Sort(const wxSortCompareFunction compfunc) -{ - // allocate an array for the wxObject pointers of the list - const size_t num = GetCount(); - void **objArray = new void *[num]; - void **objPtr = objArray; - - // go through the list and put the pointers into the array - wxNodeBase *node; - for ( node = GetFirst(); node; node = node->GetNext() ) - { - *objPtr++ = node->GetData(); - } - - // sort the array - qsort((void *)objArray,num,sizeof(wxObject *), -#ifdef __WXWINCE__ - (int (__cdecl *)(const void *,const void *)) -#endif - compfunc); - - // put the sorted pointers back into the list - objPtr = objArray; - for ( node = GetFirst(); node; node = node->GetNext() ) - { - node->SetData(*objPtr++); - } - - // free the array - delete[] objArray; -} - -void wxListBase::Reverse() -{ - wxNodeBase* node = m_nodeFirst; - wxNodeBase* tmp; - - while (node) - { - // swap prev and next pointers - tmp = node->m_next; - node->m_next = node->m_previous; - node->m_previous = tmp; - - // this is the node that was next before swapping - node = tmp; - } - - // swap first and last node - tmp = m_nodeFirst; m_nodeFirst = m_nodeLast; m_nodeLast = tmp; -} - -void wxListBase::DeleteNodes(wxNodeBase* first, wxNodeBase* last) -{ - wxNodeBase* node = first; - - while (node != last) - { - wxNodeBase* next = node->GetNext(); - DeleteNode(node); - node = next; - } -} - -// ============================================================================ -// compatibility section from now on -// ============================================================================ - -#ifdef wxLIST_COMPATIBILITY - -// ----------------------------------------------------------------------------- -// wxList (a.k.a. wxObjectList) -// ----------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxList, wxObject) - -wxList::wxList( int key_type ) - : wxObjectList( (wxKeyType)key_type ) -{ -} - -void wxObjectListNode::DeleteData() -{ - delete (wxObject *)GetData(); -} - -// ---------------------------------------------------------------------------- -// wxStringList -// ---------------------------------------------------------------------------- - -static inline wxChar* MYcopystring(const wxChar* s) -{ - wxChar* copy = new wxChar[wxStrlen(s) + 1]; - return wxStrcpy(copy, s); -} - -IMPLEMENT_DYNAMIC_CLASS(wxStringList, wxObject) - -// instead of WX_DEFINE_LIST(wxStringListBase) we define this function -// ourselves -void wxStringListNode::DeleteData() -{ - delete [] (char *)GetData(); -} - -bool wxStringList::Delete(const wxChar *s) -{ - wxStringListNode *current; - - for ( current = GetFirst(); current; current = current->GetNext() ) - { - if ( wxStrcmp(current->GetData(), s) == 0 ) - { - DeleteNode(current); - return true; - } - } - - // not found - return false; -} - -void wxStringList::DoCopy(const wxStringList& other) -{ - wxASSERT( GetCount() == 0 ); // this list must be empty before copying! - - size_t count = other.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - Add(other.Item(n)->GetData()); - } -} - -wxStringList::wxStringList() -{ - DeleteContents(true); -} - -// Variable argument list, terminated by a zero -// Makes new storage for the strings -wxStringList::wxStringList (const wxChar *first, ...) -{ - DeleteContents(true); - if ( !first ) - return; - - va_list ap; - va_start(ap, first); - - const wxChar *s = first; - for (;;) - { - Add(s); - - // icc gives this warning in its own va_arg() macro, argh -#ifdef __INTELC__ - #pragma warning(push) - #pragma warning(disable: 1684) -#endif - - s = va_arg(ap, const wxChar *); - -#ifdef __INTELC__ - #pragma warning(pop) -#endif - - if ( !s ) - break; - } - - va_end(ap); -} - -// Only makes new strings if arg is true -wxChar **wxStringList::ListToArray(bool new_copies) const -{ - wxChar **string_array = new wxChar *[GetCount()]; - wxStringListNode *node = GetFirst(); - for (size_t i = 0; i < GetCount(); i++) - { - wxChar *s = node->GetData(); - if ( new_copies ) - string_array[i] = MYcopystring(s); - else - string_array[i] = s; - node = node->GetNext(); - } - - return string_array; -} - -// Checks whether s is a member of the list -bool wxStringList::Member(const wxChar *s) const -{ - for ( wxStringListNode *node = GetFirst(); node; node = node->GetNext() ) - { - const wxChar *s1 = node->GetData(); - if (s == s1 || wxStrcmp (s, s1) == 0) - return true; - } - - return false; -} - -#ifdef __WXWINCE__ -extern "C" int __cdecl -#else -extern "C" int LINKAGEMODE -#endif - -wx_comparestrings(const void *arg1, const void *arg2) -{ - wxChar **s1 = (wxChar **) arg1; - wxChar **s2 = (wxChar **) arg2; - - return wxStrcmp (*s1, *s2); -} - -// Sort a list of strings - deallocates old nodes, allocates new -void wxStringList::Sort() -{ - size_t N = GetCount(); - wxChar **array = new wxChar *[N]; - wxStringListNode *node; - - size_t i = 0; - for ( node = GetFirst(); node; node = node->GetNext() ) - { - array[i++] = node->GetData(); - } - - qsort (array, N, sizeof (wxChar *), wx_comparestrings); - - i = 0; - for ( node = GetFirst(); node; node = node->GetNext() ) - node->SetData( array[i++] ); - - delete [] array; -} - -wxNode *wxStringList::Add(const wxChar *s) -{ - return (wxNode *)(wxStringListBase::Node *) - wxStringListBase::Append(MYcopystring(s)); -} - -wxNode *wxStringList::Prepend(const wxChar *s) -{ - return (wxNode *)(wxStringListBase::Node *) - wxStringListBase::Insert(MYcopystring(s)); -} - -#endif // wxLIST_COMPATIBILITY - -#else // wxUSE_STL = 1 - - #include "wx/listimpl.cpp" - WX_DEFINE_LIST(wxObjectList) - -// with wxUSE_STL wxStringList contains wxString objects, not pointers -void _WX_LIST_HELPER_wxStringListBase::DeleteFunction( wxString WXUNUSED(X) ) -{ -} - -wxStringListBase::BaseListType wxStringListBase::EmptyList; - -#endif // !wxUSE_STL +//////////////////////////////////////////////////////////////////////////////// +// Name: src/common/list.cpp +// Purpose: wxList implementation +// Author: Julian Smart +// Modified by: VZ at 16/11/98: WX_DECLARE_LIST() and typesafe lists added +// Created: 04/01/98 +// RCS-ID: $Id: list.cpp 43048 2006-11-04 18:14:50Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +//////////////////////////////////////////////////////////////////////////////// + +// ============================================================================= +// declarations +// ============================================================================= + +// ----------------------------------------------------------------------------- +// headers +// ----------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include +#include +#include + +#ifndef WX_PRECOMP + #include "wx/list.h" +#endif + +#if !wxUSE_STL + +// ============================================================================= +// implementation +// ============================================================================= + +// ----------------------------------------------------------------------------- +// wxListKey +// ----------------------------------------------------------------------------- +wxListKey wxDefaultListKey; + +bool wxListKey::operator==(wxListKeyValue value) const +{ + switch ( m_keyType ) + { + default: + wxFAIL_MSG(wxT("bad key type.")); + // let compiler optimize the line above away in release build + // by not putting return here... + + case wxKEY_STRING: + return wxStrcmp(m_key.string, value.string) == 0; + + case wxKEY_INTEGER: + return m_key.integer == value.integer; + } +} + +// ----------------------------------------------------------------------------- +// wxNodeBase +// ----------------------------------------------------------------------------- + +wxNodeBase::wxNodeBase(wxListBase *list, + wxNodeBase *previous, wxNodeBase *next, + void *data, const wxListKey& key) +{ + m_list = list; + m_data = data; + m_previous = previous; + m_next = next; + + switch ( key.GetKeyType() ) + { + case wxKEY_NONE: + break; + + case wxKEY_INTEGER: + m_key.integer = key.GetNumber(); + break; + + case wxKEY_STRING: + // to be free()d later + m_key.string = wxStrdup(key.GetString()); + break; + + default: + wxFAIL_MSG(wxT("invalid key type")); + } + + if ( previous ) + previous->m_next = this; + + if ( next ) + next->m_previous = this; +} + +wxNodeBase::~wxNodeBase() +{ + // handle the case when we're being deleted from the list by the user (i.e. + // not by the list itself from DeleteNode) - we must do it for + // compatibility with old code + if ( m_list != NULL ) + { + if ( m_list->m_keyType == wxKEY_STRING ) + { + free(m_key.string); + } + + m_list->DetachNode(this); + } +} + +int wxNodeBase::IndexOf() const +{ + wxCHECK_MSG( m_list, wxNOT_FOUND, wxT("node doesn't belong to a list in IndexOf")); + + // It would be more efficient to implement IndexOf() completely inside + // wxListBase (only traverse the list once), but this is probably a more + // reusable way of doing it. Can always be optimized at a later date (since + // IndexOf() resides in wxListBase as well) if efficiency is a problem. + int i; + wxNodeBase *prev = m_previous; + + for( i = 0; prev; i++ ) + { + prev = prev->m_previous; + } + + return i; +} + +// ----------------------------------------------------------------------------- +// wxListBase +// ----------------------------------------------------------------------------- + +void wxListBase::Init(wxKeyType keyType) +{ + m_nodeFirst = + m_nodeLast = (wxNodeBase *) NULL; + m_count = 0; + m_destroy = false; + m_keyType = keyType; +} + +wxListBase::wxListBase(size_t count, void *elements[]) +{ + Init(); + + for ( size_t n = 0; n < count; n++ ) + { + Append(elements[n]); + } +} + +void wxListBase::DoCopy(const wxListBase& list) +{ + wxASSERT_MSG( !list.m_destroy, + wxT("copying list which owns it's elements is a bad idea") ); + + m_destroy = list.m_destroy; + m_keyType = list.m_keyType; + m_nodeFirst = + m_nodeLast = (wxNodeBase *) NULL; + + switch (m_keyType) + { + case wxKEY_INTEGER: + { + long key; + for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() ) + { + key = node->GetKeyInteger(); + Append(key, node->GetData()); + } + break; + } + + case wxKEY_STRING: + { + const wxChar *key; + for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() ) + { + key = node->GetKeyString(); + Append(key, node->GetData()); + } + break; + } + + default: + { + for ( wxNodeBase *node = list.GetFirst(); node; node = node->GetNext() ) + { + Append(node->GetData()); + } + break; + } + } + + wxASSERT_MSG( m_count == list.m_count, _T("logic error in wxList::DoCopy") ); +} + +wxListBase::~wxListBase() +{ + wxNodeBase *each = m_nodeFirst; + while ( each != NULL ) + { + wxNodeBase *next = each->GetNext(); + DoDeleteNode(each); + each = next; + } +} + +wxNodeBase *wxListBase::AppendCommon(wxNodeBase *node) +{ + if ( !m_nodeFirst ) + { + m_nodeFirst = node; + m_nodeLast = m_nodeFirst; + } + else + { + m_nodeLast->m_next = node; + m_nodeLast = node; + } + + m_count++; + + return node; +} + +wxNodeBase *wxListBase::Append(void *object) +{ + // all objects in a keyed list should have a key + wxCHECK_MSG( m_keyType == wxKEY_NONE, (wxNodeBase *)NULL, + wxT("need a key for the object to append") ); + + // we use wxDefaultListKey even though it is the default parameter value + // because gcc under Mac OS X seems to miscompile this call otherwise + wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, + wxDefaultListKey); + + return AppendCommon(node); +} + +wxNodeBase *wxListBase::Append(long key, void *object) +{ + wxCHECK_MSG( (m_keyType == wxKEY_INTEGER) || + (m_keyType == wxKEY_NONE && m_count == 0), + (wxNodeBase *)NULL, + wxT("can't append object with numeric key to this list") ); + + wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, key); + return AppendCommon(node); +} + +wxNodeBase *wxListBase::Append (const wxChar *key, void *object) +{ + wxCHECK_MSG( (m_keyType == wxKEY_STRING) || + (m_keyType == wxKEY_NONE && m_count == 0), + (wxNodeBase *)NULL, + wxT("can't append object with string key to this list") ); + + wxNodeBase *node = CreateNode(m_nodeLast, (wxNodeBase *)NULL, object, key); + return AppendCommon(node); +} + +wxNodeBase *wxListBase::Insert(wxNodeBase *position, void *object) +{ + // all objects in a keyed list should have a key + wxCHECK_MSG( m_keyType == wxKEY_NONE, (wxNodeBase *)NULL, + wxT("need a key for the object to insert") ); + + wxCHECK_MSG( !position || position->m_list == this, (wxNodeBase *)NULL, + wxT("can't insert before a node from another list") ); + + // previous and next node for the node being inserted + wxNodeBase *prev, *next; + if ( position ) + { + prev = position->GetPrevious(); + next = position; + } + else + { + // inserting in the beginning of the list + prev = (wxNodeBase *)NULL; + next = m_nodeFirst; + } + + // wxDefaultListKey: see comment in Append() above + wxNodeBase *node = CreateNode(prev, next, object, wxDefaultListKey); + if ( !m_nodeFirst ) + { + m_nodeLast = node; + } + + if ( prev == NULL ) + { + m_nodeFirst = node; + } + + m_count++; + + return node; +} + +wxNodeBase *wxListBase::Item(size_t n) const +{ + for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) + { + if ( n-- == 0 ) + { + return current; + } + } + + wxFAIL_MSG( wxT("invalid index in wxListBase::Item") ); + + return (wxNodeBase *)NULL; +} + +wxNodeBase *wxListBase::Find(const wxListKey& key) const +{ + wxASSERT_MSG( m_keyType == key.GetKeyType(), + wxT("this list is not keyed on the type of this key") ); + + for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) + { + if ( key == current->m_key ) + { + return current; + } + } + + // not found + return (wxNodeBase *)NULL; +} + +wxNodeBase *wxListBase::Find(const void *object) const +{ + for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) + { + if ( current->GetData() == object ) + return current; + } + + // not found + return (wxNodeBase *)NULL; +} + +int wxListBase::IndexOf(void *object) const +{ + wxNodeBase *node = Find( object ); + + return node ? node->IndexOf() : wxNOT_FOUND; +} + +void wxListBase::DoDeleteNode(wxNodeBase *node) +{ + // free node's data + if ( m_keyType == wxKEY_STRING ) + { + free(node->m_key.string); + } + + if ( m_destroy ) + { + node->DeleteData(); + } + + // so that the node knows that it's being deleted by the list + node->m_list = NULL; + delete node; +} + +wxNodeBase *wxListBase::DetachNode(wxNodeBase *node) +{ + wxCHECK_MSG( node, NULL, wxT("detaching NULL wxNodeBase") ); + wxCHECK_MSG( node->m_list == this, NULL, + wxT("detaching node which is not from this list") ); + + // update the list + wxNodeBase **prevNext = node->GetPrevious() ? &node->GetPrevious()->m_next + : &m_nodeFirst; + wxNodeBase **nextPrev = node->GetNext() ? &node->GetNext()->m_previous + : &m_nodeLast; + + *prevNext = node->GetNext(); + *nextPrev = node->GetPrevious(); + + m_count--; + + // mark the node as not belonging to this list any more + node->m_list = NULL; + + return node; +} + +bool wxListBase::DeleteNode(wxNodeBase *node) +{ + if ( !DetachNode(node) ) + return false; + + DoDeleteNode(node); + + return true; +} + +bool wxListBase::DeleteObject(void *object) +{ + for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) + { + if ( current->GetData() == object ) + { + DeleteNode(current); + return true; + } + } + + // not found + return false; +} + +void wxListBase::Clear() +{ + wxNodeBase *current = m_nodeFirst; + while ( current ) + { + wxNodeBase *next = current->GetNext(); + DoDeleteNode(current); + current = next; + } + + m_nodeFirst = + m_nodeLast = (wxNodeBase *)NULL; + + m_count = 0; +} + +void wxListBase::ForEach(wxListIterateFunction F) +{ + for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) + { + (*F)(current->GetData()); + } +} + +void *wxListBase::FirstThat(wxListIterateFunction F) +{ + for ( wxNodeBase *current = GetFirst(); current; current = current->GetNext() ) + { + if ( (*F)(current->GetData()) ) + return current->GetData(); + } + + return (wxNodeBase *)NULL; +} + +void *wxListBase::LastThat(wxListIterateFunction F) +{ + for ( wxNodeBase *current = GetLast(); current; current = current->GetPrevious() ) + { + if ( (*F)(current->GetData()) ) + return current->GetData(); + } + + return (wxNodeBase *)NULL; +} + +// (stefan.hammes@urz.uni-heidelberg.de) +// +// function for sorting lists. the concept is borrowed from 'qsort'. +// by giving a sort function, arbitrary lists can be sorted. +// method: +// - put wxObject pointers into an array +// - sort the array with qsort +// - put back the sorted wxObject pointers into the list +// +// CAVE: the sort function receives pointers to wxObject pointers (wxObject **), +// so dereference right! +// EXAMPLE: +// int listcompare(const void *arg1, const void *arg2) +// { +// return(compare(**(wxString **)arg1, +// **(wxString **)arg2)); +// } +// +// void main() +// { +// wxListBase list; +// +// list.Append(new wxString("DEF")); +// list.Append(new wxString("GHI")); +// list.Append(new wxString("ABC")); +// list.Sort(listcompare); +// } + +void wxListBase::Sort(const wxSortCompareFunction compfunc) +{ + // allocate an array for the wxObject pointers of the list + const size_t num = GetCount(); + void **objArray = new void *[num]; + void **objPtr = objArray; + + // go through the list and put the pointers into the array + wxNodeBase *node; + for ( node = GetFirst(); node; node = node->GetNext() ) + { + *objPtr++ = node->GetData(); + } + + // sort the array + qsort((void *)objArray,num,sizeof(wxObject *), +#ifdef __WXWINCE__ + (int (__cdecl *)(const void *,const void *)) +#endif + compfunc); + + // put the sorted pointers back into the list + objPtr = objArray; + for ( node = GetFirst(); node; node = node->GetNext() ) + { + node->SetData(*objPtr++); + } + + // free the array + delete[] objArray; +} + +void wxListBase::Reverse() +{ + wxNodeBase* node = m_nodeFirst; + wxNodeBase* tmp; + + while (node) + { + // swap prev and next pointers + tmp = node->m_next; + node->m_next = node->m_previous; + node->m_previous = tmp; + + // this is the node that was next before swapping + node = tmp; + } + + // swap first and last node + tmp = m_nodeFirst; m_nodeFirst = m_nodeLast; m_nodeLast = tmp; +} + +void wxListBase::DeleteNodes(wxNodeBase* first, wxNodeBase* last) +{ + wxNodeBase* node = first; + + while (node != last) + { + wxNodeBase* next = node->GetNext(); + DeleteNode(node); + node = next; + } +} + +// ============================================================================ +// compatibility section from now on +// ============================================================================ + +#ifdef wxLIST_COMPATIBILITY + +// ----------------------------------------------------------------------------- +// wxList (a.k.a. wxObjectList) +// ----------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxList, wxObject) + +wxList::wxList( int key_type ) + : wxObjectList( (wxKeyType)key_type ) +{ +} + +void wxObjectListNode::DeleteData() +{ + delete (wxObject *)GetData(); +} + +// ---------------------------------------------------------------------------- +// wxStringList +// ---------------------------------------------------------------------------- + +static inline wxChar* MYcopystring(const wxChar* s) +{ + wxChar* copy = new wxChar[wxStrlen(s) + 1]; + return wxStrcpy(copy, s); +} + +IMPLEMENT_DYNAMIC_CLASS(wxStringList, wxObject) + +// instead of WX_DEFINE_LIST(wxStringListBase) we define this function +// ourselves +void wxStringListNode::DeleteData() +{ + delete [] (char *)GetData(); +} + +bool wxStringList::Delete(const wxChar *s) +{ + wxStringListNode *current; + + for ( current = GetFirst(); current; current = current->GetNext() ) + { + if ( wxStrcmp(current->GetData(), s) == 0 ) + { + DeleteNode(current); + return true; + } + } + + // not found + return false; +} + +void wxStringList::DoCopy(const wxStringList& other) +{ + wxASSERT( GetCount() == 0 ); // this list must be empty before copying! + + size_t count = other.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + Add(other.Item(n)->GetData()); + } +} + +wxStringList::wxStringList() +{ + DeleteContents(true); +} + +// Variable argument list, terminated by a zero +// Makes new storage for the strings +wxStringList::wxStringList (const wxChar *first, ...) +{ + DeleteContents(true); + if ( !first ) + return; + + va_list ap; + va_start(ap, first); + + const wxChar *s = first; + for (;;) + { + Add(s); + + // icc gives this warning in its own va_arg() macro, argh +#ifdef __INTELC__ + #pragma warning(push) + #pragma warning(disable: 1684) +#endif + + s = va_arg(ap, const wxChar *); + +#ifdef __INTELC__ + #pragma warning(pop) +#endif + + if ( !s ) + break; + } + + va_end(ap); +} + +// Only makes new strings if arg is true +wxChar **wxStringList::ListToArray(bool new_copies) const +{ + wxChar **string_array = new wxChar *[GetCount()]; + wxStringListNode *node = GetFirst(); + for (size_t i = 0; i < GetCount(); i++) + { + wxChar *s = node->GetData(); + if ( new_copies ) + string_array[i] = MYcopystring(s); + else + string_array[i] = s; + node = node->GetNext(); + } + + return string_array; +} + +// Checks whether s is a member of the list +bool wxStringList::Member(const wxChar *s) const +{ + for ( wxStringListNode *node = GetFirst(); node; node = node->GetNext() ) + { + const wxChar *s1 = node->GetData(); + if (s == s1 || wxStrcmp (s, s1) == 0) + return true; + } + + return false; +} + +#ifdef __WXWINCE__ +extern "C" int __cdecl +#else +extern "C" int LINKAGEMODE +#endif + +wx_comparestrings(const void *arg1, const void *arg2) +{ + wxChar **s1 = (wxChar **) arg1; + wxChar **s2 = (wxChar **) arg2; + + return wxStrcmp (*s1, *s2); +} + +// Sort a list of strings - deallocates old nodes, allocates new +void wxStringList::Sort() +{ + size_t N = GetCount(); + wxChar **array = new wxChar *[N]; + wxStringListNode *node; + + size_t i = 0; + for ( node = GetFirst(); node; node = node->GetNext() ) + { + array[i++] = node->GetData(); + } + + qsort (array, N, sizeof (wxChar *), wx_comparestrings); + + i = 0; + for ( node = GetFirst(); node; node = node->GetNext() ) + node->SetData( array[i++] ); + + delete [] array; +} + +wxNode *wxStringList::Add(const wxChar *s) +{ + return (wxNode *)(wxStringListBase::Node *) + wxStringListBase::Append(MYcopystring(s)); +} + +wxNode *wxStringList::Prepend(const wxChar *s) +{ + return (wxNode *)(wxStringListBase::Node *) + wxStringListBase::Insert(MYcopystring(s)); +} + +#endif // wxLIST_COMPATIBILITY + +#else // wxUSE_STL = 1 + + #include "wx/listimpl.cpp" + WX_DEFINE_LIST(wxObjectList) + +// with wxUSE_STL wxStringList contains wxString objects, not pointers +void _WX_LIST_HELPER_wxStringListBase::DeleteFunction( wxString WXUNUSED(X) ) +{ +} + +wxStringListBase::BaseListType wxStringListBase::EmptyList; + +#endif // !wxUSE_STL diff --git a/Source/3rd Party/wx/src/common/listctrlcmn.cpp b/Source/3rd Party/wx/src/common/listctrlcmn.cpp index f0703f39e..c5366a1aa 100644 --- a/Source/3rd Party/wx/src/common/listctrlcmn.cpp +++ b/Source/3rd Party/wx/src/common/listctrlcmn.cpp @@ -1,54 +1,54 @@ -//////////////////////////////////////////////////////////////////////////////// -// Name: src/common/listctrlcmn.cpp -// Purpose: Common defines for wxListCtrl and wxListCtrl-based classes. -// Author: Kevin Ollivier -// Created: 09/15/06 -// RCS-ID: $Id: listctrlcmn.cpp 41568 2006-10-02 17:38:30Z PC $ -// Copyright: (c) Kevin Ollivier -// Licence: wxWindows licence -//////////////////////////////////////////////////////////////////////////////// - -// ============================================================================= -// declarations -// ============================================================================= - -// ----------------------------------------------------------------------------- -// headers -// ----------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if wxUSE_LISTCTRL - -#include "wx/listctrl.h" - -const wxChar wxListCtrlNameStr[] = wxT("listCtrl"); - -// ListCtrl events -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS) -#if WXWIN_COMPATIBILITY_2_4 -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO) -#endif -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT) - -#endif // wxUSE_LISTCTRL +//////////////////////////////////////////////////////////////////////////////// +// Name: src/common/listctrlcmn.cpp +// Purpose: Common defines for wxListCtrl and wxListCtrl-based classes. +// Author: Kevin Ollivier +// Created: 09/15/06 +// RCS-ID: $Id: listctrlcmn.cpp 41568 2006-10-02 17:38:30Z PC $ +// Copyright: (c) Kevin Ollivier +// Licence: wxWindows licence +//////////////////////////////////////////////////////////////////////////////// + +// ============================================================================= +// declarations +// ============================================================================= + +// ----------------------------------------------------------------------------- +// headers +// ----------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if wxUSE_LISTCTRL + +#include "wx/listctrl.h" + +const wxChar wxListCtrlNameStr[] = wxT("listCtrl"); + +// ListCtrl events +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_DRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_RDRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_BEGIN_LABEL_EDIT) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_END_LABEL_EDIT) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ITEM) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_DELETE_ALL_ITEMS) +#if WXWIN_COMPATIBILITY_2_4 +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_GET_INFO) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_SET_INFO) +#endif +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_SELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_DESELECTED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_KEY_DOWN) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_INSERT_ITEM) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_RIGHT_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_BEGIN_DRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_DRAGGING) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_COL_END_DRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_RIGHT_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_MIDDLE_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_ACTIVATED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_ITEM_FOCUSED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_LIST_CACHE_HINT) + +#endif // wxUSE_LISTCTRL diff --git a/Source/3rd Party/wx/src/common/log.cpp b/Source/3rd Party/wx/src/common/log.cpp index c4d8da4b1..dc23a83e3 100644 --- a/Source/3rd Party/wx/src/common/log.cpp +++ b/Source/3rd Party/wx/src/common/log.cpp @@ -1,838 +1,838 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/log.cpp -// Purpose: Assorted wxLogXXX functions, and wxLog (sink for logs) -// Author: Vadim Zeitlin -// Modified by: -// Created: 29/01/98 -// RCS-ID: $Id: log.cpp 67119 2011-03-03 15:09:44Z JS $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_LOG - -// wxWidgets -#ifndef WX_PRECOMP - #include "wx/log.h" - #include "wx/app.h" - #include "wx/arrstr.h" - #include "wx/intl.h" - #include "wx/string.h" - #include "wx/utils.h" -#endif //WX_PRECOMP - -#include "wx/apptrait.h" -#include "wx/datetime.h" -#include "wx/file.h" -#include "wx/msgout.h" -#include "wx/textfile.h" -#include "wx/thread.h" -#include "wx/wxchar.h" - -// other standard headers -#ifndef __WXWINCE__ -#include -#endif - -#include - -#ifndef __WXWINCE__ -#include -#else -#include "wx/msw/wince/time.h" -#endif - -#if defined(__WINDOWS__) - #include "wx/msw/private.h" // includes windows.h -#endif - -// ---------------------------------------------------------------------------- -// non member functions -// ---------------------------------------------------------------------------- - -// define this to enable wrapping of log messages -//#define LOG_PRETTY_WRAP - -#ifdef LOG_PRETTY_WRAP - static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz); -#endif - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// implementation of Log functions -// -// NB: unfortunately we need all these distinct functions, we can't make them -// macros and not all compilers inline vararg functions. -// ---------------------------------------------------------------------------- - -// generic log function -void wxVLogGeneric(wxLogLevel level, const wxChar *szFormat, va_list argptr) -{ - if ( wxLog::IsEnabled() ) { - wxLog::OnLog(level, wxString::FormatV(szFormat, argptr), time(NULL)); - } -} - -void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...) -{ - va_list argptr; - va_start(argptr, szFormat); - wxVLogGeneric(level, szFormat, argptr); - va_end(argptr); -} - -#define IMPLEMENT_LOG_FUNCTION(level) \ - void wxVLog##level(const wxChar *szFormat, va_list argptr) \ - { \ - if ( wxLog::IsEnabled() ) { \ - wxLog::OnLog(wxLOG_##level, \ - wxString::FormatV(szFormat, argptr), time(NULL));\ - } \ - } \ - \ - void wxLog##level(const wxChar *szFormat, ...) \ - { \ - va_list argptr; \ - va_start(argptr, szFormat); \ - wxVLog##level(szFormat, argptr); \ - va_end(argptr); \ - } - -IMPLEMENT_LOG_FUNCTION(Error) -IMPLEMENT_LOG_FUNCTION(Warning) -IMPLEMENT_LOG_FUNCTION(Message) -IMPLEMENT_LOG_FUNCTION(Info) -IMPLEMENT_LOG_FUNCTION(Status) - -void wxSafeShowMessage(const wxString& title, const wxString& text) -{ -#ifdef __WINDOWS__ - ::MessageBox(NULL, text, title, MB_OK | MB_ICONSTOP); -#else - wxFprintf(stderr, _T("%s: %s\n"), title.c_str(), text.c_str()); - fflush(stderr); -#endif -} - -// fatal errors can't be suppressed nor handled by the custom log target and -// always terminate the program -void wxVLogFatalError(const wxChar *szFormat, va_list argptr) -{ - wxSafeShowMessage(_T("Fatal Error"), wxString::FormatV(szFormat, argptr)); - -#ifdef __WXWINCE__ - ExitThread(3); -#else - abort(); -#endif -} - -void wxLogFatalError(const wxChar *szFormat, ...) -{ - va_list argptr; - va_start(argptr, szFormat); - wxVLogFatalError(szFormat, argptr); - - // some compilers warn about unreachable code and it shouldn't matter - // for the others anyhow... - //va_end(argptr); -} - -// same as info, but only if 'verbose' mode is on -void wxVLogVerbose(const wxChar *szFormat, va_list argptr) -{ - if ( wxLog::IsEnabled() ) { - if ( wxLog::GetActiveTarget() != NULL && wxLog::GetVerbose() ) { - wxLog::OnLog(wxLOG_Info, - wxString::FormatV(szFormat, argptr), time(NULL)); - } - } -} - -void wxLogVerbose(const wxChar *szFormat, ...) -{ - va_list argptr; - va_start(argptr, szFormat); - wxVLogVerbose(szFormat, argptr); - va_end(argptr); -} - -// debug functions -#ifdef __WXDEBUG__ -#define IMPLEMENT_LOG_DEBUG_FUNCTION(level) \ - void wxVLog##level(const wxChar *szFormat, va_list argptr) \ - { \ - if ( wxLog::IsEnabled() ) { \ - wxLog::OnLog(wxLOG_##level, \ - wxString::FormatV(szFormat, argptr), time(NULL));\ - } \ - } \ - \ - void wxLog##level(const wxChar *szFormat, ...) \ - { \ - va_list argptr; \ - va_start(argptr, szFormat); \ - wxVLog##level(szFormat, argptr); \ - va_end(argptr); \ - } - - void wxVLogTrace(const wxChar *mask, const wxChar *szFormat, va_list argptr) - { - if ( wxLog::IsEnabled() && wxLog::IsAllowedTraceMask(mask) ) { - wxString msg; - msg << _T("(") << mask << _T(") ") << wxString::FormatV(szFormat, argptr); - - wxLog::OnLog(wxLOG_Trace, msg, time(NULL)); - } - } - - void wxLogTrace(const wxChar *mask, const wxChar *szFormat, ...) - { - va_list argptr; - va_start(argptr, szFormat); - wxVLogTrace(mask, szFormat, argptr); - va_end(argptr); - } - - void wxVLogTrace(wxTraceMask mask, const wxChar *szFormat, va_list argptr) - { - // we check that all of mask bits are set in the current mask, so - // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something - // if both bits are set. - if ( wxLog::IsEnabled() && ((wxLog::GetTraceMask() & mask) == mask) ) { - wxLog::OnLog(wxLOG_Trace, wxString::FormatV(szFormat, argptr), time(NULL)); - } - } - - void wxLogTrace(wxTraceMask mask, const wxChar *szFormat, ...) - { - va_list argptr; - va_start(argptr, szFormat); - wxVLogTrace(mask, szFormat, argptr); - va_end(argptr); - } - -#else // release - #define IMPLEMENT_LOG_DEBUG_FUNCTION(level) -#endif - -IMPLEMENT_LOG_DEBUG_FUNCTION(Debug) -IMPLEMENT_LOG_DEBUG_FUNCTION(Trace) - -// wxLogSysError: one uses the last error code, for other you must give it -// explicitly - -// return the system error message description -static inline wxString wxLogSysErrorHelper(long err) -{ - return wxString::Format(_(" (error %ld: %s)"), err, wxSysErrorMsg(err)); -} - -void WXDLLEXPORT wxVLogSysError(const wxChar *szFormat, va_list argptr) -{ - wxVLogSysError(wxSysErrorCode(), szFormat, argptr); -} - -void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...) -{ - va_list argptr; - va_start(argptr, szFormat); - wxVLogSysError(szFormat, argptr); - va_end(argptr); -} - -void WXDLLEXPORT wxVLogSysError(long err, const wxChar *fmt, va_list argptr) -{ - if ( wxLog::IsEnabled() ) { - wxLog::OnLog(wxLOG_Error, - wxString::FormatV(fmt, argptr) + wxLogSysErrorHelper(err), - time(NULL)); - } -} - -void WXDLLEXPORT wxLogSysError(long lErrCode, const wxChar *szFormat, ...) -{ - va_list argptr; - va_start(argptr, szFormat); - wxVLogSysError(lErrCode, szFormat, argptr); - va_end(argptr); -} - -// ---------------------------------------------------------------------------- -// wxLog class implementation -// ---------------------------------------------------------------------------- - -// define a critical section gs_prevCS protecting access to wxLog::ms_prevXXX -wxCRIT_SECT_DECLARE(gs_prevCS); - -/* static */ -unsigned wxLog::DoLogNumberOfRepeats() -{ - wxLog * const pLogger = GetActiveTarget(); - return pLogger ? pLogger->LogLastRepeatIfNeeded() : 0u; -} - -unsigned wxLog::LogLastRepeatIfNeeded() -{ - wxCRIT_SECT_LOCKER(lock, gs_prevCS); - - return LogLastRepeatIfNeededUnlocked(); -} - -unsigned wxLog::LogLastRepeatIfNeededUnlocked() -{ - long retval = ms_prevCounter; - if ( ms_prevCounter > 0 ) - { - wxString msg; -#if wxUSE_INTL - msg.Printf(wxPLURAL("The previous message repeated once.", - "The previous message repeated %lu times.", - ms_prevCounter), - ms_prevCounter); -#else - msg.Printf(wxT("The previous message was repeated.")); -#endif - ms_prevCounter = 0; - ms_prevString.clear(); - DoLog(ms_prevLevel, msg.c_str(), ms_prevTimeStamp); - } - return retval; -} - -wxLog::~wxLog() -{ -} - -/* static */ -void wxLog::OnLog(wxLogLevel level, const wxChar *szString, time_t t) -{ - if ( IsEnabled() && ms_logLevel >= level ) - { - wxLog *pLogger = GetActiveTarget(); - if ( pLogger ) - { - if ( GetRepetitionCounting() ) - { - wxCRIT_SECT_LOCKER(lock, gs_prevCS); - - if ( szString == ms_prevString ) - { - ms_prevCounter++; - - // nothing else to do, in particular, don't log the - // repeated message - return; - } - - pLogger->LogLastRepeatIfNeededUnlocked(); - - // reset repetition counter for a new message - ms_prevString = szString; - ms_prevLevel = level; - ms_prevTimeStamp = t; - } - - pLogger->DoLog(level, szString, t); - } - } -} - -// deprecated function -#if WXWIN_COMPATIBILITY_2_6 - -wxChar *wxLog::SetLogBuffer(wxChar * WXUNUSED(buf), size_t WXUNUSED(size)) -{ - return NULL; -} - -#endif // WXWIN_COMPATIBILITY_2_6 - -wxLog *wxLog::GetActiveTarget() -{ - if ( ms_bAutoCreate && ms_pLogger == NULL ) { - // prevent infinite recursion if someone calls wxLogXXX() from - // wxApp::CreateLogTarget() - static bool s_bInGetActiveTarget = false; - if ( !s_bInGetActiveTarget ) { - s_bInGetActiveTarget = true; - - // ask the application to create a log target for us - if ( wxTheApp != NULL ) - ms_pLogger = wxTheApp->GetTraits()->CreateLogTarget(); - else - ms_pLogger = new wxLogStderr; - - s_bInGetActiveTarget = false; - - // do nothing if it fails - what can we do? - } - } - - return ms_pLogger; -} - -wxLog *wxLog::SetActiveTarget(wxLog *pLogger) -{ - if ( ms_pLogger != NULL ) { - // flush the old messages before changing because otherwise they might - // get lost later if this target is not restored - ms_pLogger->Flush(); - } - - wxLog *pOldLogger = ms_pLogger; - ms_pLogger = pLogger; - - return pOldLogger; -} - -void wxLog::DontCreateOnDemand() -{ - ms_bAutoCreate = false; - - // this is usually called at the end of the program and we assume that it - // is *always* called at the end - so we free memory here to avoid false - // memory leak reports from wxWin memory tracking code - ClearTraceMasks(); -} - -void wxLog::DoCreateOnDemand() -{ - ms_bAutoCreate = true; -} - -void wxLog::RemoveTraceMask(const wxString& str) -{ - int index = ms_aTraceMasks.Index(str); - if ( index != wxNOT_FOUND ) - ms_aTraceMasks.RemoveAt((size_t)index); -} - -void wxLog::ClearTraceMasks() -{ - ms_aTraceMasks.Clear(); -} - -void wxLog::TimeStamp(wxString *str) -{ -#if wxUSE_DATETIME - if ( ms_timestamp ) - { - wxChar buf[256]; - time_t timeNow; - (void)time(&timeNow); - - struct tm tm; - wxStrftime(buf, WXSIZEOF(buf), - ms_timestamp, wxLocaltime_r(&timeNow, &tm)); - - str->Empty(); - *str << buf << wxT(": "); - } -#endif // wxUSE_DATETIME -} - -void wxLog::DoLog(wxLogLevel level, const wxChar *szString, time_t t) -{ - switch ( level ) { - case wxLOG_FatalError: - DoLogString(wxString(_("Fatal error: ")) + szString, t); - DoLogString(_("Program aborted."), t); - Flush(); -#ifdef __WXWINCE__ - ExitThread(3); -#else - abort(); -#endif - break; - - case wxLOG_Error: - DoLogString(wxString(_("Error: ")) + szString, t); - break; - - case wxLOG_Warning: - DoLogString(wxString(_("Warning: ")) + szString, t); - break; - - case wxLOG_Info: - if ( GetVerbose() ) - case wxLOG_Message: - case wxLOG_Status: - default: // log unknown log levels too - DoLogString(szString, t); - break; - - case wxLOG_Trace: - case wxLOG_Debug: -#ifdef __WXDEBUG__ - { - wxString msg = level == wxLOG_Trace ? wxT("Trace: ") - : wxT("Debug: "); - msg << szString; - DoLogString(msg, t); - } -#endif // Debug - break; - } -} - -void wxLog::DoLogString(const wxChar *WXUNUSED(szString), time_t WXUNUSED(t)) -{ - wxFAIL_MSG(wxT("DoLogString must be overriden if it's called.")); -} - -void wxLog::Flush() -{ - LogLastRepeatIfNeeded(); -} - -/*static*/ bool wxLog::IsAllowedTraceMask(const wxChar *mask) -{ - for ( wxArrayString::iterator it = ms_aTraceMasks.begin(), - en = ms_aTraceMasks.end(); - it != en; ++it ) - if ( *it == mask) - return true; - return false; -} - -// ---------------------------------------------------------------------------- -// wxLogBuffer implementation -// ---------------------------------------------------------------------------- - -void wxLogBuffer::Flush() -{ - if ( !m_str.empty() ) - { - wxMessageOutputBest out; - out.Printf(_T("%s"), m_str.c_str()); - m_str.clear(); - } -} - -void wxLogBuffer::DoLog(wxLogLevel level, const wxChar *szString, time_t t) -{ - switch ( level ) - { - case wxLOG_Trace: - case wxLOG_Debug: -#ifdef __WXDEBUG__ - // don't put debug messages in the buffer, we don't want to show - // them to the user in a msg box, log them immediately - { - wxString str; - TimeStamp(&str); - str += szString; - - wxMessageOutputDebug dbgout; - dbgout.Printf(_T("%s\n"), str.c_str()); - } -#endif // __WXDEBUG__ - break; - - default: - wxLog::DoLog(level, szString, t); - } -} - -void wxLogBuffer::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) -{ - m_str << szString << _T("\n"); -} - -// ---------------------------------------------------------------------------- -// wxLogStderr class implementation -// ---------------------------------------------------------------------------- - -wxLogStderr::wxLogStderr(FILE *fp) -{ - if ( fp == NULL ) - m_fp = stderr; - else - m_fp = fp; -} - -void wxLogStderr::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) -{ - wxString str; - TimeStamp(&str); - str << szString; - - wxFputs(str, m_fp); - wxFputc(_T('\n'), m_fp); - fflush(m_fp); - - // under GUI systems such as Windows or Mac, programs usually don't have - // stderr at all, so show the messages also somewhere else, typically in - // the debugger window so that they go at least somewhere instead of being - // simply lost - if ( m_fp == stderr ) - { - wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; - if ( traits && !traits->HasStderr() ) - { - wxMessageOutputDebug dbgout; - dbgout.Printf(_T("%s\n"), str.c_str()); - } - } -} - -// ---------------------------------------------------------------------------- -// wxLogStream implementation -// ---------------------------------------------------------------------------- - -#if wxUSE_STD_IOSTREAM -#include "wx/ioswrap.h" -wxLogStream::wxLogStream(wxSTD ostream *ostr) -{ - if ( ostr == NULL ) - m_ostr = &wxSTD cerr; - else - m_ostr = ostr; -} - -void wxLogStream::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) -{ - wxString str; - TimeStamp(&str); - (*m_ostr) << wxSafeConvertWX2MB(str) << wxSafeConvertWX2MB(szString) << wxSTD endl; -} -#endif // wxUSE_STD_IOSTREAM - -// ---------------------------------------------------------------------------- -// wxLogChain -// ---------------------------------------------------------------------------- - -wxLogChain::wxLogChain(wxLog *logger) -{ - m_bPassMessages = true; - - m_logNew = logger; - m_logOld = wxLog::SetActiveTarget(this); -} - -wxLogChain::~wxLogChain() -{ - wxLog::SetActiveTarget(m_logOld); - - if ( m_logNew != this ) - delete m_logNew; -} - -void wxLogChain::SetLog(wxLog *logger) -{ - if ( m_logNew != this ) - delete m_logNew; - - m_logNew = logger; -} - -void wxLogChain::Flush() -{ - if ( m_logOld ) - m_logOld->Flush(); - - // be careful to avoid infinite recursion - if ( m_logNew && m_logNew != this ) - m_logNew->Flush(); -} - -void wxLogChain::DoLog(wxLogLevel level, const wxChar *szString, time_t t) -{ - // let the previous logger show it - if ( m_logOld && IsPassingMessages() ) - { - // bogus cast just to access protected DoLog - ((wxLogChain *)m_logOld)->DoLog(level, szString, t); - } - - if ( m_logNew && m_logNew != this ) - { - // as above... - ((wxLogChain *)m_logNew)->DoLog(level, szString, t); - } -} - -// ---------------------------------------------------------------------------- -// wxLogPassThrough -// ---------------------------------------------------------------------------- - -#ifdef __VISUALC__ - // "'this' : used in base member initializer list" - so what? - #pragma warning(disable:4355) -#endif // VC++ - -wxLogPassThrough::wxLogPassThrough() - : wxLogChain(this) -{ -} - -#ifdef __VISUALC__ - #pragma warning(default:4355) -#endif // VC++ - -// ============================================================================ -// Global functions/variables -// ============================================================================ - -// ---------------------------------------------------------------------------- -// static variables -// ---------------------------------------------------------------------------- - -bool wxLog::ms_bRepetCounting = false; -wxString wxLog::ms_prevString; -unsigned int wxLog::ms_prevCounter = 0; -time_t wxLog::ms_prevTimeStamp= 0; -wxLogLevel wxLog::ms_prevLevel; - -wxLog *wxLog::ms_pLogger = (wxLog *)NULL; -bool wxLog::ms_doLog = true; -bool wxLog::ms_bAutoCreate = true; -bool wxLog::ms_bVerbose = false; - -wxLogLevel wxLog::ms_logLevel = wxLOG_Max; // log everything by default - -size_t wxLog::ms_suspendCount = 0; - -const wxChar *wxLog::ms_timestamp = wxT("%X"); // time only, no date - -wxTraceMask wxLog::ms_ulTraceMask = (wxTraceMask)0; -wxArrayString wxLog::ms_aTraceMasks; - -// ---------------------------------------------------------------------------- -// stdout error logging helper -// ---------------------------------------------------------------------------- - -// helper function: wraps the message and justifies it under given position -// (looks more pretty on the terminal). Also adds newline at the end. -// -// TODO this is now disabled until I find a portable way of determining the -// terminal window size (ok, I found it but does anybody really cares?) -#ifdef LOG_PRETTY_WRAP -static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz) -{ - size_t nMax = 80; // FIXME - size_t nStart = strlen(pszPrefix); - fputs(pszPrefix, f); - - size_t n; - while ( *psz != '\0' ) { - for ( n = nStart; (n < nMax) && (*psz != '\0'); n++ ) - putc(*psz++, f); - - // wrapped? - if ( *psz != '\0' ) { - /*putc('\n', f);*/ - for ( n = 0; n < nStart; n++ ) - putc(' ', f); - - // as we wrapped, squeeze all white space - while ( isspace(*psz) ) - psz++; - } - } - - putc('\n', f); -} -#endif //LOG_PRETTY_WRAP - -// ---------------------------------------------------------------------------- -// error code/error message retrieval functions -// ---------------------------------------------------------------------------- - -// get error code from syste -unsigned long wxSysErrorCode() -{ -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - return ::GetLastError(); -#else //Unix - return errno; -#endif //Win/Unix -} - -// get error message from system -const wxChar *wxSysErrorMsg(unsigned long nErrCode) -{ - if ( nErrCode == 0 ) - nErrCode = wxSysErrorCode(); - -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - static wxChar s_szBuf[1024]; - - // get error message from system - LPVOID lpMsgBuf; - if ( ::FormatMessage - ( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - nErrCode, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR)&lpMsgBuf, - 0, - NULL - ) == 0 ) - { - // if this happens, something is seriously wrong, so don't use _() here - // for safety - wxSprintf(s_szBuf, _T("unknown error %lx"), nErrCode); - return s_szBuf; - } - - - // copy it to our buffer and free memory - // Crashes on SmartPhone (FIXME) -#if !defined(__SMARTPHONE__) /* of WinCE */ - if( lpMsgBuf != 0 ) - { - wxStrncpy(s_szBuf, (const wxChar *)lpMsgBuf, WXSIZEOF(s_szBuf) - 1); - s_szBuf[WXSIZEOF(s_szBuf) - 1] = wxT('\0'); - - LocalFree(lpMsgBuf); - - // returned string is capitalized and ended with '\r\n' - bad - s_szBuf[0] = (wxChar)wxTolower(s_szBuf[0]); - size_t len = wxStrlen(s_szBuf); - if ( len > 0 ) { - // truncate string - if ( s_szBuf[len - 2] == wxT('\r') ) - s_szBuf[len - 2] = wxT('\0'); - } - } - else -#endif // !__SMARTPHONE__ - { - s_szBuf[0] = wxT('\0'); - } - - return s_szBuf; -#else // !__WXMSW__ - #if wxUSE_UNICODE - static wchar_t s_wzBuf[1024]; - wxConvCurrent->MB2WC(s_wzBuf, strerror((int)nErrCode), - WXSIZEOF(s_wzBuf) - 1); - return s_wzBuf; - #else - return strerror((int)nErrCode); - #endif -#endif // __WXMSW__/!__WXMSW__ -} - -#endif // wxUSE_LOG +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/log.cpp +// Purpose: Assorted wxLogXXX functions, and wxLog (sink for logs) +// Author: Vadim Zeitlin +// Modified by: +// Created: 29/01/98 +// RCS-ID: $Id: log.cpp 67119 2011-03-03 15:09:44Z JS $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_LOG + +// wxWidgets +#ifndef WX_PRECOMP + #include "wx/log.h" + #include "wx/app.h" + #include "wx/arrstr.h" + #include "wx/intl.h" + #include "wx/string.h" + #include "wx/utils.h" +#endif //WX_PRECOMP + +#include "wx/apptrait.h" +#include "wx/datetime.h" +#include "wx/file.h" +#include "wx/msgout.h" +#include "wx/textfile.h" +#include "wx/thread.h" +#include "wx/wxchar.h" + +// other standard headers +#ifndef __WXWINCE__ +#include +#endif + +#include + +#ifndef __WXWINCE__ +#include +#else +#include "wx/msw/wince/time.h" +#endif + +#if defined(__WINDOWS__) + #include "wx/msw/private.h" // includes windows.h +#endif + +// ---------------------------------------------------------------------------- +// non member functions +// ---------------------------------------------------------------------------- + +// define this to enable wrapping of log messages +//#define LOG_PRETTY_WRAP + +#ifdef LOG_PRETTY_WRAP + static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz); +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// implementation of Log functions +// +// NB: unfortunately we need all these distinct functions, we can't make them +// macros and not all compilers inline vararg functions. +// ---------------------------------------------------------------------------- + +// generic log function +void wxVLogGeneric(wxLogLevel level, const wxChar *szFormat, va_list argptr) +{ + if ( wxLog::IsEnabled() ) { + wxLog::OnLog(level, wxString::FormatV(szFormat, argptr), time(NULL)); + } +} + +void wxLogGeneric(wxLogLevel level, const wxChar *szFormat, ...) +{ + va_list argptr; + va_start(argptr, szFormat); + wxVLogGeneric(level, szFormat, argptr); + va_end(argptr); +} + +#define IMPLEMENT_LOG_FUNCTION(level) \ + void wxVLog##level(const wxChar *szFormat, va_list argptr) \ + { \ + if ( wxLog::IsEnabled() ) { \ + wxLog::OnLog(wxLOG_##level, \ + wxString::FormatV(szFormat, argptr), time(NULL));\ + } \ + } \ + \ + void wxLog##level(const wxChar *szFormat, ...) \ + { \ + va_list argptr; \ + va_start(argptr, szFormat); \ + wxVLog##level(szFormat, argptr); \ + va_end(argptr); \ + } + +IMPLEMENT_LOG_FUNCTION(Error) +IMPLEMENT_LOG_FUNCTION(Warning) +IMPLEMENT_LOG_FUNCTION(Message) +IMPLEMENT_LOG_FUNCTION(Info) +IMPLEMENT_LOG_FUNCTION(Status) + +void wxSafeShowMessage(const wxString& title, const wxString& text) +{ +#ifdef __WINDOWS__ + ::MessageBox(NULL, text, title, MB_OK | MB_ICONSTOP); +#else + wxFprintf(stderr, _T("%s: %s\n"), title.c_str(), text.c_str()); + fflush(stderr); +#endif +} + +// fatal errors can't be suppressed nor handled by the custom log target and +// always terminate the program +void wxVLogFatalError(const wxChar *szFormat, va_list argptr) +{ + wxSafeShowMessage(_T("Fatal Error"), wxString::FormatV(szFormat, argptr)); + +#ifdef __WXWINCE__ + ExitThread(3); +#else + abort(); +#endif +} + +void wxLogFatalError(const wxChar *szFormat, ...) +{ + va_list argptr; + va_start(argptr, szFormat); + wxVLogFatalError(szFormat, argptr); + + // some compilers warn about unreachable code and it shouldn't matter + // for the others anyhow... + //va_end(argptr); +} + +// same as info, but only if 'verbose' mode is on +void wxVLogVerbose(const wxChar *szFormat, va_list argptr) +{ + if ( wxLog::IsEnabled() ) { + if ( wxLog::GetActiveTarget() != NULL && wxLog::GetVerbose() ) { + wxLog::OnLog(wxLOG_Info, + wxString::FormatV(szFormat, argptr), time(NULL)); + } + } +} + +void wxLogVerbose(const wxChar *szFormat, ...) +{ + va_list argptr; + va_start(argptr, szFormat); + wxVLogVerbose(szFormat, argptr); + va_end(argptr); +} + +// debug functions +#ifdef __WXDEBUG__ +#define IMPLEMENT_LOG_DEBUG_FUNCTION(level) \ + void wxVLog##level(const wxChar *szFormat, va_list argptr) \ + { \ + if ( wxLog::IsEnabled() ) { \ + wxLog::OnLog(wxLOG_##level, \ + wxString::FormatV(szFormat, argptr), time(NULL));\ + } \ + } \ + \ + void wxLog##level(const wxChar *szFormat, ...) \ + { \ + va_list argptr; \ + va_start(argptr, szFormat); \ + wxVLog##level(szFormat, argptr); \ + va_end(argptr); \ + } + + void wxVLogTrace(const wxChar *mask, const wxChar *szFormat, va_list argptr) + { + if ( wxLog::IsEnabled() && wxLog::IsAllowedTraceMask(mask) ) { + wxString msg; + msg << _T("(") << mask << _T(") ") << wxString::FormatV(szFormat, argptr); + + wxLog::OnLog(wxLOG_Trace, msg, time(NULL)); + } + } + + void wxLogTrace(const wxChar *mask, const wxChar *szFormat, ...) + { + va_list argptr; + va_start(argptr, szFormat); + wxVLogTrace(mask, szFormat, argptr); + va_end(argptr); + } + + void wxVLogTrace(wxTraceMask mask, const wxChar *szFormat, va_list argptr) + { + // we check that all of mask bits are set in the current mask, so + // that wxLogTrace(wxTraceRefCount | wxTraceOle) will only do something + // if both bits are set. + if ( wxLog::IsEnabled() && ((wxLog::GetTraceMask() & mask) == mask) ) { + wxLog::OnLog(wxLOG_Trace, wxString::FormatV(szFormat, argptr), time(NULL)); + } + } + + void wxLogTrace(wxTraceMask mask, const wxChar *szFormat, ...) + { + va_list argptr; + va_start(argptr, szFormat); + wxVLogTrace(mask, szFormat, argptr); + va_end(argptr); + } + +#else // release + #define IMPLEMENT_LOG_DEBUG_FUNCTION(level) +#endif + +IMPLEMENT_LOG_DEBUG_FUNCTION(Debug) +IMPLEMENT_LOG_DEBUG_FUNCTION(Trace) + +// wxLogSysError: one uses the last error code, for other you must give it +// explicitly + +// return the system error message description +static inline wxString wxLogSysErrorHelper(long err) +{ + return wxString::Format(_(" (error %ld: %s)"), err, wxSysErrorMsg(err)); +} + +void WXDLLEXPORT wxVLogSysError(const wxChar *szFormat, va_list argptr) +{ + wxVLogSysError(wxSysErrorCode(), szFormat, argptr); +} + +void WXDLLEXPORT wxLogSysError(const wxChar *szFormat, ...) +{ + va_list argptr; + va_start(argptr, szFormat); + wxVLogSysError(szFormat, argptr); + va_end(argptr); +} + +void WXDLLEXPORT wxVLogSysError(long err, const wxChar *fmt, va_list argptr) +{ + if ( wxLog::IsEnabled() ) { + wxLog::OnLog(wxLOG_Error, + wxString::FormatV(fmt, argptr) + wxLogSysErrorHelper(err), + time(NULL)); + } +} + +void WXDLLEXPORT wxLogSysError(long lErrCode, const wxChar *szFormat, ...) +{ + va_list argptr; + va_start(argptr, szFormat); + wxVLogSysError(lErrCode, szFormat, argptr); + va_end(argptr); +} + +// ---------------------------------------------------------------------------- +// wxLog class implementation +// ---------------------------------------------------------------------------- + +// define a critical section gs_prevCS protecting access to wxLog::ms_prevXXX +wxCRIT_SECT_DECLARE(gs_prevCS); + +/* static */ +unsigned wxLog::DoLogNumberOfRepeats() +{ + wxLog * const pLogger = GetActiveTarget(); + return pLogger ? pLogger->LogLastRepeatIfNeeded() : 0u; +} + +unsigned wxLog::LogLastRepeatIfNeeded() +{ + wxCRIT_SECT_LOCKER(lock, gs_prevCS); + + return LogLastRepeatIfNeededUnlocked(); +} + +unsigned wxLog::LogLastRepeatIfNeededUnlocked() +{ + long retval = ms_prevCounter; + if ( ms_prevCounter > 0 ) + { + wxString msg; +#if wxUSE_INTL + msg.Printf(wxPLURAL("The previous message repeated once.", + "The previous message repeated %lu times.", + ms_prevCounter), + ms_prevCounter); +#else + msg.Printf(wxT("The previous message was repeated.")); +#endif + ms_prevCounter = 0; + ms_prevString.clear(); + DoLog(ms_prevLevel, msg.c_str(), ms_prevTimeStamp); + } + return retval; +} + +wxLog::~wxLog() +{ +} + +/* static */ +void wxLog::OnLog(wxLogLevel level, const wxChar *szString, time_t t) +{ + if ( IsEnabled() && ms_logLevel >= level ) + { + wxLog *pLogger = GetActiveTarget(); + if ( pLogger ) + { + if ( GetRepetitionCounting() ) + { + wxCRIT_SECT_LOCKER(lock, gs_prevCS); + + if ( szString == ms_prevString ) + { + ms_prevCounter++; + + // nothing else to do, in particular, don't log the + // repeated message + return; + } + + pLogger->LogLastRepeatIfNeededUnlocked(); + + // reset repetition counter for a new message + ms_prevString = szString; + ms_prevLevel = level; + ms_prevTimeStamp = t; + } + + pLogger->DoLog(level, szString, t); + } + } +} + +// deprecated function +#if WXWIN_COMPATIBILITY_2_6 + +wxChar *wxLog::SetLogBuffer(wxChar * WXUNUSED(buf), size_t WXUNUSED(size)) +{ + return NULL; +} + +#endif // WXWIN_COMPATIBILITY_2_6 + +wxLog *wxLog::GetActiveTarget() +{ + if ( ms_bAutoCreate && ms_pLogger == NULL ) { + // prevent infinite recursion if someone calls wxLogXXX() from + // wxApp::CreateLogTarget() + static bool s_bInGetActiveTarget = false; + if ( !s_bInGetActiveTarget ) { + s_bInGetActiveTarget = true; + + // ask the application to create a log target for us + if ( wxTheApp != NULL ) + ms_pLogger = wxTheApp->GetTraits()->CreateLogTarget(); + else + ms_pLogger = new wxLogStderr; + + s_bInGetActiveTarget = false; + + // do nothing if it fails - what can we do? + } + } + + return ms_pLogger; +} + +wxLog *wxLog::SetActiveTarget(wxLog *pLogger) +{ + if ( ms_pLogger != NULL ) { + // flush the old messages before changing because otherwise they might + // get lost later if this target is not restored + ms_pLogger->Flush(); + } + + wxLog *pOldLogger = ms_pLogger; + ms_pLogger = pLogger; + + return pOldLogger; +} + +void wxLog::DontCreateOnDemand() +{ + ms_bAutoCreate = false; + + // this is usually called at the end of the program and we assume that it + // is *always* called at the end - so we free memory here to avoid false + // memory leak reports from wxWin memory tracking code + ClearTraceMasks(); +} + +void wxLog::DoCreateOnDemand() +{ + ms_bAutoCreate = true; +} + +void wxLog::RemoveTraceMask(const wxString& str) +{ + int index = ms_aTraceMasks.Index(str); + if ( index != wxNOT_FOUND ) + ms_aTraceMasks.RemoveAt((size_t)index); +} + +void wxLog::ClearTraceMasks() +{ + ms_aTraceMasks.Clear(); +} + +void wxLog::TimeStamp(wxString *str) +{ +#if wxUSE_DATETIME + if ( ms_timestamp ) + { + wxChar buf[256]; + time_t timeNow; + (void)time(&timeNow); + + struct tm tm; + wxStrftime(buf, WXSIZEOF(buf), + ms_timestamp, wxLocaltime_r(&timeNow, &tm)); + + str->Empty(); + *str << buf << wxT(": "); + } +#endif // wxUSE_DATETIME +} + +void wxLog::DoLog(wxLogLevel level, const wxChar *szString, time_t t) +{ + switch ( level ) { + case wxLOG_FatalError: + DoLogString(wxString(_("Fatal error: ")) + szString, t); + DoLogString(_("Program aborted."), t); + Flush(); +#ifdef __WXWINCE__ + ExitThread(3); +#else + abort(); +#endif + break; + + case wxLOG_Error: + DoLogString(wxString(_("Error: ")) + szString, t); + break; + + case wxLOG_Warning: + DoLogString(wxString(_("Warning: ")) + szString, t); + break; + + case wxLOG_Info: + if ( GetVerbose() ) + case wxLOG_Message: + case wxLOG_Status: + default: // log unknown log levels too + DoLogString(szString, t); + break; + + case wxLOG_Trace: + case wxLOG_Debug: +#ifdef __WXDEBUG__ + { + wxString msg = level == wxLOG_Trace ? wxT("Trace: ") + : wxT("Debug: "); + msg << szString; + DoLogString(msg, t); + } +#endif // Debug + break; + } +} + +void wxLog::DoLogString(const wxChar *WXUNUSED(szString), time_t WXUNUSED(t)) +{ + wxFAIL_MSG(wxT("DoLogString must be overriden if it's called.")); +} + +void wxLog::Flush() +{ + LogLastRepeatIfNeeded(); +} + +/*static*/ bool wxLog::IsAllowedTraceMask(const wxChar *mask) +{ + for ( wxArrayString::iterator it = ms_aTraceMasks.begin(), + en = ms_aTraceMasks.end(); + it != en; ++it ) + if ( *it == mask) + return true; + return false; +} + +// ---------------------------------------------------------------------------- +// wxLogBuffer implementation +// ---------------------------------------------------------------------------- + +void wxLogBuffer::Flush() +{ + if ( !m_str.empty() ) + { + wxMessageOutputBest out; + out.Printf(_T("%s"), m_str.c_str()); + m_str.clear(); + } +} + +void wxLogBuffer::DoLog(wxLogLevel level, const wxChar *szString, time_t t) +{ + switch ( level ) + { + case wxLOG_Trace: + case wxLOG_Debug: +#ifdef __WXDEBUG__ + // don't put debug messages in the buffer, we don't want to show + // them to the user in a msg box, log them immediately + { + wxString str; + TimeStamp(&str); + str += szString; + + wxMessageOutputDebug dbgout; + dbgout.Printf(_T("%s\n"), str.c_str()); + } +#endif // __WXDEBUG__ + break; + + default: + wxLog::DoLog(level, szString, t); + } +} + +void wxLogBuffer::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) +{ + m_str << szString << _T("\n"); +} + +// ---------------------------------------------------------------------------- +// wxLogStderr class implementation +// ---------------------------------------------------------------------------- + +wxLogStderr::wxLogStderr(FILE *fp) +{ + if ( fp == NULL ) + m_fp = stderr; + else + m_fp = fp; +} + +void wxLogStderr::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) +{ + wxString str; + TimeStamp(&str); + str << szString; + + wxFputs(str, m_fp); + wxFputc(_T('\n'), m_fp); + fflush(m_fp); + + // under GUI systems such as Windows or Mac, programs usually don't have + // stderr at all, so show the messages also somewhere else, typically in + // the debugger window so that they go at least somewhere instead of being + // simply lost + if ( m_fp == stderr ) + { + wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; + if ( traits && !traits->HasStderr() ) + { + wxMessageOutputDebug dbgout; + dbgout.Printf(_T("%s\n"), str.c_str()); + } + } +} + +// ---------------------------------------------------------------------------- +// wxLogStream implementation +// ---------------------------------------------------------------------------- + +#if wxUSE_STD_IOSTREAM +#include "wx/ioswrap.h" +wxLogStream::wxLogStream(wxSTD ostream *ostr) +{ + if ( ostr == NULL ) + m_ostr = &wxSTD cerr; + else + m_ostr = ostr; +} + +void wxLogStream::DoLogString(const wxChar *szString, time_t WXUNUSED(t)) +{ + wxString str; + TimeStamp(&str); + (*m_ostr) << wxSafeConvertWX2MB(str) << wxSafeConvertWX2MB(szString) << wxSTD endl; +} +#endif // wxUSE_STD_IOSTREAM + +// ---------------------------------------------------------------------------- +// wxLogChain +// ---------------------------------------------------------------------------- + +wxLogChain::wxLogChain(wxLog *logger) +{ + m_bPassMessages = true; + + m_logNew = logger; + m_logOld = wxLog::SetActiveTarget(this); +} + +wxLogChain::~wxLogChain() +{ + wxLog::SetActiveTarget(m_logOld); + + if ( m_logNew != this ) + delete m_logNew; +} + +void wxLogChain::SetLog(wxLog *logger) +{ + if ( m_logNew != this ) + delete m_logNew; + + m_logNew = logger; +} + +void wxLogChain::Flush() +{ + if ( m_logOld ) + m_logOld->Flush(); + + // be careful to avoid infinite recursion + if ( m_logNew && m_logNew != this ) + m_logNew->Flush(); +} + +void wxLogChain::DoLog(wxLogLevel level, const wxChar *szString, time_t t) +{ + // let the previous logger show it + if ( m_logOld && IsPassingMessages() ) + { + // bogus cast just to access protected DoLog + ((wxLogChain *)m_logOld)->DoLog(level, szString, t); + } + + if ( m_logNew && m_logNew != this ) + { + // as above... + ((wxLogChain *)m_logNew)->DoLog(level, szString, t); + } +} + +// ---------------------------------------------------------------------------- +// wxLogPassThrough +// ---------------------------------------------------------------------------- + +#ifdef __VISUALC__ + // "'this' : used in base member initializer list" - so what? + #pragma warning(disable:4355) +#endif // VC++ + +wxLogPassThrough::wxLogPassThrough() + : wxLogChain(this) +{ +} + +#ifdef __VISUALC__ + #pragma warning(default:4355) +#endif // VC++ + +// ============================================================================ +// Global functions/variables +// ============================================================================ + +// ---------------------------------------------------------------------------- +// static variables +// ---------------------------------------------------------------------------- + +bool wxLog::ms_bRepetCounting = false; +wxString wxLog::ms_prevString; +unsigned int wxLog::ms_prevCounter = 0; +time_t wxLog::ms_prevTimeStamp= 0; +wxLogLevel wxLog::ms_prevLevel; + +wxLog *wxLog::ms_pLogger = (wxLog *)NULL; +bool wxLog::ms_doLog = true; +bool wxLog::ms_bAutoCreate = true; +bool wxLog::ms_bVerbose = false; + +wxLogLevel wxLog::ms_logLevel = wxLOG_Max; // log everything by default + +size_t wxLog::ms_suspendCount = 0; + +const wxChar *wxLog::ms_timestamp = wxT("%X"); // time only, no date + +wxTraceMask wxLog::ms_ulTraceMask = (wxTraceMask)0; +wxArrayString wxLog::ms_aTraceMasks; + +// ---------------------------------------------------------------------------- +// stdout error logging helper +// ---------------------------------------------------------------------------- + +// helper function: wraps the message and justifies it under given position +// (looks more pretty on the terminal). Also adds newline at the end. +// +// TODO this is now disabled until I find a portable way of determining the +// terminal window size (ok, I found it but does anybody really cares?) +#ifdef LOG_PRETTY_WRAP +static void wxLogWrap(FILE *f, const char *pszPrefix, const char *psz) +{ + size_t nMax = 80; // FIXME + size_t nStart = strlen(pszPrefix); + fputs(pszPrefix, f); + + size_t n; + while ( *psz != '\0' ) { + for ( n = nStart; (n < nMax) && (*psz != '\0'); n++ ) + putc(*psz++, f); + + // wrapped? + if ( *psz != '\0' ) { + /*putc('\n', f);*/ + for ( n = 0; n < nStart; n++ ) + putc(' ', f); + + // as we wrapped, squeeze all white space + while ( isspace(*psz) ) + psz++; + } + } + + putc('\n', f); +} +#endif //LOG_PRETTY_WRAP + +// ---------------------------------------------------------------------------- +// error code/error message retrieval functions +// ---------------------------------------------------------------------------- + +// get error code from syste +unsigned long wxSysErrorCode() +{ +#if defined(__WXMSW__) && !defined(__WXMICROWIN__) + return ::GetLastError(); +#else //Unix + return errno; +#endif //Win/Unix +} + +// get error message from system +const wxChar *wxSysErrorMsg(unsigned long nErrCode) +{ + if ( nErrCode == 0 ) + nErrCode = wxSysErrorCode(); + +#if defined(__WXMSW__) && !defined(__WXMICROWIN__) + static wxChar s_szBuf[1024]; + + // get error message from system + LPVOID lpMsgBuf; + if ( ::FormatMessage + ( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + nErrCode, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR)&lpMsgBuf, + 0, + NULL + ) == 0 ) + { + // if this happens, something is seriously wrong, so don't use _() here + // for safety + wxSprintf(s_szBuf, _T("unknown error %lx"), nErrCode); + return s_szBuf; + } + + + // copy it to our buffer and free memory + // Crashes on SmartPhone (FIXME) +#if !defined(__SMARTPHONE__) /* of WinCE */ + if( lpMsgBuf != 0 ) + { + wxStrncpy(s_szBuf, (const wxChar *)lpMsgBuf, WXSIZEOF(s_szBuf) - 1); + s_szBuf[WXSIZEOF(s_szBuf) - 1] = wxT('\0'); + + LocalFree(lpMsgBuf); + + // returned string is capitalized and ended with '\r\n' - bad + s_szBuf[0] = (wxChar)wxTolower(s_szBuf[0]); + size_t len = wxStrlen(s_szBuf); + if ( len > 0 ) { + // truncate string + if ( s_szBuf[len - 2] == wxT('\r') ) + s_szBuf[len - 2] = wxT('\0'); + } + } + else +#endif // !__SMARTPHONE__ + { + s_szBuf[0] = wxT('\0'); + } + + return s_szBuf; +#else // !__WXMSW__ + #if wxUSE_UNICODE + static wchar_t s_wzBuf[1024]; + wxConvCurrent->MB2WC(s_wzBuf, strerror((int)nErrCode), + WXSIZEOF(s_wzBuf) - 1); + return s_wzBuf; + #else + return strerror((int)nErrCode); + #endif +#endif // __WXMSW__/!__WXMSW__ +} + +#endif // wxUSE_LOG diff --git a/Source/3rd Party/wx/src/common/longlong.cpp b/Source/3rd Party/wx/src/common/longlong.cpp index af121be81..78a47ce25 100644 --- a/Source/3rd Party/wx/src/common/longlong.cpp +++ b/Source/3rd Party/wx/src/common/longlong.cpp @@ -1,1363 +1,1363 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/longlong.cpp -// Purpose: implementation of wxLongLongNative -// Author: Jeffrey C. Ollie , Vadim Zeitlin -// Remarks: this class is not public in wxWidgets 2.0! It is intentionally -// not documented and is for private use only. -// Modified by: -// Created: 10.02.99 -// RCS-ID: $Id: longlong.cpp 40750 2006-08-22 19:04:45Z MW $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// headers -// ============================================================================ - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_LONGLONG - -#include "wx/longlong.h" - -#ifndef WX_PRECOMP - #include "wx/math.h" // for fabs() -#endif - -#if wxUSE_STREAMS - #include "wx/txtstrm.h" -#endif - -#include // for memset() - -#include "wx/ioswrap.h" - -// ============================================================================ -// implementation -// ============================================================================ - -#if wxUSE_LONGLONG_NATIVE - -// ---------------------------------------------------------------------------- -// misc -// ---------------------------------------------------------------------------- - -void *wxLongLongNative::asArray() const -{ - static unsigned char temp[8]; - - temp[0] = wx_truncate_cast(unsigned char, ((m_ll >> 56) & 0xFF)); - temp[1] = wx_truncate_cast(unsigned char, ((m_ll >> 48) & 0xFF)); - temp[2] = wx_truncate_cast(unsigned char, ((m_ll >> 40) & 0xFF)); - temp[3] = wx_truncate_cast(unsigned char, ((m_ll >> 32) & 0xFF)); - temp[4] = wx_truncate_cast(unsigned char, ((m_ll >> 24) & 0xFF)); - temp[5] = wx_truncate_cast(unsigned char, ((m_ll >> 16) & 0xFF)); - temp[6] = wx_truncate_cast(unsigned char, ((m_ll >> 8) & 0xFF)); - temp[7] = wx_truncate_cast(unsigned char, ((m_ll >> 0) & 0xFF)); - - return temp; -} - -void *wxULongLongNative::asArray() const -{ - static unsigned char temp[8]; - - temp[0] = wx_truncate_cast(unsigned char, ((m_ll >> 56) & 0xFF)); - temp[1] = wx_truncate_cast(unsigned char, ((m_ll >> 48) & 0xFF)); - temp[2] = wx_truncate_cast(unsigned char, ((m_ll >> 40) & 0xFF)); - temp[3] = wx_truncate_cast(unsigned char, ((m_ll >> 32) & 0xFF)); - temp[4] = wx_truncate_cast(unsigned char, ((m_ll >> 24) & 0xFF)); - temp[5] = wx_truncate_cast(unsigned char, ((m_ll >> 16) & 0xFF)); - temp[6] = wx_truncate_cast(unsigned char, ((m_ll >> 8) & 0xFF)); - temp[7] = wx_truncate_cast(unsigned char, ((m_ll >> 0) & 0xFF)); - - return temp; -} - -#if wxUSE_LONGLONG_WX -wxLongLongNative::wxLongLongNative(wxLongLongWx ll) -{ - // assign first to avoid precision loss! - m_ll = ll.GetHi(); - m_ll <<= 32; - m_ll |= ll.GetLo(); -} - -wxLongLongNative& wxLongLongNative::operator=(wxLongLongWx ll) -{ - // assign first to avoid precision loss! - m_ll = ll.GetHi(); - m_ll <<= 32; - m_ll |= ll.GetLo(); - return *this; -} - -wxLongLongNative& wxLongLongNative::operator=(const class wxULongLongWx &ll) -{ - // assign first to avoid precision loss! - m_ll = ll.GetHi(); - m_ll <<= 32; - m_ll |= ll.GetLo(); - return *this; -} - -wxULongLongNative::wxULongLongNative(const class wxULongLongWx &ll) -{ - // assign first to avoid precision loss! - m_ll = ll.GetHi(); - m_ll <<= 32; - m_ll |= ((unsigned long) ll.GetLo()); -} - -wxULongLongNative& wxULongLongNative::operator=(wxLongLongWx ll) -{ - // assign first to avoid precision loss! - m_ll = ll.GetHi(); - m_ll <<= 32; - m_ll |= ((unsigned long) ll.GetLo()); - return *this; -} - -wxULongLongNative& wxULongLongNative::operator=(const class wxULongLongWx &ll) -{ - // assign first to avoid precision loss! - m_ll = ll.GetHi(); - m_ll <<= 32; - m_ll |= ((unsigned long) ll.GetLo()); - return *this; -} -#endif - -#endif // wxUSE_LONGLONG_NATIVE - -// ============================================================================ -// wxLongLongWx: emulation of 'long long' using 2 longs -// ============================================================================ - -#if wxUSE_LONGLONG_WX - -// Set value from unsigned wxULongLongWx -wxLongLongWx &wxLongLongWx::operator=(const class wxULongLongWx &ll) -{ - m_hi = (unsigned long) ll.GetHi(); - m_lo = ll.GetLo(); - return *this; -} - -// assignment -wxLongLongWx& wxLongLongWx::Assign(double d) -{ - bool positive = d >= 0; - d = fabs(d); - if ( d <= ULONG_MAX ) - { - m_hi = 0; - m_lo = (long)d; - } - else - { - m_hi = (unsigned long)(d / (1.0 + (double)ULONG_MAX)); - m_lo = (unsigned long)(d - ((double)m_hi * (1.0 + (double)ULONG_MAX))); - } - -#ifdef wxLONGLONG_TEST_MODE - m_ll = (wxLongLong_t)d; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - if ( !positive ) - Negate(); - - return *this; -} - -double wxLongLongWx::ToDouble() const -{ - double d = m_hi; - d *= 1.0 + (double)ULONG_MAX; - d += m_lo; - -#ifdef wxLONGLONG_TEST_MODE - wxASSERT( d == m_ll ); -#endif // wxLONGLONG_TEST_MODE - - return d; -} - -double wxULongLongWx::ToDouble() const -{ - unsigned double d = m_hi; - d *= 1.0 + (double)ULONG_MAX; - d += m_lo; - -#ifdef wxLONGLONG_TEST_MODE - wxASSERT( d == m_ll ); -#endif // wxLONGLONG_TEST_MODE - - return d; -} - -wxLongLongWx wxLongLongWx::operator<<(int shift) const -{ - wxLongLongWx ll(*this); - ll <<= shift; - - return ll; -} - -wxULongLongWx wxULongLongWx::operator<<(int shift) const -{ - wxULongLongWx ll(*this); - ll <<= shift; - - return ll; -} - -wxLongLongWx& wxLongLongWx::operator<<=(int shift) -{ - if (shift != 0) - { - if (shift < 32) - { - m_hi <<= shift; - m_hi |= m_lo >> (32 - shift); - m_lo <<= shift; - } - else - { - m_hi = m_lo << (shift - 32); - m_lo = 0; - } - } - -#ifdef wxLONGLONG_TEST_MODE - m_ll <<= shift; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator<<=(int shift) -{ - if (shift != 0) - { - if (shift < 32) - { - m_hi <<= shift; - m_hi |= m_lo >> (32 - shift); - m_lo <<= shift; - } - else - { - m_hi = m_lo << (shift - 32); - m_lo = 0; - } - } - -#ifdef wxLONGLONG_TEST_MODE - m_ll <<= shift; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxLongLongWx wxLongLongWx::operator>>(int shift) const -{ - wxLongLongWx ll(*this); - ll >>= shift; - - return ll; -} - -wxULongLongWx wxULongLongWx::operator>>(int shift) const -{ - wxULongLongWx ll(*this); - ll >>= shift; - - return ll; -} - -wxLongLongWx& wxLongLongWx::operator>>=(int shift) -{ - if (shift != 0) - { - if (shift < 32) - { - m_lo >>= shift; - m_lo |= m_hi << (32 - shift); - m_hi >>= shift; - } - else - { - m_lo = m_hi >> (shift - 32); - m_hi = (m_hi < 0 ? -1L : 0); - } - } - -#ifdef wxLONGLONG_TEST_MODE - m_ll >>= shift; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator>>=(int shift) -{ - if (shift != 0) - { - if (shift < 32) - { - m_lo >>= shift; - m_lo |= m_hi << (32 - shift); - m_hi >>= shift; - } - else - { - m_lo = m_hi >> (shift - 32); - m_hi = 0; - } - } - -#ifdef wxLONGLONG_TEST_MODE - m_ll >>= shift; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxLongLongWx wxLongLongWx::operator+(const wxLongLongWx& ll) const -{ - wxLongLongWx res(*this); - res += ll; - - return res; -} - -wxULongLongWx wxULongLongWx::operator+(const wxULongLongWx& ll) const -{ - wxULongLongWx res(*this); - res += ll; - - return res; -} - -wxLongLongWx wxLongLongWx::operator+(long l) const -{ - wxLongLongWx res(*this); - res += l; - - return res; -} - -wxULongLongWx wxULongLongWx::operator+(unsigned long l) const -{ - wxULongLongWx res(*this); - res += l; - - return res; -} - -wxLongLongWx& wxLongLongWx::operator+=(const wxLongLongWx& ll) -{ - unsigned long previous = m_lo; - - m_lo += ll.m_lo; - m_hi += ll.m_hi; - - if ((m_lo < previous) || (m_lo < ll.m_lo)) - m_hi++; - -#ifdef wxLONGLONG_TEST_MODE - m_ll += ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator+=(const wxULongLongWx& ll) -{ - unsigned long previous = m_lo; - - m_lo += ll.m_lo; - m_hi += ll.m_hi; - - if ((m_lo < previous) || (m_lo < ll.m_lo)) - m_hi++; - -#ifdef wxLONGLONG_TEST_MODE - m_ll += ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxLongLongWx& wxLongLongWx::operator+=(long l) -{ - unsigned long previous = m_lo; - - m_lo += l; - if (l < 0) - m_hi += -1l; - - if ((m_lo < previous) || (m_lo < (unsigned long)l)) - m_hi++; - -#ifdef wxLONGLONG_TEST_MODE - m_ll += l; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator+=(unsigned long l) -{ - unsigned long previous = m_lo; - - m_lo += l; - - if ((m_lo < previous) || (m_lo < l)) - m_hi++; - -#ifdef wxLONGLONG_TEST_MODE - m_ll += l; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -// pre increment -wxLongLongWx& wxLongLongWx::operator++() -{ - m_lo++; - if (m_lo == 0) - m_hi++; - -#ifdef wxLONGLONG_TEST_MODE - m_ll++; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator++() -{ - m_lo++; - if (m_lo == 0) - m_hi++; - -#ifdef wxLONGLONG_TEST_MODE - m_ll++; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -// negation -wxLongLongWx wxLongLongWx::operator-() const -{ - wxLongLongWx res(*this); - res.Negate(); - - return res; -} - -wxLongLongWx& wxLongLongWx::Negate() -{ - m_hi = ~m_hi; - m_lo = ~m_lo; - - m_lo++; - if ( m_lo == 0 ) - m_hi++; - -#ifdef wxLONGLONG_TEST_MODE - m_ll = -m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -// subtraction - -wxLongLongWx wxLongLongWx::operator-(const wxLongLongWx& ll) const -{ - wxLongLongWx res(*this); - res -= ll; - - return res; -} - -wxLongLongWx wxULongLongWx::operator-(const wxULongLongWx& ll) const -{ - wxASSERT(m_hi <= LONG_MAX ); - wxASSERT(ll.m_hi <= LONG_MAX ); - - wxLongLongWx res( (long)m_hi , m_lo ); - wxLongLongWx op( (long)ll.m_hi , ll.m_lo ); - res -= op; - - return res; -} - -wxLongLongWx& wxLongLongWx::operator-=(const wxLongLongWx& ll) -{ - unsigned long previous = m_lo; - - m_lo -= ll.m_lo; - m_hi -= ll.m_hi; - - if (previous < ll.m_lo) - m_hi--; - -#ifdef wxLONGLONG_TEST_MODE - m_ll -= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator-=(const wxULongLongWx& ll) -{ - unsigned long previous = m_lo; - - m_lo -= ll.m_lo; - m_hi -= ll.m_hi; - - if (previous < ll.m_lo) - m_hi--; - -#ifdef wxLONGLONG_TEST_MODE - m_ll -= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -// pre decrement -wxLongLongWx& wxLongLongWx::operator--() -{ - m_lo--; - if (m_lo == 0xFFFFFFFF) - m_hi--; - -#ifdef wxLONGLONG_TEST_MODE - m_ll--; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator--() -{ - m_lo--; - if (m_lo == 0xFFFFFFFF) - m_hi--; - -#ifdef wxLONGLONG_TEST_MODE - m_ll--; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -// comparison operators - -bool wxLongLongWx::operator<(const wxLongLongWx& ll) const -{ - if ( m_hi < ll.m_hi ) - return true; - else if ( m_hi == ll.m_hi ) - return m_lo < ll.m_lo; - else - return false; -} - -bool wxULongLongWx::operator<(const wxULongLongWx& ll) const -{ - if ( m_hi < ll.m_hi ) - return true; - else if ( m_hi == ll.m_hi ) - return m_lo < ll.m_lo; - else - return false; -} - -bool wxLongLongWx::operator>(const wxLongLongWx& ll) const -{ - if ( m_hi > ll.m_hi ) - return true; - else if ( m_hi == ll.m_hi ) - return m_lo > ll.m_lo; - else - return false; -} - -bool wxULongLongWx::operator>(const wxULongLongWx& ll) const -{ - if ( m_hi > ll.m_hi ) - return true; - else if ( m_hi == ll.m_hi ) - return m_lo > ll.m_lo; - else - return false; -} - -// bitwise operators - -wxLongLongWx wxLongLongWx::operator&(const wxLongLongWx& ll) const -{ - return wxLongLongWx(m_hi & ll.m_hi, m_lo & ll.m_lo); -} - -wxULongLongWx wxULongLongWx::operator&(const wxULongLongWx& ll) const -{ - return wxULongLongWx(m_hi & ll.m_hi, m_lo & ll.m_lo); -} - -wxLongLongWx wxLongLongWx::operator|(const wxLongLongWx& ll) const -{ - return wxLongLongWx(m_hi | ll.m_hi, m_lo | ll.m_lo); -} - -wxULongLongWx wxULongLongWx::operator|(const wxULongLongWx& ll) const -{ - return wxULongLongWx(m_hi | ll.m_hi, m_lo | ll.m_lo); -} - -wxLongLongWx wxLongLongWx::operator^(const wxLongLongWx& ll) const -{ - return wxLongLongWx(m_hi ^ ll.m_hi, m_lo ^ ll.m_lo); -} - -wxULongLongWx wxULongLongWx::operator^(const wxULongLongWx& ll) const -{ - return wxULongLongWx(m_hi ^ ll.m_hi, m_lo ^ ll.m_lo); -} - -wxLongLongWx& wxLongLongWx::operator&=(const wxLongLongWx& ll) -{ - m_lo &= ll.m_lo; - m_hi &= ll.m_hi; - -#ifdef wxLONGLONG_TEST_MODE - m_ll &= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator&=(const wxULongLongWx& ll) -{ - m_lo &= ll.m_lo; - m_hi &= ll.m_hi; - -#ifdef wxLONGLONG_TEST_MODE - m_ll &= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxLongLongWx& wxLongLongWx::operator|=(const wxLongLongWx& ll) -{ - m_lo |= ll.m_lo; - m_hi |= ll.m_hi; - -#ifdef wxLONGLONG_TEST_MODE - m_ll |= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator|=(const wxULongLongWx& ll) -{ - m_lo |= ll.m_lo; - m_hi |= ll.m_hi; - -#ifdef wxLONGLONG_TEST_MODE - m_ll |= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxLongLongWx& wxLongLongWx::operator^=(const wxLongLongWx& ll) -{ - m_lo ^= ll.m_lo; - m_hi ^= ll.m_hi; - -#ifdef wxLONGLONG_TEST_MODE - m_ll ^= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator^=(const wxULongLongWx& ll) -{ - m_lo ^= ll.m_lo; - m_hi ^= ll.m_hi; - -#ifdef wxLONGLONG_TEST_MODE - m_ll ^= ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxLongLongWx wxLongLongWx::operator~() const -{ - return wxLongLongWx(~m_hi, ~m_lo); -} - -wxULongLongWx wxULongLongWx::operator~() const -{ - return wxULongLongWx(~m_hi, ~m_lo); -} - -// multiplication - -wxLongLongWx wxLongLongWx::operator*(const wxLongLongWx& ll) const -{ - wxLongLongWx res(*this); - res *= ll; - - return res; -} - -wxULongLongWx wxULongLongWx::operator*(const wxULongLongWx& ll) const -{ - wxULongLongWx res(*this); - res *= ll; - - return res; -} - -wxLongLongWx& wxLongLongWx::operator*=(const wxLongLongWx& ll) -{ - wxLongLongWx t(m_hi, m_lo); - wxLongLongWx q(ll.m_hi, ll.m_lo); - - m_hi = m_lo = 0; - -#ifdef wxLONGLONG_TEST_MODE - wxLongLong_t llOld = m_ll; - m_ll = 0; -#endif // wxLONGLONG_TEST_MODE - - int counter = 0; - do - { - if ((q.m_lo & 1) != 0) - *this += t; - q >>= 1; - t <<= 1; - counter++; - } - while ((counter < 64) && ((q.m_hi != 0) || (q.m_lo != 0))); - -#ifdef wxLONGLONG_TEST_MODE - m_ll = llOld * ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator*=(const wxULongLongWx& ll) -{ - wxULongLongWx t(m_hi, m_lo); - wxULongLongWx q(ll.m_hi, ll.m_lo); - - m_hi = m_lo = 0; - -#ifdef wxLONGLONG_TEST_MODE - wxULongLong_t llOld = m_ll; - m_ll = 0; -#endif // wxLONGLONG_TEST_MODE - - int counter = 0; - do - { - if ((q.m_lo & 1) != 0) - *this += t; - q >>= 1; - t <<= 1; - counter++; - } - while ((counter < 64) && ((q.m_hi != 0) || (q.m_lo != 0))); - -#ifdef wxLONGLONG_TEST_MODE - m_ll = llOld * ll.m_ll; - - Check(); -#endif // wxLONGLONG_TEST_MODE - - return *this; -} - -// division - -#define IS_MSB_SET(ll) ((ll.GetHi()) & (1 << (8*sizeof(long) - 1))) - -void wxLongLongWx::Divide(const wxLongLongWx& divisorIn, - wxLongLongWx& quotient, - wxLongLongWx& remainderIO) const -{ - if ((divisorIn.m_lo == 0) && (divisorIn.m_hi == 0)) - { - // provoke division by zero error and silence the compilers warnings - // about an expression without effect and unused variable - long dummy = divisorIn.m_lo/divisorIn.m_hi; - dummy += 0; - } - - // VZ: I'm writing this in a hurry and it's surely not the fastest way to - // do this - any improvements are more than welcome - // - // code inspired by the snippet at - // http://www.bearcave.com/software/divide.htm - // - // Copyright notice: - // - // Use of this program, for any purpose, is granted the author, Ian - // Kaplan, as long as this copyright notice is included in the source - // code or any source code derived from this program. The user assumes - // all responsibility for using this code. - - // init everything - wxULongLongWx dividend, divisor, remainder; - - quotient = 0l; - remainder = 0l; - - // always do unsigned division and adjust the signs later: in C integer - // division, the sign of the remainder is the same as the sign of the - // dividend, while the sign of the quotient is the product of the signs of - // the dividend and divisor. Of course, we also always have - // - // dividend = quotient*divisor + remainder - // - // with 0 <= abs(remainder) < abs(divisor) - bool negRemainder = GetHi() < 0; - bool negQuotient = false; // assume positive - if ( GetHi() < 0 ) - { - negQuotient = !negQuotient; - dividend = -*this; - } else { - dividend = *this; - } - if ( divisorIn.GetHi() < 0 ) - { - negQuotient = !negQuotient; - divisor = -divisorIn; - } else { - divisor = divisorIn; - } - - // check for some particular cases - if ( divisor > dividend ) - { - remainder = dividend; - } - else if ( divisor == dividend ) - { - quotient = 1l; - } - else - { - // here: dividend > divisor and both are positive: do unsigned division - size_t nBits = 64u; - wxLongLongWx d; - - while ( remainder < divisor ) - { - remainder <<= 1; - if ( IS_MSB_SET(dividend) ) - { - remainder |= 1; - } - - d = dividend; - dividend <<= 1; - - nBits--; - } - - // undo the last loop iteration - dividend = d; - remainder >>= 1; - nBits++; - - for ( size_t i = 0; i < nBits; i++ ) - { - remainder <<= 1; - if ( IS_MSB_SET(dividend) ) - { - remainder |= 1; - } - - wxLongLongWx t = remainder - divisor; - dividend <<= 1; - quotient <<= 1; - if ( !IS_MSB_SET(t) ) - { - quotient |= 1; - - remainder = t; - } - } - } - - remainderIO = remainder; - - // adjust signs - if ( negRemainder ) - { - remainderIO = -remainderIO; - } - - if ( negQuotient ) - { - quotient = -quotient; - } -} - -void wxULongLongWx::Divide(const wxULongLongWx& divisorIn, - wxULongLongWx& quotient, - wxULongLongWx& remainder) const -{ - if ((divisorIn.m_lo == 0) && (divisorIn.m_hi == 0)) - { - // provoke division by zero error and silence the compilers warnings - // about an expression without effect and unused variable - unsigned long dummy = divisorIn.m_lo/divisorIn.m_hi; - dummy += 0; - } - - // VZ: I'm writing this in a hurry and it's surely not the fastest way to - // do this - any improvements are more than welcome - // - // code inspired by the snippet at - // http://www.bearcave.com/software/divide.htm - // - // Copyright notice: - // - // Use of this program, for any purpose, is granted the author, Ian - // Kaplan, as long as this copyright notice is included in the source - // code or any source code derived from this program. The user assumes - // all responsibility for using this code. - - // init everything - wxULongLongWx dividend = *this, - divisor = divisorIn; - - quotient = 0l; - remainder = 0l; - - // check for some particular cases - if ( divisor > dividend ) - { - remainder = dividend; - } - else if ( divisor == dividend ) - { - quotient = 1l; - } - else - { - // here: dividend > divisor - size_t nBits = 64u; - wxULongLongWx d; - - while ( remainder < divisor ) - { - remainder <<= 1; - if ( IS_MSB_SET(dividend) ) - { - remainder |= 1; - } - - d = dividend; - dividend <<= 1; - - nBits--; - } - - // undo the last loop iteration - dividend = d; - remainder >>= 1; - nBits++; - - for ( size_t i = 0; i < nBits; i++ ) - { - remainder <<= 1; - if ( IS_MSB_SET(dividend) ) - { - remainder |= 1; - } - - wxULongLongWx t = remainder - divisor; - dividend <<= 1; - quotient <<= 1; - if ( !IS_MSB_SET(t) ) - { - quotient |= 1; - - remainder = t; - } - } - } -} - -wxLongLongWx wxLongLongWx::operator/(const wxLongLongWx& ll) const -{ - wxLongLongWx quotient, remainder; - - Divide(ll, quotient, remainder); - - return quotient; -} - -wxULongLongWx wxULongLongWx::operator/(const wxULongLongWx& ll) const -{ - wxULongLongWx quotient, remainder; - - Divide(ll, quotient, remainder); - - return quotient; -} - -wxLongLongWx& wxLongLongWx::operator/=(const wxLongLongWx& ll) -{ - wxLongLongWx quotient, remainder; - - Divide(ll, quotient, remainder); - - *this = quotient; - - return *this; -} - -wxULongLongWx& wxULongLongWx::operator/=(const wxULongLongWx& ll) -{ - wxULongLongWx quotient, remainder; - - Divide(ll, quotient, remainder); - - *this = quotient; - - return *this; -} - -wxLongLongWx wxLongLongWx::operator%(const wxLongLongWx& ll) const -{ - wxLongLongWx quotient, remainder; - - Divide(ll, quotient, remainder); - - return remainder; -} - -wxULongLongWx wxULongLongWx::operator%(const wxULongLongWx& ll) const -{ - wxULongLongWx quotient, remainder; - - Divide(ll, quotient, remainder); - - return remainder; -} - -// ---------------------------------------------------------------------------- -// misc -// ---------------------------------------------------------------------------- - -// temporary - just for testing -void *wxLongLongWx::asArray(void) const -{ - static unsigned char temp[8]; - - temp[0] = (char)((m_hi >> 24) & 0xFF); - temp[1] = (char)((m_hi >> 16) & 0xFF); - temp[2] = (char)((m_hi >> 8) & 0xFF); - temp[3] = (char)((m_hi >> 0) & 0xFF); - temp[4] = (char)((m_lo >> 24) & 0xFF); - temp[5] = (char)((m_lo >> 16) & 0xFF); - temp[6] = (char)((m_lo >> 8) & 0xFF); - temp[7] = (char)((m_lo >> 0) & 0xFF); - - return temp; -} - -void *wxULongLongWx::asArray(void) const -{ - static unsigned char temp[8]; - - temp[0] = (char)((m_hi >> 24) & 0xFF); - temp[1] = (char)((m_hi >> 16) & 0xFF); - temp[2] = (char)((m_hi >> 8) & 0xFF); - temp[3] = (char)((m_hi >> 0) & 0xFF); - temp[4] = (char)((m_lo >> 24) & 0xFF); - temp[5] = (char)((m_lo >> 16) & 0xFF); - temp[6] = (char)((m_lo >> 8) & 0xFF); - temp[7] = (char)((m_lo >> 0) & 0xFF); - - return temp; -} - -#endif // wxUSE_LONGLONG_WX - -#define LL_TO_STRING(name) \ - wxString name::ToString() const \ - { \ - /* TODO: this is awfully inefficient, anything better? */ \ - wxString result; \ - \ - name ll = *this; \ - \ - bool neg = ll < 0; \ - if ( neg ) \ - { \ - while ( ll != 0 ) \ - { \ - long digit = (ll % 10).ToLong(); \ - result.Prepend((wxChar)(_T('0') - digit)); \ - ll /= 10; \ - } \ - } \ - else \ - { \ - while ( ll != 0 ) \ - { \ - long digit = (ll % 10).ToLong(); \ - result.Prepend((wxChar)(_T('0') + digit)); \ - ll /= 10; \ - } \ - } \ - \ - if ( result.empty() ) \ - result = _T('0'); \ - else if ( neg ) \ - result.Prepend(_T('-')); \ - \ - return result; \ - } - -#define ULL_TO_STRING(name) \ - wxString name::ToString() const \ - { \ - /* TODO: this is awfully inefficient, anything better? */ \ - wxString result; \ - \ - name ll = *this; \ - \ - while ( ll != 0 ) \ - { \ - result.Prepend((wxChar)(_T('0') + (ll % 10).ToULong())); \ - ll /= 10; \ - } \ - \ - if ( result.empty() ) \ - result = _T('0'); \ - \ - return result; \ - } - -#if wxUSE_LONGLONG_NATIVE - LL_TO_STRING(wxLongLongNative) - ULL_TO_STRING(wxULongLongNative) -#endif - -#if wxUSE_LONGLONG_WX - LL_TO_STRING(wxLongLongWx) - ULL_TO_STRING(wxULongLongWx) -#endif - -#if wxUSE_STD_IOSTREAM - -// input/output -WXDLLIMPEXP_BASE -wxSTD ostream& operator<< (wxSTD ostream& o, const wxLongLong& ll) -{ - return o << ll.ToString(); -} - -WXDLLIMPEXP_BASE -wxSTD ostream& operator<< (wxSTD ostream& o, const wxULongLong& ll) -{ - return o << ll.ToString(); -} - -#endif // wxUSE_STD_IOSTREAM - -WXDLLIMPEXP_BASE wxString& operator<< (wxString& s, const wxLongLong& ll) -{ - return s << ll.ToString(); -} - -WXDLLIMPEXP_BASE wxString& operator<< (wxString& s, const wxULongLong& ll) -{ - return s << ll.ToString(); -} - -#if wxUSE_STREAMS - -WXDLLIMPEXP_BASE wxTextOutputStream& operator<< (wxTextOutputStream& o, const wxULongLong& ll) -{ - return o << ll.ToString(); -} - -WXDLLIMPEXP_BASE wxTextOutputStream& operator<< (wxTextOutputStream& o, const wxLongLong& ll) -{ - return o << ll.ToString(); -} - -#define READ_STRING_CHAR(s, idx, len) ((wxChar) ((idx!=len) ? s[idx++] : 0)) - -WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxULongLong &ll) -{ - wxString s = o.ReadWord(); - - ll = wxULongLong(0l, 0l); - size_t length = s.length(); - size_t idx = 0; - - wxChar ch = READ_STRING_CHAR(s, idx, length); - - // Skip WS - while (ch==wxT(' ') || ch==wxT('\t')) - ch = READ_STRING_CHAR(s, idx, length); - - // Read number - wxULongLong multiplier(0l, 10l); - while (ch>=wxT('0') && ch<=wxT('9')) { - long lValue = (unsigned) (ch - wxT('0')); - ll = ll * multiplier + wxULongLong(0l, lValue); - ch = READ_STRING_CHAR(s, idx, length); - } - - return o; -} - -WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxLongLong &ll) -{ - wxString s = o.ReadWord(); - - ll = wxLongLong(0l, 0l); - size_t length = s.length(); - size_t idx = 0; - - wxChar ch = READ_STRING_CHAR(s, idx, length); - - // Skip WS - while (ch==wxT(' ') || ch==wxT('\t')) - ch = READ_STRING_CHAR(s, idx, length); - - // Ask for sign - int iSign = 1; - if (ch==wxT('-') || ch==wxT('+')) { - iSign = ((ch==wxT('-')) ? -1 : 1); - ch = READ_STRING_CHAR(s, idx, length); - } - - // Read number - wxLongLong multiplier(0l, 10l); - while (ch>=wxT('0') && ch<=wxT('9')) { - long lValue = (unsigned) (ch - wxT('0')); - ll = ll * multiplier + wxLongLong(0l, lValue); - ch = READ_STRING_CHAR(s, idx, length); - } - -#if wxUSE_LONGLONG_NATIVE - ll = ll * wxLongLong((wxLongLong_t) iSign); -#else - ll = ll * wxLongLong((long) iSign); -#endif - - return o; -} - -#if wxUSE_LONGLONG_NATIVE - -WXDLLIMPEXP_BASE class wxTextOutputStream &operator<<(class wxTextOutputStream &o, wxULongLong_t value) -{ - return o << wxULongLong(value).ToString(); -} - -WXDLLIMPEXP_BASE class wxTextOutputStream &operator<<(class wxTextOutputStream &o, wxLongLong_t value) -{ - return o << wxLongLong(value).ToString(); -} - -WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxULongLong_t &value) -{ - wxULongLong ll; - o >> ll; - value = ll.GetValue(); - return o; -} - -WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxLongLong_t &value) -{ - wxLongLong ll; - o >> ll; - value = ll.GetValue(); - return o; -} - -#endif // wxUSE_LONGLONG_NATIVE - -#endif // wxUSE_STREAMS - -#endif // wxUSE_LONGLONG +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/longlong.cpp +// Purpose: implementation of wxLongLongNative +// Author: Jeffrey C. Ollie , Vadim Zeitlin +// Remarks: this class is not public in wxWidgets 2.0! It is intentionally +// not documented and is for private use only. +// Modified by: +// Created: 10.02.99 +// RCS-ID: $Id: longlong.cpp 40750 2006-08-22 19:04:45Z MW $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// headers +// ============================================================================ + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_LONGLONG + +#include "wx/longlong.h" + +#ifndef WX_PRECOMP + #include "wx/math.h" // for fabs() +#endif + +#if wxUSE_STREAMS + #include "wx/txtstrm.h" +#endif + +#include // for memset() + +#include "wx/ioswrap.h" + +// ============================================================================ +// implementation +// ============================================================================ + +#if wxUSE_LONGLONG_NATIVE + +// ---------------------------------------------------------------------------- +// misc +// ---------------------------------------------------------------------------- + +void *wxLongLongNative::asArray() const +{ + static unsigned char temp[8]; + + temp[0] = wx_truncate_cast(unsigned char, ((m_ll >> 56) & 0xFF)); + temp[1] = wx_truncate_cast(unsigned char, ((m_ll >> 48) & 0xFF)); + temp[2] = wx_truncate_cast(unsigned char, ((m_ll >> 40) & 0xFF)); + temp[3] = wx_truncate_cast(unsigned char, ((m_ll >> 32) & 0xFF)); + temp[4] = wx_truncate_cast(unsigned char, ((m_ll >> 24) & 0xFF)); + temp[5] = wx_truncate_cast(unsigned char, ((m_ll >> 16) & 0xFF)); + temp[6] = wx_truncate_cast(unsigned char, ((m_ll >> 8) & 0xFF)); + temp[7] = wx_truncate_cast(unsigned char, ((m_ll >> 0) & 0xFF)); + + return temp; +} + +void *wxULongLongNative::asArray() const +{ + static unsigned char temp[8]; + + temp[0] = wx_truncate_cast(unsigned char, ((m_ll >> 56) & 0xFF)); + temp[1] = wx_truncate_cast(unsigned char, ((m_ll >> 48) & 0xFF)); + temp[2] = wx_truncate_cast(unsigned char, ((m_ll >> 40) & 0xFF)); + temp[3] = wx_truncate_cast(unsigned char, ((m_ll >> 32) & 0xFF)); + temp[4] = wx_truncate_cast(unsigned char, ((m_ll >> 24) & 0xFF)); + temp[5] = wx_truncate_cast(unsigned char, ((m_ll >> 16) & 0xFF)); + temp[6] = wx_truncate_cast(unsigned char, ((m_ll >> 8) & 0xFF)); + temp[7] = wx_truncate_cast(unsigned char, ((m_ll >> 0) & 0xFF)); + + return temp; +} + +#if wxUSE_LONGLONG_WX +wxLongLongNative::wxLongLongNative(wxLongLongWx ll) +{ + // assign first to avoid precision loss! + m_ll = ll.GetHi(); + m_ll <<= 32; + m_ll |= ll.GetLo(); +} + +wxLongLongNative& wxLongLongNative::operator=(wxLongLongWx ll) +{ + // assign first to avoid precision loss! + m_ll = ll.GetHi(); + m_ll <<= 32; + m_ll |= ll.GetLo(); + return *this; +} + +wxLongLongNative& wxLongLongNative::operator=(const class wxULongLongWx &ll) +{ + // assign first to avoid precision loss! + m_ll = ll.GetHi(); + m_ll <<= 32; + m_ll |= ll.GetLo(); + return *this; +} + +wxULongLongNative::wxULongLongNative(const class wxULongLongWx &ll) +{ + // assign first to avoid precision loss! + m_ll = ll.GetHi(); + m_ll <<= 32; + m_ll |= ((unsigned long) ll.GetLo()); +} + +wxULongLongNative& wxULongLongNative::operator=(wxLongLongWx ll) +{ + // assign first to avoid precision loss! + m_ll = ll.GetHi(); + m_ll <<= 32; + m_ll |= ((unsigned long) ll.GetLo()); + return *this; +} + +wxULongLongNative& wxULongLongNative::operator=(const class wxULongLongWx &ll) +{ + // assign first to avoid precision loss! + m_ll = ll.GetHi(); + m_ll <<= 32; + m_ll |= ((unsigned long) ll.GetLo()); + return *this; +} +#endif + +#endif // wxUSE_LONGLONG_NATIVE + +// ============================================================================ +// wxLongLongWx: emulation of 'long long' using 2 longs +// ============================================================================ + +#if wxUSE_LONGLONG_WX + +// Set value from unsigned wxULongLongWx +wxLongLongWx &wxLongLongWx::operator=(const class wxULongLongWx &ll) +{ + m_hi = (unsigned long) ll.GetHi(); + m_lo = ll.GetLo(); + return *this; +} + +// assignment +wxLongLongWx& wxLongLongWx::Assign(double d) +{ + bool positive = d >= 0; + d = fabs(d); + if ( d <= ULONG_MAX ) + { + m_hi = 0; + m_lo = (long)d; + } + else + { + m_hi = (unsigned long)(d / (1.0 + (double)ULONG_MAX)); + m_lo = (unsigned long)(d - ((double)m_hi * (1.0 + (double)ULONG_MAX))); + } + +#ifdef wxLONGLONG_TEST_MODE + m_ll = (wxLongLong_t)d; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + if ( !positive ) + Negate(); + + return *this; +} + +double wxLongLongWx::ToDouble() const +{ + double d = m_hi; + d *= 1.0 + (double)ULONG_MAX; + d += m_lo; + +#ifdef wxLONGLONG_TEST_MODE + wxASSERT( d == m_ll ); +#endif // wxLONGLONG_TEST_MODE + + return d; +} + +double wxULongLongWx::ToDouble() const +{ + unsigned double d = m_hi; + d *= 1.0 + (double)ULONG_MAX; + d += m_lo; + +#ifdef wxLONGLONG_TEST_MODE + wxASSERT( d == m_ll ); +#endif // wxLONGLONG_TEST_MODE + + return d; +} + +wxLongLongWx wxLongLongWx::operator<<(int shift) const +{ + wxLongLongWx ll(*this); + ll <<= shift; + + return ll; +} + +wxULongLongWx wxULongLongWx::operator<<(int shift) const +{ + wxULongLongWx ll(*this); + ll <<= shift; + + return ll; +} + +wxLongLongWx& wxLongLongWx::operator<<=(int shift) +{ + if (shift != 0) + { + if (shift < 32) + { + m_hi <<= shift; + m_hi |= m_lo >> (32 - shift); + m_lo <<= shift; + } + else + { + m_hi = m_lo << (shift - 32); + m_lo = 0; + } + } + +#ifdef wxLONGLONG_TEST_MODE + m_ll <<= shift; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator<<=(int shift) +{ + if (shift != 0) + { + if (shift < 32) + { + m_hi <<= shift; + m_hi |= m_lo >> (32 - shift); + m_lo <<= shift; + } + else + { + m_hi = m_lo << (shift - 32); + m_lo = 0; + } + } + +#ifdef wxLONGLONG_TEST_MODE + m_ll <<= shift; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxLongLongWx wxLongLongWx::operator>>(int shift) const +{ + wxLongLongWx ll(*this); + ll >>= shift; + + return ll; +} + +wxULongLongWx wxULongLongWx::operator>>(int shift) const +{ + wxULongLongWx ll(*this); + ll >>= shift; + + return ll; +} + +wxLongLongWx& wxLongLongWx::operator>>=(int shift) +{ + if (shift != 0) + { + if (shift < 32) + { + m_lo >>= shift; + m_lo |= m_hi << (32 - shift); + m_hi >>= shift; + } + else + { + m_lo = m_hi >> (shift - 32); + m_hi = (m_hi < 0 ? -1L : 0); + } + } + +#ifdef wxLONGLONG_TEST_MODE + m_ll >>= shift; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator>>=(int shift) +{ + if (shift != 0) + { + if (shift < 32) + { + m_lo >>= shift; + m_lo |= m_hi << (32 - shift); + m_hi >>= shift; + } + else + { + m_lo = m_hi >> (shift - 32); + m_hi = 0; + } + } + +#ifdef wxLONGLONG_TEST_MODE + m_ll >>= shift; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxLongLongWx wxLongLongWx::operator+(const wxLongLongWx& ll) const +{ + wxLongLongWx res(*this); + res += ll; + + return res; +} + +wxULongLongWx wxULongLongWx::operator+(const wxULongLongWx& ll) const +{ + wxULongLongWx res(*this); + res += ll; + + return res; +} + +wxLongLongWx wxLongLongWx::operator+(long l) const +{ + wxLongLongWx res(*this); + res += l; + + return res; +} + +wxULongLongWx wxULongLongWx::operator+(unsigned long l) const +{ + wxULongLongWx res(*this); + res += l; + + return res; +} + +wxLongLongWx& wxLongLongWx::operator+=(const wxLongLongWx& ll) +{ + unsigned long previous = m_lo; + + m_lo += ll.m_lo; + m_hi += ll.m_hi; + + if ((m_lo < previous) || (m_lo < ll.m_lo)) + m_hi++; + +#ifdef wxLONGLONG_TEST_MODE + m_ll += ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator+=(const wxULongLongWx& ll) +{ + unsigned long previous = m_lo; + + m_lo += ll.m_lo; + m_hi += ll.m_hi; + + if ((m_lo < previous) || (m_lo < ll.m_lo)) + m_hi++; + +#ifdef wxLONGLONG_TEST_MODE + m_ll += ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxLongLongWx& wxLongLongWx::operator+=(long l) +{ + unsigned long previous = m_lo; + + m_lo += l; + if (l < 0) + m_hi += -1l; + + if ((m_lo < previous) || (m_lo < (unsigned long)l)) + m_hi++; + +#ifdef wxLONGLONG_TEST_MODE + m_ll += l; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator+=(unsigned long l) +{ + unsigned long previous = m_lo; + + m_lo += l; + + if ((m_lo < previous) || (m_lo < l)) + m_hi++; + +#ifdef wxLONGLONG_TEST_MODE + m_ll += l; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +// pre increment +wxLongLongWx& wxLongLongWx::operator++() +{ + m_lo++; + if (m_lo == 0) + m_hi++; + +#ifdef wxLONGLONG_TEST_MODE + m_ll++; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator++() +{ + m_lo++; + if (m_lo == 0) + m_hi++; + +#ifdef wxLONGLONG_TEST_MODE + m_ll++; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +// negation +wxLongLongWx wxLongLongWx::operator-() const +{ + wxLongLongWx res(*this); + res.Negate(); + + return res; +} + +wxLongLongWx& wxLongLongWx::Negate() +{ + m_hi = ~m_hi; + m_lo = ~m_lo; + + m_lo++; + if ( m_lo == 0 ) + m_hi++; + +#ifdef wxLONGLONG_TEST_MODE + m_ll = -m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +// subtraction + +wxLongLongWx wxLongLongWx::operator-(const wxLongLongWx& ll) const +{ + wxLongLongWx res(*this); + res -= ll; + + return res; +} + +wxLongLongWx wxULongLongWx::operator-(const wxULongLongWx& ll) const +{ + wxASSERT(m_hi <= LONG_MAX ); + wxASSERT(ll.m_hi <= LONG_MAX ); + + wxLongLongWx res( (long)m_hi , m_lo ); + wxLongLongWx op( (long)ll.m_hi , ll.m_lo ); + res -= op; + + return res; +} + +wxLongLongWx& wxLongLongWx::operator-=(const wxLongLongWx& ll) +{ + unsigned long previous = m_lo; + + m_lo -= ll.m_lo; + m_hi -= ll.m_hi; + + if (previous < ll.m_lo) + m_hi--; + +#ifdef wxLONGLONG_TEST_MODE + m_ll -= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator-=(const wxULongLongWx& ll) +{ + unsigned long previous = m_lo; + + m_lo -= ll.m_lo; + m_hi -= ll.m_hi; + + if (previous < ll.m_lo) + m_hi--; + +#ifdef wxLONGLONG_TEST_MODE + m_ll -= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +// pre decrement +wxLongLongWx& wxLongLongWx::operator--() +{ + m_lo--; + if (m_lo == 0xFFFFFFFF) + m_hi--; + +#ifdef wxLONGLONG_TEST_MODE + m_ll--; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator--() +{ + m_lo--; + if (m_lo == 0xFFFFFFFF) + m_hi--; + +#ifdef wxLONGLONG_TEST_MODE + m_ll--; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +// comparison operators + +bool wxLongLongWx::operator<(const wxLongLongWx& ll) const +{ + if ( m_hi < ll.m_hi ) + return true; + else if ( m_hi == ll.m_hi ) + return m_lo < ll.m_lo; + else + return false; +} + +bool wxULongLongWx::operator<(const wxULongLongWx& ll) const +{ + if ( m_hi < ll.m_hi ) + return true; + else if ( m_hi == ll.m_hi ) + return m_lo < ll.m_lo; + else + return false; +} + +bool wxLongLongWx::operator>(const wxLongLongWx& ll) const +{ + if ( m_hi > ll.m_hi ) + return true; + else if ( m_hi == ll.m_hi ) + return m_lo > ll.m_lo; + else + return false; +} + +bool wxULongLongWx::operator>(const wxULongLongWx& ll) const +{ + if ( m_hi > ll.m_hi ) + return true; + else if ( m_hi == ll.m_hi ) + return m_lo > ll.m_lo; + else + return false; +} + +// bitwise operators + +wxLongLongWx wxLongLongWx::operator&(const wxLongLongWx& ll) const +{ + return wxLongLongWx(m_hi & ll.m_hi, m_lo & ll.m_lo); +} + +wxULongLongWx wxULongLongWx::operator&(const wxULongLongWx& ll) const +{ + return wxULongLongWx(m_hi & ll.m_hi, m_lo & ll.m_lo); +} + +wxLongLongWx wxLongLongWx::operator|(const wxLongLongWx& ll) const +{ + return wxLongLongWx(m_hi | ll.m_hi, m_lo | ll.m_lo); +} + +wxULongLongWx wxULongLongWx::operator|(const wxULongLongWx& ll) const +{ + return wxULongLongWx(m_hi | ll.m_hi, m_lo | ll.m_lo); +} + +wxLongLongWx wxLongLongWx::operator^(const wxLongLongWx& ll) const +{ + return wxLongLongWx(m_hi ^ ll.m_hi, m_lo ^ ll.m_lo); +} + +wxULongLongWx wxULongLongWx::operator^(const wxULongLongWx& ll) const +{ + return wxULongLongWx(m_hi ^ ll.m_hi, m_lo ^ ll.m_lo); +} + +wxLongLongWx& wxLongLongWx::operator&=(const wxLongLongWx& ll) +{ + m_lo &= ll.m_lo; + m_hi &= ll.m_hi; + +#ifdef wxLONGLONG_TEST_MODE + m_ll &= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator&=(const wxULongLongWx& ll) +{ + m_lo &= ll.m_lo; + m_hi &= ll.m_hi; + +#ifdef wxLONGLONG_TEST_MODE + m_ll &= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxLongLongWx& wxLongLongWx::operator|=(const wxLongLongWx& ll) +{ + m_lo |= ll.m_lo; + m_hi |= ll.m_hi; + +#ifdef wxLONGLONG_TEST_MODE + m_ll |= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator|=(const wxULongLongWx& ll) +{ + m_lo |= ll.m_lo; + m_hi |= ll.m_hi; + +#ifdef wxLONGLONG_TEST_MODE + m_ll |= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxLongLongWx& wxLongLongWx::operator^=(const wxLongLongWx& ll) +{ + m_lo ^= ll.m_lo; + m_hi ^= ll.m_hi; + +#ifdef wxLONGLONG_TEST_MODE + m_ll ^= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator^=(const wxULongLongWx& ll) +{ + m_lo ^= ll.m_lo; + m_hi ^= ll.m_hi; + +#ifdef wxLONGLONG_TEST_MODE + m_ll ^= ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxLongLongWx wxLongLongWx::operator~() const +{ + return wxLongLongWx(~m_hi, ~m_lo); +} + +wxULongLongWx wxULongLongWx::operator~() const +{ + return wxULongLongWx(~m_hi, ~m_lo); +} + +// multiplication + +wxLongLongWx wxLongLongWx::operator*(const wxLongLongWx& ll) const +{ + wxLongLongWx res(*this); + res *= ll; + + return res; +} + +wxULongLongWx wxULongLongWx::operator*(const wxULongLongWx& ll) const +{ + wxULongLongWx res(*this); + res *= ll; + + return res; +} + +wxLongLongWx& wxLongLongWx::operator*=(const wxLongLongWx& ll) +{ + wxLongLongWx t(m_hi, m_lo); + wxLongLongWx q(ll.m_hi, ll.m_lo); + + m_hi = m_lo = 0; + +#ifdef wxLONGLONG_TEST_MODE + wxLongLong_t llOld = m_ll; + m_ll = 0; +#endif // wxLONGLONG_TEST_MODE + + int counter = 0; + do + { + if ((q.m_lo & 1) != 0) + *this += t; + q >>= 1; + t <<= 1; + counter++; + } + while ((counter < 64) && ((q.m_hi != 0) || (q.m_lo != 0))); + +#ifdef wxLONGLONG_TEST_MODE + m_ll = llOld * ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator*=(const wxULongLongWx& ll) +{ + wxULongLongWx t(m_hi, m_lo); + wxULongLongWx q(ll.m_hi, ll.m_lo); + + m_hi = m_lo = 0; + +#ifdef wxLONGLONG_TEST_MODE + wxULongLong_t llOld = m_ll; + m_ll = 0; +#endif // wxLONGLONG_TEST_MODE + + int counter = 0; + do + { + if ((q.m_lo & 1) != 0) + *this += t; + q >>= 1; + t <<= 1; + counter++; + } + while ((counter < 64) && ((q.m_hi != 0) || (q.m_lo != 0))); + +#ifdef wxLONGLONG_TEST_MODE + m_ll = llOld * ll.m_ll; + + Check(); +#endif // wxLONGLONG_TEST_MODE + + return *this; +} + +// division + +#define IS_MSB_SET(ll) ((ll.GetHi()) & (1 << (8*sizeof(long) - 1))) + +void wxLongLongWx::Divide(const wxLongLongWx& divisorIn, + wxLongLongWx& quotient, + wxLongLongWx& remainderIO) const +{ + if ((divisorIn.m_lo == 0) && (divisorIn.m_hi == 0)) + { + // provoke division by zero error and silence the compilers warnings + // about an expression without effect and unused variable + long dummy = divisorIn.m_lo/divisorIn.m_hi; + dummy += 0; + } + + // VZ: I'm writing this in a hurry and it's surely not the fastest way to + // do this - any improvements are more than welcome + // + // code inspired by the snippet at + // http://www.bearcave.com/software/divide.htm + // + // Copyright notice: + // + // Use of this program, for any purpose, is granted the author, Ian + // Kaplan, as long as this copyright notice is included in the source + // code or any source code derived from this program. The user assumes + // all responsibility for using this code. + + // init everything + wxULongLongWx dividend, divisor, remainder; + + quotient = 0l; + remainder = 0l; + + // always do unsigned division and adjust the signs later: in C integer + // division, the sign of the remainder is the same as the sign of the + // dividend, while the sign of the quotient is the product of the signs of + // the dividend and divisor. Of course, we also always have + // + // dividend = quotient*divisor + remainder + // + // with 0 <= abs(remainder) < abs(divisor) + bool negRemainder = GetHi() < 0; + bool negQuotient = false; // assume positive + if ( GetHi() < 0 ) + { + negQuotient = !negQuotient; + dividend = -*this; + } else { + dividend = *this; + } + if ( divisorIn.GetHi() < 0 ) + { + negQuotient = !negQuotient; + divisor = -divisorIn; + } else { + divisor = divisorIn; + } + + // check for some particular cases + if ( divisor > dividend ) + { + remainder = dividend; + } + else if ( divisor == dividend ) + { + quotient = 1l; + } + else + { + // here: dividend > divisor and both are positive: do unsigned division + size_t nBits = 64u; + wxLongLongWx d; + + while ( remainder < divisor ) + { + remainder <<= 1; + if ( IS_MSB_SET(dividend) ) + { + remainder |= 1; + } + + d = dividend; + dividend <<= 1; + + nBits--; + } + + // undo the last loop iteration + dividend = d; + remainder >>= 1; + nBits++; + + for ( size_t i = 0; i < nBits; i++ ) + { + remainder <<= 1; + if ( IS_MSB_SET(dividend) ) + { + remainder |= 1; + } + + wxLongLongWx t = remainder - divisor; + dividend <<= 1; + quotient <<= 1; + if ( !IS_MSB_SET(t) ) + { + quotient |= 1; + + remainder = t; + } + } + } + + remainderIO = remainder; + + // adjust signs + if ( negRemainder ) + { + remainderIO = -remainderIO; + } + + if ( negQuotient ) + { + quotient = -quotient; + } +} + +void wxULongLongWx::Divide(const wxULongLongWx& divisorIn, + wxULongLongWx& quotient, + wxULongLongWx& remainder) const +{ + if ((divisorIn.m_lo == 0) && (divisorIn.m_hi == 0)) + { + // provoke division by zero error and silence the compilers warnings + // about an expression without effect and unused variable + unsigned long dummy = divisorIn.m_lo/divisorIn.m_hi; + dummy += 0; + } + + // VZ: I'm writing this in a hurry and it's surely not the fastest way to + // do this - any improvements are more than welcome + // + // code inspired by the snippet at + // http://www.bearcave.com/software/divide.htm + // + // Copyright notice: + // + // Use of this program, for any purpose, is granted the author, Ian + // Kaplan, as long as this copyright notice is included in the source + // code or any source code derived from this program. The user assumes + // all responsibility for using this code. + + // init everything + wxULongLongWx dividend = *this, + divisor = divisorIn; + + quotient = 0l; + remainder = 0l; + + // check for some particular cases + if ( divisor > dividend ) + { + remainder = dividend; + } + else if ( divisor == dividend ) + { + quotient = 1l; + } + else + { + // here: dividend > divisor + size_t nBits = 64u; + wxULongLongWx d; + + while ( remainder < divisor ) + { + remainder <<= 1; + if ( IS_MSB_SET(dividend) ) + { + remainder |= 1; + } + + d = dividend; + dividend <<= 1; + + nBits--; + } + + // undo the last loop iteration + dividend = d; + remainder >>= 1; + nBits++; + + for ( size_t i = 0; i < nBits; i++ ) + { + remainder <<= 1; + if ( IS_MSB_SET(dividend) ) + { + remainder |= 1; + } + + wxULongLongWx t = remainder - divisor; + dividend <<= 1; + quotient <<= 1; + if ( !IS_MSB_SET(t) ) + { + quotient |= 1; + + remainder = t; + } + } + } +} + +wxLongLongWx wxLongLongWx::operator/(const wxLongLongWx& ll) const +{ + wxLongLongWx quotient, remainder; + + Divide(ll, quotient, remainder); + + return quotient; +} + +wxULongLongWx wxULongLongWx::operator/(const wxULongLongWx& ll) const +{ + wxULongLongWx quotient, remainder; + + Divide(ll, quotient, remainder); + + return quotient; +} + +wxLongLongWx& wxLongLongWx::operator/=(const wxLongLongWx& ll) +{ + wxLongLongWx quotient, remainder; + + Divide(ll, quotient, remainder); + + *this = quotient; + + return *this; +} + +wxULongLongWx& wxULongLongWx::operator/=(const wxULongLongWx& ll) +{ + wxULongLongWx quotient, remainder; + + Divide(ll, quotient, remainder); + + *this = quotient; + + return *this; +} + +wxLongLongWx wxLongLongWx::operator%(const wxLongLongWx& ll) const +{ + wxLongLongWx quotient, remainder; + + Divide(ll, quotient, remainder); + + return remainder; +} + +wxULongLongWx wxULongLongWx::operator%(const wxULongLongWx& ll) const +{ + wxULongLongWx quotient, remainder; + + Divide(ll, quotient, remainder); + + return remainder; +} + +// ---------------------------------------------------------------------------- +// misc +// ---------------------------------------------------------------------------- + +// temporary - just for testing +void *wxLongLongWx::asArray(void) const +{ + static unsigned char temp[8]; + + temp[0] = (char)((m_hi >> 24) & 0xFF); + temp[1] = (char)((m_hi >> 16) & 0xFF); + temp[2] = (char)((m_hi >> 8) & 0xFF); + temp[3] = (char)((m_hi >> 0) & 0xFF); + temp[4] = (char)((m_lo >> 24) & 0xFF); + temp[5] = (char)((m_lo >> 16) & 0xFF); + temp[6] = (char)((m_lo >> 8) & 0xFF); + temp[7] = (char)((m_lo >> 0) & 0xFF); + + return temp; +} + +void *wxULongLongWx::asArray(void) const +{ + static unsigned char temp[8]; + + temp[0] = (char)((m_hi >> 24) & 0xFF); + temp[1] = (char)((m_hi >> 16) & 0xFF); + temp[2] = (char)((m_hi >> 8) & 0xFF); + temp[3] = (char)((m_hi >> 0) & 0xFF); + temp[4] = (char)((m_lo >> 24) & 0xFF); + temp[5] = (char)((m_lo >> 16) & 0xFF); + temp[6] = (char)((m_lo >> 8) & 0xFF); + temp[7] = (char)((m_lo >> 0) & 0xFF); + + return temp; +} + +#endif // wxUSE_LONGLONG_WX + +#define LL_TO_STRING(name) \ + wxString name::ToString() const \ + { \ + /* TODO: this is awfully inefficient, anything better? */ \ + wxString result; \ + \ + name ll = *this; \ + \ + bool neg = ll < 0; \ + if ( neg ) \ + { \ + while ( ll != 0 ) \ + { \ + long digit = (ll % 10).ToLong(); \ + result.Prepend((wxChar)(_T('0') - digit)); \ + ll /= 10; \ + } \ + } \ + else \ + { \ + while ( ll != 0 ) \ + { \ + long digit = (ll % 10).ToLong(); \ + result.Prepend((wxChar)(_T('0') + digit)); \ + ll /= 10; \ + } \ + } \ + \ + if ( result.empty() ) \ + result = _T('0'); \ + else if ( neg ) \ + result.Prepend(_T('-')); \ + \ + return result; \ + } + +#define ULL_TO_STRING(name) \ + wxString name::ToString() const \ + { \ + /* TODO: this is awfully inefficient, anything better? */ \ + wxString result; \ + \ + name ll = *this; \ + \ + while ( ll != 0 ) \ + { \ + result.Prepend((wxChar)(_T('0') + (ll % 10).ToULong())); \ + ll /= 10; \ + } \ + \ + if ( result.empty() ) \ + result = _T('0'); \ + \ + return result; \ + } + +#if wxUSE_LONGLONG_NATIVE + LL_TO_STRING(wxLongLongNative) + ULL_TO_STRING(wxULongLongNative) +#endif + +#if wxUSE_LONGLONG_WX + LL_TO_STRING(wxLongLongWx) + ULL_TO_STRING(wxULongLongWx) +#endif + +#if wxUSE_STD_IOSTREAM + +// input/output +WXDLLIMPEXP_BASE +wxSTD ostream& operator<< (wxSTD ostream& o, const wxLongLong& ll) +{ + return o << ll.ToString(); +} + +WXDLLIMPEXP_BASE +wxSTD ostream& operator<< (wxSTD ostream& o, const wxULongLong& ll) +{ + return o << ll.ToString(); +} + +#endif // wxUSE_STD_IOSTREAM + +WXDLLIMPEXP_BASE wxString& operator<< (wxString& s, const wxLongLong& ll) +{ + return s << ll.ToString(); +} + +WXDLLIMPEXP_BASE wxString& operator<< (wxString& s, const wxULongLong& ll) +{ + return s << ll.ToString(); +} + +#if wxUSE_STREAMS + +WXDLLIMPEXP_BASE wxTextOutputStream& operator<< (wxTextOutputStream& o, const wxULongLong& ll) +{ + return o << ll.ToString(); +} + +WXDLLIMPEXP_BASE wxTextOutputStream& operator<< (wxTextOutputStream& o, const wxLongLong& ll) +{ + return o << ll.ToString(); +} + +#define READ_STRING_CHAR(s, idx, len) ((wxChar) ((idx!=len) ? s[idx++] : 0)) + +WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxULongLong &ll) +{ + wxString s = o.ReadWord(); + + ll = wxULongLong(0l, 0l); + size_t length = s.length(); + size_t idx = 0; + + wxChar ch = READ_STRING_CHAR(s, idx, length); + + // Skip WS + while (ch==wxT(' ') || ch==wxT('\t')) + ch = READ_STRING_CHAR(s, idx, length); + + // Read number + wxULongLong multiplier(0l, 10l); + while (ch>=wxT('0') && ch<=wxT('9')) { + long lValue = (unsigned) (ch - wxT('0')); + ll = ll * multiplier + wxULongLong(0l, lValue); + ch = READ_STRING_CHAR(s, idx, length); + } + + return o; +} + +WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxLongLong &ll) +{ + wxString s = o.ReadWord(); + + ll = wxLongLong(0l, 0l); + size_t length = s.length(); + size_t idx = 0; + + wxChar ch = READ_STRING_CHAR(s, idx, length); + + // Skip WS + while (ch==wxT(' ') || ch==wxT('\t')) + ch = READ_STRING_CHAR(s, idx, length); + + // Ask for sign + int iSign = 1; + if (ch==wxT('-') || ch==wxT('+')) { + iSign = ((ch==wxT('-')) ? -1 : 1); + ch = READ_STRING_CHAR(s, idx, length); + } + + // Read number + wxLongLong multiplier(0l, 10l); + while (ch>=wxT('0') && ch<=wxT('9')) { + long lValue = (unsigned) (ch - wxT('0')); + ll = ll * multiplier + wxLongLong(0l, lValue); + ch = READ_STRING_CHAR(s, idx, length); + } + +#if wxUSE_LONGLONG_NATIVE + ll = ll * wxLongLong((wxLongLong_t) iSign); +#else + ll = ll * wxLongLong((long) iSign); +#endif + + return o; +} + +#if wxUSE_LONGLONG_NATIVE + +WXDLLIMPEXP_BASE class wxTextOutputStream &operator<<(class wxTextOutputStream &o, wxULongLong_t value) +{ + return o << wxULongLong(value).ToString(); +} + +WXDLLIMPEXP_BASE class wxTextOutputStream &operator<<(class wxTextOutputStream &o, wxLongLong_t value) +{ + return o << wxLongLong(value).ToString(); +} + +WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxULongLong_t &value) +{ + wxULongLong ll; + o >> ll; + value = ll.GetValue(); + return o; +} + +WXDLLIMPEXP_BASE class wxTextInputStream &operator>>(class wxTextInputStream &o, wxLongLong_t &value) +{ + wxLongLong ll; + o >> ll; + value = ll.GetValue(); + return o; +} + +#endif // wxUSE_LONGLONG_NATIVE + +#endif // wxUSE_STREAMS + +#endif // wxUSE_LONGLONG diff --git a/Source/3rd Party/wx/src/common/matrix.cpp b/Source/3rd Party/wx/src/common/matrix.cpp index e0fe8b002..4903aca39 100644 --- a/Source/3rd Party/wx/src/common/matrix.cpp +++ b/Source/3rd Party/wx/src/common/matrix.cpp @@ -1,601 +1,601 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/matrix.cpp -// Purpose: wxTransformMatrix class -// Author: Chris Breeze, Julian Smart -// Modified by: Klaas Holwerda -// Created: 01/02/97 -// RCS-ID: $Id: matrix.cpp 39745 2006-06-15 17:58:49Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// Note: this is intended to be used in wxDC at some point to replace -// the current system of scaling/translation. It is not yet used. - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/matrix.h" - -#ifndef WX_PRECOMP - #include "wx/math.h" -#endif - -static const double pi = M_PI; - -wxTransformMatrix::wxTransformMatrix(void) -{ - m_isIdentity = false; - - Identity(); -} - -wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix& mat) - : wxObject() -{ - (*this) = mat; -} - -double wxTransformMatrix::GetValue(int col, int row) const -{ - if (row < 0 || row > 2 || col < 0 || col > 2) - return 0.0; - - return m_matrix[col][row]; -} - -void wxTransformMatrix::SetValue(int col, int row, double value) -{ - if (row < 0 || row > 2 || col < 0 || col > 2) - return; - - m_matrix[col][row] = value; - m_isIdentity = IsIdentity1(); -} - -void wxTransformMatrix::operator = (const wxTransformMatrix& mat) -{ - int i, j; - for (i = 0; i < 3; i++) - { - for (j = 0; j < 3; j++) - { - m_matrix[i][j] = mat.m_matrix[i][j]; - } - } - m_isIdentity = mat.m_isIdentity; -} - -bool wxTransformMatrix::operator == (const wxTransformMatrix& mat) const -{ - if (m_isIdentity && mat.m_isIdentity) - return true; - - int i, j; - for (i = 0; i < 3; i++) - { - for (j = 0; j < 3; j++) - { - if ( !wxIsSameDouble(m_matrix[i][j], mat.m_matrix[i][j]) ) - return false; - } - } - return true; -} - -bool wxTransformMatrix::operator != (const wxTransformMatrix& mat) const -{ - return (! ((*this) == mat)); -} - -double& wxTransformMatrix::operator()(int col, int row) -{ - if (row < 0 || row > 2 || col < 0 || col > 2) - return m_matrix[0][0]; - - return m_matrix[col][row]; -} - -double wxTransformMatrix::operator()(int col, int row) const -{ - if (row < 0 || row > 2 || col < 0 || col > 2) - return 0.0; - - return m_matrix[col][row]; -} - -// Invert matrix -bool wxTransformMatrix::Invert(void) -{ - double inverseMatrix[3][3]; - - // calculate the adjoint - inverseMatrix[0][0] = wxCalculateDet(m_matrix[1][1],m_matrix[2][1],m_matrix[1][2],m_matrix[2][2]); - inverseMatrix[0][1] = -wxCalculateDet(m_matrix[0][1],m_matrix[2][1],m_matrix[0][2],m_matrix[2][2]); - inverseMatrix[0][2] = wxCalculateDet(m_matrix[0][1],m_matrix[1][1],m_matrix[0][2],m_matrix[1][2]); - - inverseMatrix[1][0] = -wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][2],m_matrix[2][2]); - inverseMatrix[1][1] = wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][2],m_matrix[2][2]); - inverseMatrix[1][2] = -wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][2],m_matrix[1][2]); - - inverseMatrix[2][0] = wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][1],m_matrix[2][1]); - inverseMatrix[2][1] = -wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][1],m_matrix[2][1]); - inverseMatrix[2][2] = wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][1],m_matrix[1][1]); - - // now divide by the determinant - double det = m_matrix[0][0] * inverseMatrix[0][0] + m_matrix[0][1] * inverseMatrix[1][0] + m_matrix[0][2] * inverseMatrix[2][0]; - if ( wxIsNullDouble(det) ) - return false; - - inverseMatrix[0][0] /= det; inverseMatrix[1][0] /= det; inverseMatrix[2][0] /= det; - inverseMatrix[0][1] /= det; inverseMatrix[1][1] /= det; inverseMatrix[2][1] /= det; - inverseMatrix[0][2] /= det; inverseMatrix[1][2] /= det; inverseMatrix[2][2] /= det; - - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 3; j++) - { - m_matrix[i][j] = inverseMatrix[i][j]; - } - } - m_isIdentity = IsIdentity1(); - return true; -} - -// Make into identity matrix -bool wxTransformMatrix::Identity(void) -{ - m_matrix[0][0] = m_matrix[1][1] = m_matrix[2][2] = 1.0; - m_matrix[1][0] = m_matrix[2][0] = m_matrix[0][1] = m_matrix[2][1] = m_matrix[0][2] = m_matrix[1][2] = 0.0; - m_isIdentity = true; - - return true; -} - -// Scale by scale (isotropic scaling i.e. the same in x and y): -// | scale 0 0 | -// matrix' = | 0 scale 0 | x matrix -// | 0 0 scale | -// -bool wxTransformMatrix::Scale(double scale) -{ - int i, j; - for (i = 0; i < 3; i++) - { - for (j = 0; j < 3; j++) - { - m_matrix[i][j] *= scale; - } - } - m_isIdentity = IsIdentity1(); - - return true; -} - - -// scale a matrix in 2D -// -// xs 0 xc(1-xs) -// 0 ys yc(1-ys) -// 0 0 1 -// -wxTransformMatrix& wxTransformMatrix::Scale(const double &xs, const double &ys,const double &xc, const double &yc) -{ - double r00,r10,r20,r01,r11,r21; - - if (m_isIdentity) - { - double tx = xc*(1-xs); - double ty = yc*(1-ys); - r00 = xs; - r10 = 0; - r20 = tx; - r01 = 0; - r11 = ys; - r21 = ty; - } - else if ( !wxIsNullDouble(xc) || !wxIsNullDouble(yc) ) - { - double tx = xc*(1-xs); - double ty = yc*(1-ys); - r00 = xs * m_matrix[0][0]; - r10 = xs * m_matrix[1][0]; - r20 = xs * m_matrix[2][0] + tx; - r01 = ys * m_matrix[0][1]; - r11 = ys * m_matrix[1][1]; - r21 = ys * m_matrix[2][1] + ty; - } - else - { - r00 = xs * m_matrix[0][0]; - r10 = xs * m_matrix[1][0]; - r20 = xs * m_matrix[2][0]; - r01 = ys * m_matrix[0][1]; - r11 = ys * m_matrix[1][1]; - r21 = ys * m_matrix[2][1]; - } - - m_matrix[0][0] = r00; - m_matrix[1][0] = r10; - m_matrix[2][0] = r20; - m_matrix[0][1] = r01; - m_matrix[1][1] = r11; - m_matrix[2][1] = r21; - -/* or like this - // first translate to origin O - (*this).Translate(-x_cen, -y_cen); - - // now do the scaling - wxTransformMatrix scale; - scale.m_matrix[0][0] = x_fac; - scale.m_matrix[1][1] = y_fac; - scale.m_isIdentity = IsIdentity1(); - - *this = scale * (*this); - - // translate back from origin to x_cen, y_cen - (*this).Translate(x_cen, y_cen); -*/ - - m_isIdentity = IsIdentity1(); - - return *this; -} - - -// mirror a matrix in x, y -// -// -1 0 0 Y-mirror -// 0 -1 0 X-mirror -// 0 0 -1 Z-mirror -wxTransformMatrix& wxTransformMatrix::Mirror(bool x, bool y) -{ - wxTransformMatrix temp; - if (x) - { - temp.m_matrix[1][1] = -1; - temp.m_isIdentity=false; - } - if (y) - { - temp.m_matrix[0][0] = -1; - temp.m_isIdentity=false; - } - - *this = temp * (*this); - m_isIdentity = IsIdentity1(); - return *this; -} - -// Translate by dx, dy: -// | 1 0 dx | -// matrix' = | 0 1 dy | x matrix -// | 0 0 1 | -// -bool wxTransformMatrix::Translate(double dx, double dy) -{ - int i; - for (i = 0; i < 3; i++) - m_matrix[i][0] += dx * m_matrix[i][2]; - for (i = 0; i < 3; i++) - m_matrix[i][1] += dy * m_matrix[i][2]; - - m_isIdentity = IsIdentity1(); - - return true; -} - -// Rotate clockwise by the given number of degrees: -// | cos sin 0 | -// matrix' = | -sin cos 0 | x matrix -// | 0 0 1 | -bool wxTransformMatrix::Rotate(double degrees) -{ - Rotate(-degrees,0,0); - return true; -} - -// counter clockwise rotate around a point -// -// cos(r) -sin(r) x(1-cos(r))+y(sin(r) -// sin(r) cos(r) y(1-cos(r))-x(sin(r) -// 0 0 1 -wxTransformMatrix& wxTransformMatrix::Rotate(const double °rees, const double &x, const double &y) -{ - double angle = degrees * pi / 180.0; - double c = cos(angle); - double s = sin(angle); - double r00,r10,r20,r01,r11,r21; - - if (m_isIdentity) - { - double tx = x*(1-c)+y*s; - double ty = y*(1-c)-x*s; - r00 = c ; - r10 = -s; - r20 = tx; - r01 = s; - r11 = c; - r21 = ty; - } - else if ( !wxIsNullDouble(x) || !wxIsNullDouble(y) ) - { - double tx = x*(1-c)+y*s; - double ty = y*(1-c)-x*s; - r00 = c * m_matrix[0][0] - s * m_matrix[0][1] + tx * m_matrix[0][2]; - r10 = c * m_matrix[1][0] - s * m_matrix[1][1] + tx * m_matrix[1][2]; - r20 = c * m_matrix[2][0] - s * m_matrix[2][1] + tx;// * m_matrix[2][2]; - r01 = c * m_matrix[0][1] + s * m_matrix[0][0] + ty * m_matrix[0][2]; - r11 = c * m_matrix[1][1] + s * m_matrix[1][0] + ty * m_matrix[1][2]; - r21 = c * m_matrix[2][1] + s * m_matrix[2][0] + ty;// * m_matrix[2][2]; - } - else - { - r00 = c * m_matrix[0][0] - s * m_matrix[0][1]; - r10 = c * m_matrix[1][0] - s * m_matrix[1][1]; - r20 = c * m_matrix[2][0] - s * m_matrix[2][1]; - r01 = c * m_matrix[0][1] + s * m_matrix[0][0]; - r11 = c * m_matrix[1][1] + s * m_matrix[1][0]; - r21 = c * m_matrix[2][1] + s * m_matrix[2][0]; - } - - m_matrix[0][0] = r00; - m_matrix[1][0] = r10; - m_matrix[2][0] = r20; - m_matrix[0][1] = r01; - m_matrix[1][1] = r11; - m_matrix[2][1] = r21; - -/* or like this - wxTransformMatrix rotate; - rotate.m_matrix[2][0] = tx; - rotate.m_matrix[2][1] = ty; - - rotate.m_matrix[0][0] = c; - rotate.m_matrix[0][1] = s; - - rotate.m_matrix[1][0] = -s; - rotate.m_matrix[1][1] = c; - - rotate.m_isIdentity=false; - *this = rotate * (*this); -*/ - m_isIdentity = IsIdentity1(); - - return *this; -} - -// Transform a point from logical to device coordinates -bool wxTransformMatrix::TransformPoint(double x, double y, double& tx, double& ty) const -{ - if (IsIdentity()) - { - tx = x; ty = y; return true; - } - - tx = x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0]; - ty = x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1]; - - return true; -} - -// Transform a point from device to logical coordinates. - -// Example of use: -// wxTransformMatrix mat = dc.GetTransformation(); -// mat.Invert(); -// mat.InverseTransformPoint(x, y, x1, y1); -// OR (shorthand:) -// dc.LogicalToDevice(x, y, x1, y1); -// The latter is slightly less efficient if we're doing several -// conversions, since the matrix is inverted several times. -bool wxTransformMatrix::InverseTransformPoint(double x, double y, double& tx, double& ty) const -{ - if (IsIdentity()) - { - tx = x; - ty = y; - return true; - } - - const double z = (1.0 - m_matrix[0][2] * x - m_matrix[1][2] * y) / m_matrix[2][2]; - if ( wxIsNullDouble(z) ) - return false; - - tx = x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0]; - ty = x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1]; - return true; -} - -wxTransformMatrix& wxTransformMatrix::operator*=(const double& t) -{ - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - m_matrix[i][j]*= t; - m_isIdentity = IsIdentity1(); - return *this; -} - -wxTransformMatrix& wxTransformMatrix::operator/=(const double& t) -{ - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - m_matrix[i][j]/= t; - m_isIdentity = IsIdentity1(); - return *this; -} - -wxTransformMatrix& wxTransformMatrix::operator+=(const wxTransformMatrix& mat) -{ - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - m_matrix[i][j] += mat.m_matrix[i][j]; - m_isIdentity = IsIdentity1(); - return *this; -} - -wxTransformMatrix& wxTransformMatrix::operator-=(const wxTransformMatrix& mat) -{ - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - m_matrix[i][j] -= mat.m_matrix[i][j]; - m_isIdentity = IsIdentity1(); - return *this; -} - -wxTransformMatrix& wxTransformMatrix::operator*=(const wxTransformMatrix& mat) -{ - - if (mat.m_isIdentity) - return *this; - if (m_isIdentity) - { - *this = mat; - return *this; - } - else - { - wxTransformMatrix result; - for (int i = 0; i < 3; i++) - { - for (int j = 0; j < 3; j++) - { - double sum = 0; - for (int k = 0; k < 3; k++) - sum += m_matrix[k][i] * mat.m_matrix[j][k]; - result.m_matrix[j][i] = sum; - } - } - *this = result; - } - - m_isIdentity = IsIdentity1(); - return *this; -} - - -// constant operators -wxTransformMatrix wxTransformMatrix::operator*(const double& t) const -{ - wxTransformMatrix result = *this; - result *= t; - result.m_isIdentity = result.IsIdentity1(); - return result; -} - -wxTransformMatrix wxTransformMatrix::operator/(const double& t) const -{ - wxTransformMatrix result = *this; -// wxASSERT(t!=0); - result /= t; - result.m_isIdentity = result.IsIdentity1(); - return result; -} - -wxTransformMatrix wxTransformMatrix::operator+(const wxTransformMatrix& m) const -{ - wxTransformMatrix result = *this; - result += m; - result.m_isIdentity = result.IsIdentity1(); - return result; -} - -wxTransformMatrix wxTransformMatrix::operator-(const wxTransformMatrix& m) const -{ - wxTransformMatrix result = *this; - result -= m; - result.m_isIdentity = result.IsIdentity1(); - return result; -} - - -wxTransformMatrix wxTransformMatrix::operator*(const wxTransformMatrix& m) const -{ - wxTransformMatrix result = *this; - result *= m; - result.m_isIdentity = result.IsIdentity1(); - return result; -} - - -wxTransformMatrix wxTransformMatrix::operator-() const -{ - wxTransformMatrix result = *this; - for (int i = 0; i < 3; i++) - for (int j = 0; j < 3; j++) - result.m_matrix[i][j] = -(this->m_matrix[i][j]); - result.m_isIdentity = result.IsIdentity1(); - return result; -} - -static double CheckInt(double getal) -{ - // check if the number is very close to an integer - if ( (ceil(getal) - getal) < 0.0001) - return ceil(getal); - - else if ( (getal - floor(getal)) < 0.0001) - return floor(getal); - - return getal; - -} - -double wxTransformMatrix::Get_scaleX() -{ - double scale_factor; - double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi); - if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) ) - scale_factor = m_matrix[0][0]/cos((rot_angle/180)*pi); - else - scale_factor = m_matrix[0][0]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden ! - - scale_factor = CheckInt(scale_factor); - if (scale_factor < 0) - scale_factor = -scale_factor; - - return scale_factor; -} - -double wxTransformMatrix::Get_scaleY() -{ - double scale_factor; - double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi); - if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) ) - scale_factor = m_matrix[1][1]/cos((rot_angle/180)*pi); - else - scale_factor = m_matrix[1][1]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden ! - - scale_factor = CheckInt(scale_factor); - if (scale_factor < 0) - - scale_factor = -scale_factor; - - return scale_factor; - -} - -double wxTransformMatrix::GetRotation() -{ - double temp1 = GetValue(0,0); // for angle calculation - double temp2 = GetValue(0,1); // - - // Rotation - double rot_angle = atan2(temp2,temp1)*180/pi; - - rot_angle = CheckInt(rot_angle); - return rot_angle; -} - -void wxTransformMatrix::SetRotation(double rotation) -{ - double x=GetValue(2,0); - double y=GetValue(2,1); - Rotate(-GetRotation(), x, y); - Rotate(rotation, x, y); -} +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/matrix.cpp +// Purpose: wxTransformMatrix class +// Author: Chris Breeze, Julian Smart +// Modified by: Klaas Holwerda +// Created: 01/02/97 +// RCS-ID: $Id: matrix.cpp 39745 2006-06-15 17:58:49Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// Note: this is intended to be used in wxDC at some point to replace +// the current system of scaling/translation. It is not yet used. + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/matrix.h" + +#ifndef WX_PRECOMP + #include "wx/math.h" +#endif + +static const double pi = M_PI; + +wxTransformMatrix::wxTransformMatrix(void) +{ + m_isIdentity = false; + + Identity(); +} + +wxTransformMatrix::wxTransformMatrix(const wxTransformMatrix& mat) + : wxObject() +{ + (*this) = mat; +} + +double wxTransformMatrix::GetValue(int col, int row) const +{ + if (row < 0 || row > 2 || col < 0 || col > 2) + return 0.0; + + return m_matrix[col][row]; +} + +void wxTransformMatrix::SetValue(int col, int row, double value) +{ + if (row < 0 || row > 2 || col < 0 || col > 2) + return; + + m_matrix[col][row] = value; + m_isIdentity = IsIdentity1(); +} + +void wxTransformMatrix::operator = (const wxTransformMatrix& mat) +{ + int i, j; + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + m_matrix[i][j] = mat.m_matrix[i][j]; + } + } + m_isIdentity = mat.m_isIdentity; +} + +bool wxTransformMatrix::operator == (const wxTransformMatrix& mat) const +{ + if (m_isIdentity && mat.m_isIdentity) + return true; + + int i, j; + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + if ( !wxIsSameDouble(m_matrix[i][j], mat.m_matrix[i][j]) ) + return false; + } + } + return true; +} + +bool wxTransformMatrix::operator != (const wxTransformMatrix& mat) const +{ + return (! ((*this) == mat)); +} + +double& wxTransformMatrix::operator()(int col, int row) +{ + if (row < 0 || row > 2 || col < 0 || col > 2) + return m_matrix[0][0]; + + return m_matrix[col][row]; +} + +double wxTransformMatrix::operator()(int col, int row) const +{ + if (row < 0 || row > 2 || col < 0 || col > 2) + return 0.0; + + return m_matrix[col][row]; +} + +// Invert matrix +bool wxTransformMatrix::Invert(void) +{ + double inverseMatrix[3][3]; + + // calculate the adjoint + inverseMatrix[0][0] = wxCalculateDet(m_matrix[1][1],m_matrix[2][1],m_matrix[1][2],m_matrix[2][2]); + inverseMatrix[0][1] = -wxCalculateDet(m_matrix[0][1],m_matrix[2][1],m_matrix[0][2],m_matrix[2][2]); + inverseMatrix[0][2] = wxCalculateDet(m_matrix[0][1],m_matrix[1][1],m_matrix[0][2],m_matrix[1][2]); + + inverseMatrix[1][0] = -wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][2],m_matrix[2][2]); + inverseMatrix[1][1] = wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][2],m_matrix[2][2]); + inverseMatrix[1][2] = -wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][2],m_matrix[1][2]); + + inverseMatrix[2][0] = wxCalculateDet(m_matrix[1][0],m_matrix[2][0],m_matrix[1][1],m_matrix[2][1]); + inverseMatrix[2][1] = -wxCalculateDet(m_matrix[0][0],m_matrix[2][0],m_matrix[0][1],m_matrix[2][1]); + inverseMatrix[2][2] = wxCalculateDet(m_matrix[0][0],m_matrix[1][0],m_matrix[0][1],m_matrix[1][1]); + + // now divide by the determinant + double det = m_matrix[0][0] * inverseMatrix[0][0] + m_matrix[0][1] * inverseMatrix[1][0] + m_matrix[0][2] * inverseMatrix[2][0]; + if ( wxIsNullDouble(det) ) + return false; + + inverseMatrix[0][0] /= det; inverseMatrix[1][0] /= det; inverseMatrix[2][0] /= det; + inverseMatrix[0][1] /= det; inverseMatrix[1][1] /= det; inverseMatrix[2][1] /= det; + inverseMatrix[0][2] /= det; inverseMatrix[1][2] /= det; inverseMatrix[2][2] /= det; + + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + m_matrix[i][j] = inverseMatrix[i][j]; + } + } + m_isIdentity = IsIdentity1(); + return true; +} + +// Make into identity matrix +bool wxTransformMatrix::Identity(void) +{ + m_matrix[0][0] = m_matrix[1][1] = m_matrix[2][2] = 1.0; + m_matrix[1][0] = m_matrix[2][0] = m_matrix[0][1] = m_matrix[2][1] = m_matrix[0][2] = m_matrix[1][2] = 0.0; + m_isIdentity = true; + + return true; +} + +// Scale by scale (isotropic scaling i.e. the same in x and y): +// | scale 0 0 | +// matrix' = | 0 scale 0 | x matrix +// | 0 0 scale | +// +bool wxTransformMatrix::Scale(double scale) +{ + int i, j; + for (i = 0; i < 3; i++) + { + for (j = 0; j < 3; j++) + { + m_matrix[i][j] *= scale; + } + } + m_isIdentity = IsIdentity1(); + + return true; +} + + +// scale a matrix in 2D +// +// xs 0 xc(1-xs) +// 0 ys yc(1-ys) +// 0 0 1 +// +wxTransformMatrix& wxTransformMatrix::Scale(const double &xs, const double &ys,const double &xc, const double &yc) +{ + double r00,r10,r20,r01,r11,r21; + + if (m_isIdentity) + { + double tx = xc*(1-xs); + double ty = yc*(1-ys); + r00 = xs; + r10 = 0; + r20 = tx; + r01 = 0; + r11 = ys; + r21 = ty; + } + else if ( !wxIsNullDouble(xc) || !wxIsNullDouble(yc) ) + { + double tx = xc*(1-xs); + double ty = yc*(1-ys); + r00 = xs * m_matrix[0][0]; + r10 = xs * m_matrix[1][0]; + r20 = xs * m_matrix[2][0] + tx; + r01 = ys * m_matrix[0][1]; + r11 = ys * m_matrix[1][1]; + r21 = ys * m_matrix[2][1] + ty; + } + else + { + r00 = xs * m_matrix[0][0]; + r10 = xs * m_matrix[1][0]; + r20 = xs * m_matrix[2][0]; + r01 = ys * m_matrix[0][1]; + r11 = ys * m_matrix[1][1]; + r21 = ys * m_matrix[2][1]; + } + + m_matrix[0][0] = r00; + m_matrix[1][0] = r10; + m_matrix[2][0] = r20; + m_matrix[0][1] = r01; + m_matrix[1][1] = r11; + m_matrix[2][1] = r21; + +/* or like this + // first translate to origin O + (*this).Translate(-x_cen, -y_cen); + + // now do the scaling + wxTransformMatrix scale; + scale.m_matrix[0][0] = x_fac; + scale.m_matrix[1][1] = y_fac; + scale.m_isIdentity = IsIdentity1(); + + *this = scale * (*this); + + // translate back from origin to x_cen, y_cen + (*this).Translate(x_cen, y_cen); +*/ + + m_isIdentity = IsIdentity1(); + + return *this; +} + + +// mirror a matrix in x, y +// +// -1 0 0 Y-mirror +// 0 -1 0 X-mirror +// 0 0 -1 Z-mirror +wxTransformMatrix& wxTransformMatrix::Mirror(bool x, bool y) +{ + wxTransformMatrix temp; + if (x) + { + temp.m_matrix[1][1] = -1; + temp.m_isIdentity=false; + } + if (y) + { + temp.m_matrix[0][0] = -1; + temp.m_isIdentity=false; + } + + *this = temp * (*this); + m_isIdentity = IsIdentity1(); + return *this; +} + +// Translate by dx, dy: +// | 1 0 dx | +// matrix' = | 0 1 dy | x matrix +// | 0 0 1 | +// +bool wxTransformMatrix::Translate(double dx, double dy) +{ + int i; + for (i = 0; i < 3; i++) + m_matrix[i][0] += dx * m_matrix[i][2]; + for (i = 0; i < 3; i++) + m_matrix[i][1] += dy * m_matrix[i][2]; + + m_isIdentity = IsIdentity1(); + + return true; +} + +// Rotate clockwise by the given number of degrees: +// | cos sin 0 | +// matrix' = | -sin cos 0 | x matrix +// | 0 0 1 | +bool wxTransformMatrix::Rotate(double degrees) +{ + Rotate(-degrees,0,0); + return true; +} + +// counter clockwise rotate around a point +// +// cos(r) -sin(r) x(1-cos(r))+y(sin(r) +// sin(r) cos(r) y(1-cos(r))-x(sin(r) +// 0 0 1 +wxTransformMatrix& wxTransformMatrix::Rotate(const double °rees, const double &x, const double &y) +{ + double angle = degrees * pi / 180.0; + double c = cos(angle); + double s = sin(angle); + double r00,r10,r20,r01,r11,r21; + + if (m_isIdentity) + { + double tx = x*(1-c)+y*s; + double ty = y*(1-c)-x*s; + r00 = c ; + r10 = -s; + r20 = tx; + r01 = s; + r11 = c; + r21 = ty; + } + else if ( !wxIsNullDouble(x) || !wxIsNullDouble(y) ) + { + double tx = x*(1-c)+y*s; + double ty = y*(1-c)-x*s; + r00 = c * m_matrix[0][0] - s * m_matrix[0][1] + tx * m_matrix[0][2]; + r10 = c * m_matrix[1][0] - s * m_matrix[1][1] + tx * m_matrix[1][2]; + r20 = c * m_matrix[2][0] - s * m_matrix[2][1] + tx;// * m_matrix[2][2]; + r01 = c * m_matrix[0][1] + s * m_matrix[0][0] + ty * m_matrix[0][2]; + r11 = c * m_matrix[1][1] + s * m_matrix[1][0] + ty * m_matrix[1][2]; + r21 = c * m_matrix[2][1] + s * m_matrix[2][0] + ty;// * m_matrix[2][2]; + } + else + { + r00 = c * m_matrix[0][0] - s * m_matrix[0][1]; + r10 = c * m_matrix[1][0] - s * m_matrix[1][1]; + r20 = c * m_matrix[2][0] - s * m_matrix[2][1]; + r01 = c * m_matrix[0][1] + s * m_matrix[0][0]; + r11 = c * m_matrix[1][1] + s * m_matrix[1][0]; + r21 = c * m_matrix[2][1] + s * m_matrix[2][0]; + } + + m_matrix[0][0] = r00; + m_matrix[1][0] = r10; + m_matrix[2][0] = r20; + m_matrix[0][1] = r01; + m_matrix[1][1] = r11; + m_matrix[2][1] = r21; + +/* or like this + wxTransformMatrix rotate; + rotate.m_matrix[2][0] = tx; + rotate.m_matrix[2][1] = ty; + + rotate.m_matrix[0][0] = c; + rotate.m_matrix[0][1] = s; + + rotate.m_matrix[1][0] = -s; + rotate.m_matrix[1][1] = c; + + rotate.m_isIdentity=false; + *this = rotate * (*this); +*/ + m_isIdentity = IsIdentity1(); + + return *this; +} + +// Transform a point from logical to device coordinates +bool wxTransformMatrix::TransformPoint(double x, double y, double& tx, double& ty) const +{ + if (IsIdentity()) + { + tx = x; ty = y; return true; + } + + tx = x * m_matrix[0][0] + y * m_matrix[1][0] + m_matrix[2][0]; + ty = x * m_matrix[0][1] + y * m_matrix[1][1] + m_matrix[2][1]; + + return true; +} + +// Transform a point from device to logical coordinates. + +// Example of use: +// wxTransformMatrix mat = dc.GetTransformation(); +// mat.Invert(); +// mat.InverseTransformPoint(x, y, x1, y1); +// OR (shorthand:) +// dc.LogicalToDevice(x, y, x1, y1); +// The latter is slightly less efficient if we're doing several +// conversions, since the matrix is inverted several times. +bool wxTransformMatrix::InverseTransformPoint(double x, double y, double& tx, double& ty) const +{ + if (IsIdentity()) + { + tx = x; + ty = y; + return true; + } + + const double z = (1.0 - m_matrix[0][2] * x - m_matrix[1][2] * y) / m_matrix[2][2]; + if ( wxIsNullDouble(z) ) + return false; + + tx = x * m_matrix[0][0] + y * m_matrix[1][0] + z * m_matrix[2][0]; + ty = x * m_matrix[0][1] + y * m_matrix[1][1] + z * m_matrix[2][1]; + return true; +} + +wxTransformMatrix& wxTransformMatrix::operator*=(const double& t) +{ + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + m_matrix[i][j]*= t; + m_isIdentity = IsIdentity1(); + return *this; +} + +wxTransformMatrix& wxTransformMatrix::operator/=(const double& t) +{ + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + m_matrix[i][j]/= t; + m_isIdentity = IsIdentity1(); + return *this; +} + +wxTransformMatrix& wxTransformMatrix::operator+=(const wxTransformMatrix& mat) +{ + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + m_matrix[i][j] += mat.m_matrix[i][j]; + m_isIdentity = IsIdentity1(); + return *this; +} + +wxTransformMatrix& wxTransformMatrix::operator-=(const wxTransformMatrix& mat) +{ + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + m_matrix[i][j] -= mat.m_matrix[i][j]; + m_isIdentity = IsIdentity1(); + return *this; +} + +wxTransformMatrix& wxTransformMatrix::operator*=(const wxTransformMatrix& mat) +{ + + if (mat.m_isIdentity) + return *this; + if (m_isIdentity) + { + *this = mat; + return *this; + } + else + { + wxTransformMatrix result; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + double sum = 0; + for (int k = 0; k < 3; k++) + sum += m_matrix[k][i] * mat.m_matrix[j][k]; + result.m_matrix[j][i] = sum; + } + } + *this = result; + } + + m_isIdentity = IsIdentity1(); + return *this; +} + + +// constant operators +wxTransformMatrix wxTransformMatrix::operator*(const double& t) const +{ + wxTransformMatrix result = *this; + result *= t; + result.m_isIdentity = result.IsIdentity1(); + return result; +} + +wxTransformMatrix wxTransformMatrix::operator/(const double& t) const +{ + wxTransformMatrix result = *this; +// wxASSERT(t!=0); + result /= t; + result.m_isIdentity = result.IsIdentity1(); + return result; +} + +wxTransformMatrix wxTransformMatrix::operator+(const wxTransformMatrix& m) const +{ + wxTransformMatrix result = *this; + result += m; + result.m_isIdentity = result.IsIdentity1(); + return result; +} + +wxTransformMatrix wxTransformMatrix::operator-(const wxTransformMatrix& m) const +{ + wxTransformMatrix result = *this; + result -= m; + result.m_isIdentity = result.IsIdentity1(); + return result; +} + + +wxTransformMatrix wxTransformMatrix::operator*(const wxTransformMatrix& m) const +{ + wxTransformMatrix result = *this; + result *= m; + result.m_isIdentity = result.IsIdentity1(); + return result; +} + + +wxTransformMatrix wxTransformMatrix::operator-() const +{ + wxTransformMatrix result = *this; + for (int i = 0; i < 3; i++) + for (int j = 0; j < 3; j++) + result.m_matrix[i][j] = -(this->m_matrix[i][j]); + result.m_isIdentity = result.IsIdentity1(); + return result; +} + +static double CheckInt(double getal) +{ + // check if the number is very close to an integer + if ( (ceil(getal) - getal) < 0.0001) + return ceil(getal); + + else if ( (getal - floor(getal)) < 0.0001) + return floor(getal); + + return getal; + +} + +double wxTransformMatrix::Get_scaleX() +{ + double scale_factor; + double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi); + if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) ) + scale_factor = m_matrix[0][0]/cos((rot_angle/180)*pi); + else + scale_factor = m_matrix[0][0]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden ! + + scale_factor = CheckInt(scale_factor); + if (scale_factor < 0) + scale_factor = -scale_factor; + + return scale_factor; +} + +double wxTransformMatrix::Get_scaleY() +{ + double scale_factor; + double rot_angle = CheckInt(atan2(m_matrix[1][0],m_matrix[0][0])*180/pi); + if ( !wxIsSameDouble(rot_angle, 90) && !wxIsSameDouble(rot_angle, -90) ) + scale_factor = m_matrix[1][1]/cos((rot_angle/180)*pi); + else + scale_factor = m_matrix[1][1]/sin((rot_angle/180)*pi); // er kan nl. niet door 0 gedeeld worden ! + + scale_factor = CheckInt(scale_factor); + if (scale_factor < 0) + + scale_factor = -scale_factor; + + return scale_factor; + +} + +double wxTransformMatrix::GetRotation() +{ + double temp1 = GetValue(0,0); // for angle calculation + double temp2 = GetValue(0,1); // + + // Rotation + double rot_angle = atan2(temp2,temp1)*180/pi; + + rot_angle = CheckInt(rot_angle); + return rot_angle; +} + +void wxTransformMatrix::SetRotation(double rotation) +{ + double x=GetValue(2,0); + double y=GetValue(2,1); + Rotate(-GetRotation(), x, y); + Rotate(rotation, x, y); +} diff --git a/Source/3rd Party/wx/src/common/memory.cpp b/Source/3rd Party/wx/src/common/memory.cpp index d01f1a061..e3a1d7866 100644 --- a/Source/3rd Party/wx/src/common/memory.cpp +++ b/Source/3rd Party/wx/src/common/memory.cpp @@ -1,1148 +1,1148 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/memory.cpp -// Purpose: Memory checking implementation -// Author: Arthur Seaton, Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: memory.cpp 41054 2006-09-07 19:01:45Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT - -#include "wx/memory.h" - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/wrapwin.h" - #endif - #include "wx/utils.h" - #include "wx/app.h" - #include "wx/hash.h" - #include "wx/log.h" -#endif - -#if wxUSE_THREADS - #include "wx/thread.h" -#endif - -#include - -#include "wx/ioswrap.h" - -#if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )\ - && !defined( __MWERKS__ ) && !defined(__SALFORDC__) -#include -#endif - -#include -#include - -#if wxUSE_THREADS && defined(__WXDEBUG__) -#define USE_THREADSAFE_MEMORY_ALLOCATION 1 -#else -#define USE_THREADSAFE_MEMORY_ALLOCATION 0 -#endif - - -#ifdef new -#undef new -#endif - -// wxDebugContext wxTheDebugContext; -/* - Redefine new and delete so that we can pick up situations where: - - we overwrite or underwrite areas of malloc'd memory. - - we use uninitialise variables - Only do this in debug mode. - - We change new to get enough memory to allocate a struct, followed - by the caller's requested memory, followed by a tag. The struct - is used to create a doubly linked list of these areas and also - contains another tag. The tags are used to determine when the area - has been over/under written. -*/ - - -/* - Values which are used to set the markers which will be tested for - under/over write. There are 3 of these, one in the struct, one - immediately after the struct but before the caller requested memory and - one immediately after the requested memory. -*/ -#define MemStartCheck 0x23A8 -#define MemMidCheck 0xA328 -#define MemEndCheck 0x8A32 -#define MemFillChar 0xAF -#define MemStructId 0x666D - -/* - External interface for the wxMemStruct class. Others are - defined inline within the class def. Here we only need to be able - to add and delete nodes from the list and handle errors in some way. -*/ - -/* - Used for internal "this shouldn't happen" type of errors. -*/ -void wxMemStruct::ErrorMsg (const char * mesg) -{ - wxLogMessage(wxT("wxWidgets memory checking error: %s"), mesg); - PrintNode (); -} - -/* - Used when we find an overwrite or an underwrite error. -*/ -void wxMemStruct::ErrorMsg () -{ - wxLogMessage(wxT("wxWidgets over/underwrite memory error:")); - PrintNode (); -} - - -/* - We want to find out if pointers have been overwritten as soon as is - possible, so test everything before we dereference it. Of course it's still - quite possible that, if things have been overwritten, this function will - fall over, but the only way of dealing with that would cost too much in terms - of time. -*/ -int wxMemStruct::AssertList () -{ - if (wxDebugContext::GetHead () != 0 && ! (wxDebugContext::GetHead ())->AssertIt () || - wxDebugContext::GetTail () != 0 && ! wxDebugContext::GetTail ()->AssertIt ()) { - ErrorMsg ("Head or tail pointers trashed"); - return 0; - } - return 1; -} - - -/* - Check that the thing we're pointing to has the correct id for a wxMemStruct - object and also that it's previous and next pointers are pointing at objects - which have valid ids. - This is definitely not perfect since we could fall over just trying to access - any of the slots which we use here, but I think it's about the best that I - can do without doing something like taking all new wxMemStruct pointers and - comparing them against all known pointer within the list and then only - doing this sort of check _after_ you've found the pointer in the list. That - would be safer, but also much more time consuming. -*/ -int wxMemStruct::AssertIt () -{ - return (m_id == MemStructId && - (m_prev == 0 || m_prev->m_id == MemStructId) && - (m_next == 0 || m_next->m_id == MemStructId)); -} - - -/* - Additions are always at the tail of the list. - Returns 0 on error, non-zero on success. -*/ -int wxMemStruct::Append () -{ - if (! AssertList ()) - return 0; - - if (wxDebugContext::GetHead () == 0) { - if (wxDebugContext::GetTail () != 0) { - ErrorMsg ("Null list should have a null tail pointer"); - return 0; - } - (void) wxDebugContext::SetHead (this); - (void) wxDebugContext::SetTail (this); - } else { - wxDebugContext::GetTail ()->m_next = this; - this->m_prev = wxDebugContext::GetTail (); - (void) wxDebugContext::SetTail (this); - } - return 1; -} - - -/* - Don't actually free up anything here as the space which is used - by the node will be free'd up when the whole block is free'd. - Returns 0 on error, non-zero on success. -*/ -int wxMemStruct::Unlink () -{ - if (! AssertList ()) - return 0; - - if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) { - ErrorMsg ("Trying to remove node from empty list"); - return 0; - } - - // Handle the part of the list before this node. - if (m_prev == 0) { - if (this != wxDebugContext::GetHead ()) { - ErrorMsg ("No previous node for non-head node"); - return 0; - } - (void) wxDebugContext::SetHead (m_next); - } else { - if (! m_prev->AssertIt ()) { - ErrorMsg ("Trashed previous pointer"); - return 0; - } - - if (m_prev->m_next != this) { - ErrorMsg ("List is inconsistent"); - return 0; - } - m_prev->m_next = m_next; - } - - // Handle the part of the list after this node. - if (m_next == 0) { - if (this != wxDebugContext::GetTail ()) { - ErrorMsg ("No next node for non-tail node"); - return 0; - } - (void) wxDebugContext::SetTail (m_prev); - } else { - if (! m_next->AssertIt ()) { - ErrorMsg ("Trashed next pointer"); - return 0; - } - - if (m_next->m_prev != this) { - ErrorMsg ("List is inconsistent"); - return 0; - } - m_next->m_prev = m_prev; - } - - return 1; -} - - - -/* - Checks a node and block of memory to see that the markers are still - intact. -*/ -int wxMemStruct::CheckBlock () -{ - int nFailures = 0; - - if (m_firstMarker != MemStartCheck) { - nFailures++; - ErrorMsg (); - } - - char * pointer = wxDebugContext::MidMarkerPos ((char *) this); - if (* (wxMarkerType *) pointer != MemMidCheck) { - nFailures++; - ErrorMsg (); - } - - pointer = wxDebugContext::EndMarkerPos ((char *) this, RequestSize ()); - if (* (wxMarkerType *) pointer != MemEndCheck) { - nFailures++; - ErrorMsg (); - } - - return nFailures; -} - - -/* - Check the list of nodes to see if they are all ok. -*/ -int wxMemStruct::CheckAllPrevious () -{ - int nFailures = 0; - - for (wxMemStruct * st = this->m_prev; st != 0; st = st->m_prev) { - if (st->AssertIt ()) - nFailures += st->CheckBlock (); - else - return -1; - } - - return nFailures; -} - - -/* - When we delete a node we set the id slot to a specific value and then test - against this to see if a nodes have been deleted previously. I don't - just set the entire memory to the fillChar because then I'd be overwriting - useful stuff like the vtbl which may be needed to output the error message - including the file name and line numbers. Without this info the whole point - of this class is lost! -*/ -void wxMemStruct::SetDeleted () -{ - m_id = MemFillChar; -} - -int wxMemStruct::IsDeleted () -{ - return (m_id == MemFillChar); -} - - -/* - Print out a single node. There are many far better ways of doing this - but this will suffice for now. -*/ -void wxMemStruct::PrintNode () -{ - if (m_isObject) - { - wxObject *obj = (wxObject *)m_actualData; - wxClassInfo *info = obj->GetClassInfo(); - - // Let's put this in standard form so IDEs can load the file at the appropriate - // line - wxString msg; - - if (m_fileName) - msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); - - if (info && info->GetClassName()) - msg += info->GetClassName(); - else - msg += wxT("object"); - - wxString msg2; - msg2.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize()); - msg += msg2; - - wxLogMessage(msg); - } - else - { - wxString msg; - - if (m_fileName) - msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); - msg += wxT("non-object data"); - wxString msg2; - msg2.Printf(wxT(" at 0x%lX, size %d\n"), (long)GetActualData(), (int)RequestSize()); - msg += msg2; - - wxLogMessage(msg); - } -} - -void wxMemStruct::Dump () -{ - if (!ValidateNode()) return; - - if (m_isObject) - { - wxObject *obj = (wxObject *)m_actualData; - - wxString msg; - if (m_fileName) - msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); - - - /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it. - * Instead, do what wxObject::Dump does. - * What should we do long-term, eliminate Dumping? Or specify - * that MyClass::Dump should use wxLogDebug? Ugh. - obj->Dump(wxDebugContext::GetStream()); - */ - - if (obj->GetClassInfo() && obj->GetClassInfo()->GetClassName()) - msg += obj->GetClassInfo()->GetClassName(); - else - msg += wxT("unknown object class"); - - wxString msg2; - msg2.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize()); - msg += msg2; - - wxDebugContext::OutputDumpLine(msg); - } - else - { - wxString msg; - if (m_fileName) - msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); - - wxString msg2; - msg2.Printf(wxT("non-object data at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize() ); - msg += msg2; - wxDebugContext::OutputDumpLine(msg); - } -} - - -/* - Validate a node. Check to see that the node is "clean" in the sense - that nothing has over/underwritten it etc. -*/ -int wxMemStruct::ValidateNode () -{ - char * startPointer = (char *) this; - if (!AssertIt ()) { - if (IsDeleted ()) - ErrorMsg ("Object already deleted"); - else { - // Can't use the error routines as we have no recognisable object. -#ifndef __WXGTK__ - wxLogMessage(wxT("Can't verify memory struct - all bets are off!")); -#endif - } - return 0; - } - -/* - int i; - for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++) - cout << startPointer [i]; - cout << endl; -*/ - if (Marker () != MemStartCheck) - ErrorMsg (); - if (* (wxMarkerType *) wxDebugContext::MidMarkerPos (startPointer) != MemMidCheck) - ErrorMsg (); - if (* (wxMarkerType *) wxDebugContext::EndMarkerPos (startPointer, - RequestSize ()) != - MemEndCheck) - ErrorMsg (); - - // Back to before the extra buffer and check that - // we can still read what we originally wrote. - if (Marker () != MemStartCheck || - * (wxMarkerType *) wxDebugContext::MidMarkerPos (startPointer) - != MemMidCheck || - * (wxMarkerType *) wxDebugContext::EndMarkerPos (startPointer, - RequestSize ()) != MemEndCheck) - { - ErrorMsg (); - return 0; - } - - return 1; -} - -/* - The wxDebugContext class. -*/ - -wxMemStruct *wxDebugContext::m_head = NULL; -wxMemStruct *wxDebugContext::m_tail = NULL; - -bool wxDebugContext::m_checkPrevious = false; -int wxDebugContext::debugLevel = 1; -bool wxDebugContext::debugOn = true; -wxMemStruct *wxDebugContext::checkPoint = NULL; - -// For faster alignment calculation -static wxMarkerType markerCalc[2]; -int wxDebugContext::m_balign = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]); -int wxDebugContext::m_balignmask = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]) - 1; - -wxDebugContext::wxDebugContext(void) -{ -} - -wxDebugContext::~wxDebugContext(void) -{ -} - -/* - Work out the positions of the markers by creating an array of 2 markers - and comparing the addresses of the 2 elements. Use this number as the - alignment for markers. -*/ -size_t wxDebugContext::CalcAlignment () -{ - wxMarkerType ar[2]; - return (char *) &ar[1] - (char *) &ar[0]; -} - - -char * wxDebugContext::StructPos (const char * buf) -{ - return (char *) buf; -} - -char * wxDebugContext::MidMarkerPos (const char * buf) -{ - return StructPos (buf) + PaddedSize (sizeof (wxMemStruct)); -} - -char * wxDebugContext::CallerMemPos (const char * buf) -{ - return MidMarkerPos (buf) + PaddedSize (sizeof(wxMarkerType)); -} - - -char * wxDebugContext::EndMarkerPos (const char * buf, const size_t size) -{ - return CallerMemPos (buf) + PaddedSize (size); -} - - -/* - Slightly different as this takes a pointer to the start of the caller - requested region and returns a pointer to the start of the buffer. - */ -char * wxDebugContext::StartPos (const char * caller) -{ - return ((char *) (caller - wxDebugContext::PaddedSize (sizeof(wxMarkerType)) - - wxDebugContext::PaddedSize (sizeof (wxMemStruct)))); -} - -/* - We may need padding between various parts of the allocated memory. - Given a size of memory, this returns the amount of memory which should - be allocated in order to allow for alignment of the following object. - - I don't know how portable this stuff is, but it seems to work for me at - the moment. It would be real nice if I knew more about this! - - // Note: this function is now obsolete (along with CalcAlignment) - // because the calculations are done statically, for greater speed. -*/ -size_t wxDebugContext::GetPadding (const size_t size) -{ - size_t pad = size % CalcAlignment (); - return (pad) ? sizeof(wxMarkerType) - pad : 0; -} - -size_t wxDebugContext::PaddedSize (const size_t size) -{ - // Added by Terry Farnham to replace - // slow GetPadding call. - int padb; - - padb = size & m_balignmask; - if(padb) - return(size + m_balign - padb); - else - return(size); -} - -/* - Returns the total amount of memory which we need to get from the system - in order to satisfy a caller request. This includes space for the struct - plus markers and the caller's memory as well. -*/ -size_t wxDebugContext::TotSize (const size_t reqSize) -{ - return (PaddedSize (sizeof (wxMemStruct)) + PaddedSize (reqSize) + - 2 * sizeof(wxMarkerType)); -} - - -/* - Traverse the list of nodes executing the given function on each node. -*/ -void wxDebugContext::TraverseList (PmSFV func, wxMemStruct *from) -{ - if (!from) - from = wxDebugContext::GetHead (); - - wxMemStruct * st = NULL; - for (st = from; st != 0; st = st->m_next) - { - void* data = st->GetActualData(); -// if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf)) - if (data != (void*) wxLog::GetActiveTarget()) - { - (st->*func) (); - } - } -} - - -/* - Print out the list. - */ -bool wxDebugContext::PrintList (void) -{ -#ifdef __WXDEBUG__ - TraverseList ((PmSFV)&wxMemStruct::PrintNode, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL)); - - return true; -#else - return false; -#endif -} - -bool wxDebugContext::Dump(void) -{ -#ifdef __WXDEBUG__ - { - wxChar* appName = (wxChar*) wxT("application"); - wxString appNameStr; - if (wxTheApp) - { - appNameStr = wxTheApp->GetAppName(); - appName = WXSTRINGCAST appNameStr; - OutputDumpLine(wxT("----- Memory dump of %s at %s -----"), appName, WXSTRINGCAST wxNow() ); - } - else - { - OutputDumpLine( wxT("----- Memory dump -----") ); - } - } - - TraverseList ((PmSFV)&wxMemStruct::Dump, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL)); - - OutputDumpLine(wxEmptyString); - OutputDumpLine(wxEmptyString); - - return true; -#else - return false; -#endif -} - -#ifdef __WXDEBUG__ -struct wxDebugStatsStruct -{ - long instanceCount; - long totalSize; - wxChar *instanceClass; - wxDebugStatsStruct *next; -}; - -static wxDebugStatsStruct *FindStatsStruct(wxDebugStatsStruct *st, wxChar *name) -{ - while (st) - { - if (wxStrcmp(st->instanceClass, name) == 0) - return st; - st = st->next; - } - return NULL; -} - -static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st) -{ - st->next = head; - return st; -} -#endif - -bool wxDebugContext::PrintStatistics(bool detailed) -{ -#ifdef __WXDEBUG__ - { - wxChar* appName = (wxChar*) wxT("application"); - wxString appNameStr; - if (wxTheApp) - { - appNameStr = wxTheApp->GetAppName(); - appName = WXSTRINGCAST appNameStr; - OutputDumpLine(wxT("----- Memory statistics of %s at %s -----"), appName, WXSTRINGCAST wxNow() ); - } - else - { - OutputDumpLine( wxT("----- Memory statistics -----") ); - } - } - - bool currentMode = GetDebugMode(); - SetDebugMode(false); - - long noNonObjectNodes = 0; - long noObjectNodes = 0; - long totalSize = 0; - - wxDebugStatsStruct *list = NULL; - - wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL ); - if (!from) - from = wxDebugContext::GetHead (); - - wxMemStruct *st; - for (st = from; st != 0; st = st->m_next) - { - void* data = st->GetActualData(); - if (detailed && (data != (void*) wxLog::GetActiveTarget())) - { - wxChar *className = (wxChar*) wxT("nonobject"); - if (st->m_isObject && st->GetActualData()) - { - wxObject *obj = (wxObject *)st->GetActualData(); - if (obj->GetClassInfo()->GetClassName()) - className = (wxChar*)obj->GetClassInfo()->GetClassName(); - } - wxDebugStatsStruct *stats = FindStatsStruct(list, className); - if (!stats) - { - stats = (wxDebugStatsStruct *)malloc(sizeof(wxDebugStatsStruct)); - stats->instanceClass = className; - stats->instanceCount = 0; - stats->totalSize = 0; - list = InsertStatsStruct(list, stats); - } - stats->instanceCount ++; - stats->totalSize += st->RequestSize(); - } - - if (data != (void*) wxLog::GetActiveTarget()) - { - totalSize += st->RequestSize(); - if (st->m_isObject) - noObjectNodes ++; - else - noNonObjectNodes ++; - } - } - - if (detailed) - { - while (list) - { - OutputDumpLine(wxT("%ld objects of class %s, total size %ld"), - list->instanceCount, list->instanceClass, list->totalSize); - wxDebugStatsStruct *old = list; - list = old->next; - free((char *)old); - } - OutputDumpLine(wxEmptyString); - } - - SetDebugMode(currentMode); - - OutputDumpLine(wxT("Number of object items: %ld"), noObjectNodes); - OutputDumpLine(wxT("Number of non-object items: %ld"), noNonObjectNodes); - OutputDumpLine(wxT("Total allocated size: %ld"), totalSize); - OutputDumpLine(wxEmptyString); - OutputDumpLine(wxEmptyString); - - return true; -#else - (void)detailed; - return false; -#endif -} - -bool wxDebugContext::PrintClasses(void) -{ - { - wxChar* appName = (wxChar*) wxT("application"); - wxString appNameStr; - if (wxTheApp) - { - appNameStr = wxTheApp->GetAppName(); - appName = WXSTRINGCAST appNameStr; - wxLogMessage(wxT("----- Classes in %s -----"), appName); - } - } - - int n = 0; - wxHashTable::compatibility_iterator node; - wxClassInfo *info; - - wxClassInfo::sm_classTable->BeginFind(); - node = wxClassInfo::sm_classTable->Next(); - while (node) - { - info = (wxClassInfo *)node->GetData(); - if (info->GetClassName()) - { - wxString msg(info->GetClassName()); - msg += wxT(" "); - - if (info->GetBaseClassName1() && !info->GetBaseClassName2()) - { - msg += wxT("is a "); - msg += info->GetBaseClassName1(); - } - else if (info->GetBaseClassName1() && info->GetBaseClassName2()) - { - msg += wxT("is a "); - msg += info->GetBaseClassName1() ; - msg += wxT(", "); - msg += info->GetBaseClassName2() ; - } - if (info->GetConstructor()) - msg += wxT(": dynamic"); - - wxLogMessage(msg); - } - node = wxClassInfo::sm_classTable->Next(); - n ++; - } - wxLogMessage(wxEmptyString); - wxLogMessage(wxT("There are %d classes derived from wxObject."), n); - wxLogMessage(wxEmptyString); - wxLogMessage(wxEmptyString); - return true; -} - -void wxDebugContext::SetCheckpoint(bool all) -{ - if (all) - checkPoint = NULL; - else - checkPoint = m_tail; -} - -// Checks all nodes since checkpoint, or since start. -int wxDebugContext::Check(bool checkAll) -{ - int nFailures = 0; - - wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL ); - if (!from || checkAll) - from = wxDebugContext::GetHead (); - - for (wxMemStruct * st = from; st != 0; st = st->m_next) - { - if (st->AssertIt ()) - nFailures += st->CheckBlock (); - else - return -1; - } - - return nFailures; -} - -// Count the number of non-wxDebugContext-related objects -// that are outstanding -int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint) -{ - int n = 0; - - wxMemStruct *from = NULL; - if (sinceCheckpoint && checkPoint) - from = checkPoint->m_next; - else - from = wxDebugContext::GetHead () ; - - for (wxMemStruct * st = from; st != 0; st = st->m_next) - { - void* data = st->GetActualData(); - if (data != (void*) wxLog::GetActiveTarget()) - n ++; - } - - return n ; -} - -// This function is used to output the dump -void wxDebugContext::OutputDumpLine(const wxChar *szFormat, ...) -{ - // a buffer of 2048 bytes should be long enough for a file name - // and a class name - wxChar buf[2048]; - int count; - va_list argptr; - va_start(argptr, szFormat); - buf[sizeof(buf)/sizeof(wxChar)-1] = _T('\0'); - - // keep 3 bytes for a \r\n\0 - count = wxVsnprintf(buf, sizeof(buf)/sizeof(wxChar)-3, szFormat, argptr); - - if ( count < 0 ) - count = sizeof(buf)/sizeof(wxChar)-3; - buf[count]=_T('\r'); - buf[count+1]=_T('\n'); - buf[count+2]=_T('\0'); - - wxMessageOutputDebug dbgout; - dbgout.Printf(buf); -} - - -#if USE_THREADSAFE_MEMORY_ALLOCATION -static bool memSectionOk = false; - -class MemoryCriticalSection : public wxCriticalSection -{ -public: - MemoryCriticalSection() { - memSectionOk = true; - } - ~MemoryCriticalSection() { - memSectionOk = false; - } -}; - -class MemoryCriticalSectionLocker -{ -public: - inline MemoryCriticalSectionLocker(wxCriticalSection& critsect) - : m_critsect(critsect), m_locked(memSectionOk) { if(m_locked) m_critsect.Enter(); } - inline ~MemoryCriticalSectionLocker() { if(m_locked) m_critsect.Leave(); } - -private: - // no assignment operator nor copy ctor - MemoryCriticalSectionLocker(const MemoryCriticalSectionLocker&); - MemoryCriticalSectionLocker& operator=(const MemoryCriticalSectionLocker&); - - wxCriticalSection& m_critsect; - bool m_locked; -}; - -static MemoryCriticalSection memLocker; - -#endif // USE_THREADSAFE_MEMORY_ALLOCATION - - -#ifdef __WXDEBUG__ -#if !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE))) -#if wxUSE_GLOBAL_MEMORY_OPERATORS -void * operator new (size_t size, wxChar * fileName, int lineNum) -{ - return wxDebugAlloc(size, fileName, lineNum, false, false); -} - -void * operator new (size_t size) -{ - return wxDebugAlloc(size, NULL, 0, false); -} - -void operator delete (void * buf) -{ - wxDebugFree(buf, false); -} - -#if wxUSE_ARRAY_MEMORY_OPERATORS -void * operator new[] (size_t size) -{ - return wxDebugAlloc(size, NULL, 0, false, true); -} - -void * operator new[] (size_t size, wxChar * fileName, int lineNum) -{ - return wxDebugAlloc(size, fileName, lineNum, false, true); -} - -void operator delete[] (void * buf) -{ - wxDebugFree(buf, true); -} -#endif // wxUSE_ARRAY_MEMORY_OPERATORS -#endif // wxUSE_GLOBAL_MEMORY_OPERATORS -#endif // !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE))) - -// TODO: store whether this is a vector or not. -void * wxDebugAlloc(size_t size, wxChar * fileName, int lineNum, bool isObject, bool WXUNUSED(isVect) ) -{ -#if USE_THREADSAFE_MEMORY_ALLOCATION - MemoryCriticalSectionLocker lock(memLocker); -#endif - - // If not in debugging allocation mode, do the normal thing - // so we don't leave any trace of ourselves in the node list. - -#if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ) -// VA 3.0 still has trouble in here - return (void *)malloc(size); -#endif - if (!wxDebugContext::GetDebugMode()) - { - return (void *)malloc(size); - } - - int totSize = wxDebugContext::TotSize (size); - char * buf = (char *) malloc(totSize); - if (!buf) { - wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size); - return 0; - } - wxMemStruct * st = (wxMemStruct *)buf; - st->m_firstMarker = MemStartCheck; - st->m_reqSize = size; - st->m_fileName = fileName; - st->m_lineNum = lineNum; - st->m_id = MemStructId; - st->m_prev = 0; - st->m_next = 0; - st->m_isObject = isObject; - - // Errors from Append() shouldn't really happen - but just in case! - if (st->Append () == 0) { - st->ErrorMsg ("Trying to append new node"); - } - - if (wxDebugContext::GetCheckPrevious ()) { - if (st->CheckAllPrevious () < 0) { - st->ErrorMsg ("Checking previous nodes"); - } - } - - // Set up the extra markers at the middle and end. - char * ptr = wxDebugContext::MidMarkerPos (buf); - * (wxMarkerType *) ptr = MemMidCheck; - ptr = wxDebugContext::EndMarkerPos (buf, size); - * (wxMarkerType *) ptr = MemEndCheck; - - // pointer returned points to the start of the caller's - // usable area. - void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf); - st->m_actualData = m_actualData; - - return m_actualData; -} - -// TODO: check whether was allocated as a vector -void wxDebugFree(void * buf, bool WXUNUSED(isVect) ) -{ -#if USE_THREADSAFE_MEMORY_ALLOCATION - MemoryCriticalSectionLocker lock(memLocker); -#endif - - if (!buf) - return; - -#if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ) -// VA 3.0 still has trouble in here - free((char *)buf); -#endif - // If not in debugging allocation mode, do the normal thing - // so we don't leave any trace of ourselves in the node list. - if (!wxDebugContext::GetDebugMode()) - { - free((char *)buf); - return; - } - - // Points to the start of the entire allocated area. - char * startPointer = wxDebugContext::StartPos ((char *) buf); - // Find the struct and make sure that it's identifiable. - wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer); - - if (! st->ValidateNode ()) - return; - - // If this is the current checkpoint, we need to - // move the checkpoint back so it points to a valid - // node. - if (st == wxDebugContext::checkPoint) - wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev; - - if (! st->Unlink ()) - { - st->ErrorMsg ("Unlinking deleted node"); - } - - // Now put in the fill char into the id slot and the caller requested - // memory locations. - st->SetDeleted (); - (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar, - st->RequestSize ()); - - free((char *)st); -} - -#endif // __WXDEBUG__ - -// Trace: send output to the current debugging stream -void wxTrace(const wxChar * ...) -{ -#if 1 - wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead.")); -#else - va_list ap; - static wxChar buffer[512]; - - va_start(ap, fmt); - -#ifdef __WXMSW__ - wvsprintf(buffer,fmt,ap) ; -#else - vsprintf(buffer,fmt,ap) ; -#endif - - va_end(ap); - - if (wxDebugContext::HasStream()) - { - wxDebugContext::GetStream() << buffer; - wxDebugContext::GetStream().flush(); - } - else -#ifdef __WXMSW__ -#ifdef __WIN32__ - OutputDebugString((LPCTSTR)buffer) ; -#else - OutputDebugString((const char*) buffer) ; -#endif -#else - fprintf(stderr, buffer); -#endif -#endif -} - -// Trace with level -void wxTraceLevel(int, const wxChar * ...) -{ -#if 1 - wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead.")); -#else - if (wxDebugContext::GetLevel() < level) - return; - - va_list ap; - static wxChar buffer[512]; - - va_start(ap, fmt); - -#ifdef __WXMSW__ - wxWvsprintf(buffer,fmt,ap) ; -#else - vsprintf(buffer,fmt,ap) ; -#endif - - va_end(ap); - - if (wxDebugContext::HasStream()) - { - wxDebugContext::GetStream() << buffer; - wxDebugContext::GetStream().flush(); - } - else -#ifdef __WXMSW__ -#ifdef __WIN32__ - OutputDebugString((LPCTSTR)buffer) ; -#else - OutputDebugString((const char*) buffer) ; -#endif -#else - fprintf(stderr, buffer); -#endif -#endif -} - -//---------------------------------------------------------------------------- -// Final cleanup after all global objects in all files have been destroyed -//---------------------------------------------------------------------------- - -// Don't set it to 0 by dynamic initialization -// Some compilers will really do the assignment later -// All global variables are initialized to 0 at the very beginning, and this is just fine. -int wxDebugContextDumpDelayCounter::sm_count; - -void wxDebugContextDumpDelayCounter::DoDump() -{ - if (wxDebugContext::CountObjectsLeft(true) > 0) - { - wxDebugContext::OutputDumpLine(wxT("There were memory leaks.\n")); - wxDebugContext::Dump(); - wxDebugContext::PrintStatistics(); - } -} - -// Even if there is nothing else, make sure that there is at -// least one cleanup counter object -static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_One; - -#endif // (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/memory.cpp +// Purpose: Memory checking implementation +// Author: Arthur Seaton, Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: memory.cpp 41054 2006-09-07 19:01:45Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT + +#include "wx/memory.h" + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" + #endif + #include "wx/utils.h" + #include "wx/app.h" + #include "wx/hash.h" + #include "wx/log.h" +#endif + +#if wxUSE_THREADS + #include "wx/thread.h" +#endif + +#include + +#include "wx/ioswrap.h" + +#if !defined(__WATCOMC__) && !(defined(__VMS__) && ( __VMS_VER < 70000000 ) )\ + && !defined( __MWERKS__ ) && !defined(__SALFORDC__) +#include +#endif + +#include +#include + +#if wxUSE_THREADS && defined(__WXDEBUG__) +#define USE_THREADSAFE_MEMORY_ALLOCATION 1 +#else +#define USE_THREADSAFE_MEMORY_ALLOCATION 0 +#endif + + +#ifdef new +#undef new +#endif + +// wxDebugContext wxTheDebugContext; +/* + Redefine new and delete so that we can pick up situations where: + - we overwrite or underwrite areas of malloc'd memory. + - we use uninitialise variables + Only do this in debug mode. + + We change new to get enough memory to allocate a struct, followed + by the caller's requested memory, followed by a tag. The struct + is used to create a doubly linked list of these areas and also + contains another tag. The tags are used to determine when the area + has been over/under written. +*/ + + +/* + Values which are used to set the markers which will be tested for + under/over write. There are 3 of these, one in the struct, one + immediately after the struct but before the caller requested memory and + one immediately after the requested memory. +*/ +#define MemStartCheck 0x23A8 +#define MemMidCheck 0xA328 +#define MemEndCheck 0x8A32 +#define MemFillChar 0xAF +#define MemStructId 0x666D + +/* + External interface for the wxMemStruct class. Others are + defined inline within the class def. Here we only need to be able + to add and delete nodes from the list and handle errors in some way. +*/ + +/* + Used for internal "this shouldn't happen" type of errors. +*/ +void wxMemStruct::ErrorMsg (const char * mesg) +{ + wxLogMessage(wxT("wxWidgets memory checking error: %s"), mesg); + PrintNode (); +} + +/* + Used when we find an overwrite or an underwrite error. +*/ +void wxMemStruct::ErrorMsg () +{ + wxLogMessage(wxT("wxWidgets over/underwrite memory error:")); + PrintNode (); +} + + +/* + We want to find out if pointers have been overwritten as soon as is + possible, so test everything before we dereference it. Of course it's still + quite possible that, if things have been overwritten, this function will + fall over, but the only way of dealing with that would cost too much in terms + of time. +*/ +int wxMemStruct::AssertList () +{ + if (wxDebugContext::GetHead () != 0 && ! (wxDebugContext::GetHead ())->AssertIt () || + wxDebugContext::GetTail () != 0 && ! wxDebugContext::GetTail ()->AssertIt ()) { + ErrorMsg ("Head or tail pointers trashed"); + return 0; + } + return 1; +} + + +/* + Check that the thing we're pointing to has the correct id for a wxMemStruct + object and also that it's previous and next pointers are pointing at objects + which have valid ids. + This is definitely not perfect since we could fall over just trying to access + any of the slots which we use here, but I think it's about the best that I + can do without doing something like taking all new wxMemStruct pointers and + comparing them against all known pointer within the list and then only + doing this sort of check _after_ you've found the pointer in the list. That + would be safer, but also much more time consuming. +*/ +int wxMemStruct::AssertIt () +{ + return (m_id == MemStructId && + (m_prev == 0 || m_prev->m_id == MemStructId) && + (m_next == 0 || m_next->m_id == MemStructId)); +} + + +/* + Additions are always at the tail of the list. + Returns 0 on error, non-zero on success. +*/ +int wxMemStruct::Append () +{ + if (! AssertList ()) + return 0; + + if (wxDebugContext::GetHead () == 0) { + if (wxDebugContext::GetTail () != 0) { + ErrorMsg ("Null list should have a null tail pointer"); + return 0; + } + (void) wxDebugContext::SetHead (this); + (void) wxDebugContext::SetTail (this); + } else { + wxDebugContext::GetTail ()->m_next = this; + this->m_prev = wxDebugContext::GetTail (); + (void) wxDebugContext::SetTail (this); + } + return 1; +} + + +/* + Don't actually free up anything here as the space which is used + by the node will be free'd up when the whole block is free'd. + Returns 0 on error, non-zero on success. +*/ +int wxMemStruct::Unlink () +{ + if (! AssertList ()) + return 0; + + if (wxDebugContext::GetHead () == 0 || wxDebugContext::GetTail () == 0) { + ErrorMsg ("Trying to remove node from empty list"); + return 0; + } + + // Handle the part of the list before this node. + if (m_prev == 0) { + if (this != wxDebugContext::GetHead ()) { + ErrorMsg ("No previous node for non-head node"); + return 0; + } + (void) wxDebugContext::SetHead (m_next); + } else { + if (! m_prev->AssertIt ()) { + ErrorMsg ("Trashed previous pointer"); + return 0; + } + + if (m_prev->m_next != this) { + ErrorMsg ("List is inconsistent"); + return 0; + } + m_prev->m_next = m_next; + } + + // Handle the part of the list after this node. + if (m_next == 0) { + if (this != wxDebugContext::GetTail ()) { + ErrorMsg ("No next node for non-tail node"); + return 0; + } + (void) wxDebugContext::SetTail (m_prev); + } else { + if (! m_next->AssertIt ()) { + ErrorMsg ("Trashed next pointer"); + return 0; + } + + if (m_next->m_prev != this) { + ErrorMsg ("List is inconsistent"); + return 0; + } + m_next->m_prev = m_prev; + } + + return 1; +} + + + +/* + Checks a node and block of memory to see that the markers are still + intact. +*/ +int wxMemStruct::CheckBlock () +{ + int nFailures = 0; + + if (m_firstMarker != MemStartCheck) { + nFailures++; + ErrorMsg (); + } + + char * pointer = wxDebugContext::MidMarkerPos ((char *) this); + if (* (wxMarkerType *) pointer != MemMidCheck) { + nFailures++; + ErrorMsg (); + } + + pointer = wxDebugContext::EndMarkerPos ((char *) this, RequestSize ()); + if (* (wxMarkerType *) pointer != MemEndCheck) { + nFailures++; + ErrorMsg (); + } + + return nFailures; +} + + +/* + Check the list of nodes to see if they are all ok. +*/ +int wxMemStruct::CheckAllPrevious () +{ + int nFailures = 0; + + for (wxMemStruct * st = this->m_prev; st != 0; st = st->m_prev) { + if (st->AssertIt ()) + nFailures += st->CheckBlock (); + else + return -1; + } + + return nFailures; +} + + +/* + When we delete a node we set the id slot to a specific value and then test + against this to see if a nodes have been deleted previously. I don't + just set the entire memory to the fillChar because then I'd be overwriting + useful stuff like the vtbl which may be needed to output the error message + including the file name and line numbers. Without this info the whole point + of this class is lost! +*/ +void wxMemStruct::SetDeleted () +{ + m_id = MemFillChar; +} + +int wxMemStruct::IsDeleted () +{ + return (m_id == MemFillChar); +} + + +/* + Print out a single node. There are many far better ways of doing this + but this will suffice for now. +*/ +void wxMemStruct::PrintNode () +{ + if (m_isObject) + { + wxObject *obj = (wxObject *)m_actualData; + wxClassInfo *info = obj->GetClassInfo(); + + // Let's put this in standard form so IDEs can load the file at the appropriate + // line + wxString msg; + + if (m_fileName) + msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); + + if (info && info->GetClassName()) + msg += info->GetClassName(); + else + msg += wxT("object"); + + wxString msg2; + msg2.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize()); + msg += msg2; + + wxLogMessage(msg); + } + else + { + wxString msg; + + if (m_fileName) + msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); + msg += wxT("non-object data"); + wxString msg2; + msg2.Printf(wxT(" at 0x%lX, size %d\n"), (long)GetActualData(), (int)RequestSize()); + msg += msg2; + + wxLogMessage(msg); + } +} + +void wxMemStruct::Dump () +{ + if (!ValidateNode()) return; + + if (m_isObject) + { + wxObject *obj = (wxObject *)m_actualData; + + wxString msg; + if (m_fileName) + msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); + + + /* TODO: We no longer have a stream (using wxLogDebug) so we can't dump it. + * Instead, do what wxObject::Dump does. + * What should we do long-term, eliminate Dumping? Or specify + * that MyClass::Dump should use wxLogDebug? Ugh. + obj->Dump(wxDebugContext::GetStream()); + */ + + if (obj->GetClassInfo() && obj->GetClassInfo()->GetClassName()) + msg += obj->GetClassInfo()->GetClassName(); + else + msg += wxT("unknown object class"); + + wxString msg2; + msg2.Printf(wxT(" at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize()); + msg += msg2; + + wxDebugContext::OutputDumpLine(msg); + } + else + { + wxString msg; + if (m_fileName) + msg.Printf(wxT("%s(%d): "), m_fileName, (int)m_lineNum); + + wxString msg2; + msg2.Printf(wxT("non-object data at 0x%lX, size %d"), (long)GetActualData(), (int)RequestSize() ); + msg += msg2; + wxDebugContext::OutputDumpLine(msg); + } +} + + +/* + Validate a node. Check to see that the node is "clean" in the sense + that nothing has over/underwritten it etc. +*/ +int wxMemStruct::ValidateNode () +{ + char * startPointer = (char *) this; + if (!AssertIt ()) { + if (IsDeleted ()) + ErrorMsg ("Object already deleted"); + else { + // Can't use the error routines as we have no recognisable object. +#ifndef __WXGTK__ + wxLogMessage(wxT("Can't verify memory struct - all bets are off!")); +#endif + } + return 0; + } + +/* + int i; + for (i = 0; i < wxDebugContext::TotSize (requestSize ()); i++) + cout << startPointer [i]; + cout << endl; +*/ + if (Marker () != MemStartCheck) + ErrorMsg (); + if (* (wxMarkerType *) wxDebugContext::MidMarkerPos (startPointer) != MemMidCheck) + ErrorMsg (); + if (* (wxMarkerType *) wxDebugContext::EndMarkerPos (startPointer, + RequestSize ()) != + MemEndCheck) + ErrorMsg (); + + // Back to before the extra buffer and check that + // we can still read what we originally wrote. + if (Marker () != MemStartCheck || + * (wxMarkerType *) wxDebugContext::MidMarkerPos (startPointer) + != MemMidCheck || + * (wxMarkerType *) wxDebugContext::EndMarkerPos (startPointer, + RequestSize ()) != MemEndCheck) + { + ErrorMsg (); + return 0; + } + + return 1; +} + +/* + The wxDebugContext class. +*/ + +wxMemStruct *wxDebugContext::m_head = NULL; +wxMemStruct *wxDebugContext::m_tail = NULL; + +bool wxDebugContext::m_checkPrevious = false; +int wxDebugContext::debugLevel = 1; +bool wxDebugContext::debugOn = true; +wxMemStruct *wxDebugContext::checkPoint = NULL; + +// For faster alignment calculation +static wxMarkerType markerCalc[2]; +int wxDebugContext::m_balign = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]); +int wxDebugContext::m_balignmask = (int)((char *)&markerCalc[1] - (char*)&markerCalc[0]) - 1; + +wxDebugContext::wxDebugContext(void) +{ +} + +wxDebugContext::~wxDebugContext(void) +{ +} + +/* + Work out the positions of the markers by creating an array of 2 markers + and comparing the addresses of the 2 elements. Use this number as the + alignment for markers. +*/ +size_t wxDebugContext::CalcAlignment () +{ + wxMarkerType ar[2]; + return (char *) &ar[1] - (char *) &ar[0]; +} + + +char * wxDebugContext::StructPos (const char * buf) +{ + return (char *) buf; +} + +char * wxDebugContext::MidMarkerPos (const char * buf) +{ + return StructPos (buf) + PaddedSize (sizeof (wxMemStruct)); +} + +char * wxDebugContext::CallerMemPos (const char * buf) +{ + return MidMarkerPos (buf) + PaddedSize (sizeof(wxMarkerType)); +} + + +char * wxDebugContext::EndMarkerPos (const char * buf, const size_t size) +{ + return CallerMemPos (buf) + PaddedSize (size); +} + + +/* + Slightly different as this takes a pointer to the start of the caller + requested region and returns a pointer to the start of the buffer. + */ +char * wxDebugContext::StartPos (const char * caller) +{ + return ((char *) (caller - wxDebugContext::PaddedSize (sizeof(wxMarkerType)) - + wxDebugContext::PaddedSize (sizeof (wxMemStruct)))); +} + +/* + We may need padding between various parts of the allocated memory. + Given a size of memory, this returns the amount of memory which should + be allocated in order to allow for alignment of the following object. + + I don't know how portable this stuff is, but it seems to work for me at + the moment. It would be real nice if I knew more about this! + + // Note: this function is now obsolete (along with CalcAlignment) + // because the calculations are done statically, for greater speed. +*/ +size_t wxDebugContext::GetPadding (const size_t size) +{ + size_t pad = size % CalcAlignment (); + return (pad) ? sizeof(wxMarkerType) - pad : 0; +} + +size_t wxDebugContext::PaddedSize (const size_t size) +{ + // Added by Terry Farnham to replace + // slow GetPadding call. + int padb; + + padb = size & m_balignmask; + if(padb) + return(size + m_balign - padb); + else + return(size); +} + +/* + Returns the total amount of memory which we need to get from the system + in order to satisfy a caller request. This includes space for the struct + plus markers and the caller's memory as well. +*/ +size_t wxDebugContext::TotSize (const size_t reqSize) +{ + return (PaddedSize (sizeof (wxMemStruct)) + PaddedSize (reqSize) + + 2 * sizeof(wxMarkerType)); +} + + +/* + Traverse the list of nodes executing the given function on each node. +*/ +void wxDebugContext::TraverseList (PmSFV func, wxMemStruct *from) +{ + if (!from) + from = wxDebugContext::GetHead (); + + wxMemStruct * st = NULL; + for (st = from; st != 0; st = st->m_next) + { + void* data = st->GetActualData(); +// if ((data != (void*)m_debugStream) && (data != (void*) m_streamBuf)) + if (data != (void*) wxLog::GetActiveTarget()) + { + (st->*func) (); + } + } +} + + +/* + Print out the list. + */ +bool wxDebugContext::PrintList (void) +{ +#ifdef __WXDEBUG__ + TraverseList ((PmSFV)&wxMemStruct::PrintNode, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL)); + + return true; +#else + return false; +#endif +} + +bool wxDebugContext::Dump(void) +{ +#ifdef __WXDEBUG__ + { + wxChar* appName = (wxChar*) wxT("application"); + wxString appNameStr; + if (wxTheApp) + { + appNameStr = wxTheApp->GetAppName(); + appName = WXSTRINGCAST appNameStr; + OutputDumpLine(wxT("----- Memory dump of %s at %s -----"), appName, WXSTRINGCAST wxNow() ); + } + else + { + OutputDumpLine( wxT("----- Memory dump -----") ); + } + } + + TraverseList ((PmSFV)&wxMemStruct::Dump, (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL)); + + OutputDumpLine(wxEmptyString); + OutputDumpLine(wxEmptyString); + + return true; +#else + return false; +#endif +} + +#ifdef __WXDEBUG__ +struct wxDebugStatsStruct +{ + long instanceCount; + long totalSize; + wxChar *instanceClass; + wxDebugStatsStruct *next; +}; + +static wxDebugStatsStruct *FindStatsStruct(wxDebugStatsStruct *st, wxChar *name) +{ + while (st) + { + if (wxStrcmp(st->instanceClass, name) == 0) + return st; + st = st->next; + } + return NULL; +} + +static wxDebugStatsStruct *InsertStatsStruct(wxDebugStatsStruct *head, wxDebugStatsStruct *st) +{ + st->next = head; + return st; +} +#endif + +bool wxDebugContext::PrintStatistics(bool detailed) +{ +#ifdef __WXDEBUG__ + { + wxChar* appName = (wxChar*) wxT("application"); + wxString appNameStr; + if (wxTheApp) + { + appNameStr = wxTheApp->GetAppName(); + appName = WXSTRINGCAST appNameStr; + OutputDumpLine(wxT("----- Memory statistics of %s at %s -----"), appName, WXSTRINGCAST wxNow() ); + } + else + { + OutputDumpLine( wxT("----- Memory statistics -----") ); + } + } + + bool currentMode = GetDebugMode(); + SetDebugMode(false); + + long noNonObjectNodes = 0; + long noObjectNodes = 0; + long totalSize = 0; + + wxDebugStatsStruct *list = NULL; + + wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL ); + if (!from) + from = wxDebugContext::GetHead (); + + wxMemStruct *st; + for (st = from; st != 0; st = st->m_next) + { + void* data = st->GetActualData(); + if (detailed && (data != (void*) wxLog::GetActiveTarget())) + { + wxChar *className = (wxChar*) wxT("nonobject"); + if (st->m_isObject && st->GetActualData()) + { + wxObject *obj = (wxObject *)st->GetActualData(); + if (obj->GetClassInfo()->GetClassName()) + className = (wxChar*)obj->GetClassInfo()->GetClassName(); + } + wxDebugStatsStruct *stats = FindStatsStruct(list, className); + if (!stats) + { + stats = (wxDebugStatsStruct *)malloc(sizeof(wxDebugStatsStruct)); + stats->instanceClass = className; + stats->instanceCount = 0; + stats->totalSize = 0; + list = InsertStatsStruct(list, stats); + } + stats->instanceCount ++; + stats->totalSize += st->RequestSize(); + } + + if (data != (void*) wxLog::GetActiveTarget()) + { + totalSize += st->RequestSize(); + if (st->m_isObject) + noObjectNodes ++; + else + noNonObjectNodes ++; + } + } + + if (detailed) + { + while (list) + { + OutputDumpLine(wxT("%ld objects of class %s, total size %ld"), + list->instanceCount, list->instanceClass, list->totalSize); + wxDebugStatsStruct *old = list; + list = old->next; + free((char *)old); + } + OutputDumpLine(wxEmptyString); + } + + SetDebugMode(currentMode); + + OutputDumpLine(wxT("Number of object items: %ld"), noObjectNodes); + OutputDumpLine(wxT("Number of non-object items: %ld"), noNonObjectNodes); + OutputDumpLine(wxT("Total allocated size: %ld"), totalSize); + OutputDumpLine(wxEmptyString); + OutputDumpLine(wxEmptyString); + + return true; +#else + (void)detailed; + return false; +#endif +} + +bool wxDebugContext::PrintClasses(void) +{ + { + wxChar* appName = (wxChar*) wxT("application"); + wxString appNameStr; + if (wxTheApp) + { + appNameStr = wxTheApp->GetAppName(); + appName = WXSTRINGCAST appNameStr; + wxLogMessage(wxT("----- Classes in %s -----"), appName); + } + } + + int n = 0; + wxHashTable::compatibility_iterator node; + wxClassInfo *info; + + wxClassInfo::sm_classTable->BeginFind(); + node = wxClassInfo::sm_classTable->Next(); + while (node) + { + info = (wxClassInfo *)node->GetData(); + if (info->GetClassName()) + { + wxString msg(info->GetClassName()); + msg += wxT(" "); + + if (info->GetBaseClassName1() && !info->GetBaseClassName2()) + { + msg += wxT("is a "); + msg += info->GetBaseClassName1(); + } + else if (info->GetBaseClassName1() && info->GetBaseClassName2()) + { + msg += wxT("is a "); + msg += info->GetBaseClassName1() ; + msg += wxT(", "); + msg += info->GetBaseClassName2() ; + } + if (info->GetConstructor()) + msg += wxT(": dynamic"); + + wxLogMessage(msg); + } + node = wxClassInfo::sm_classTable->Next(); + n ++; + } + wxLogMessage(wxEmptyString); + wxLogMessage(wxT("There are %d classes derived from wxObject."), n); + wxLogMessage(wxEmptyString); + wxLogMessage(wxEmptyString); + return true; +} + +void wxDebugContext::SetCheckpoint(bool all) +{ + if (all) + checkPoint = NULL; + else + checkPoint = m_tail; +} + +// Checks all nodes since checkpoint, or since start. +int wxDebugContext::Check(bool checkAll) +{ + int nFailures = 0; + + wxMemStruct *from = (checkPoint ? checkPoint->m_next : (wxMemStruct*)NULL ); + if (!from || checkAll) + from = wxDebugContext::GetHead (); + + for (wxMemStruct * st = from; st != 0; st = st->m_next) + { + if (st->AssertIt ()) + nFailures += st->CheckBlock (); + else + return -1; + } + + return nFailures; +} + +// Count the number of non-wxDebugContext-related objects +// that are outstanding +int wxDebugContext::CountObjectsLeft(bool sinceCheckpoint) +{ + int n = 0; + + wxMemStruct *from = NULL; + if (sinceCheckpoint && checkPoint) + from = checkPoint->m_next; + else + from = wxDebugContext::GetHead () ; + + for (wxMemStruct * st = from; st != 0; st = st->m_next) + { + void* data = st->GetActualData(); + if (data != (void*) wxLog::GetActiveTarget()) + n ++; + } + + return n ; +} + +// This function is used to output the dump +void wxDebugContext::OutputDumpLine(const wxChar *szFormat, ...) +{ + // a buffer of 2048 bytes should be long enough for a file name + // and a class name + wxChar buf[2048]; + int count; + va_list argptr; + va_start(argptr, szFormat); + buf[sizeof(buf)/sizeof(wxChar)-1] = _T('\0'); + + // keep 3 bytes for a \r\n\0 + count = wxVsnprintf(buf, sizeof(buf)/sizeof(wxChar)-3, szFormat, argptr); + + if ( count < 0 ) + count = sizeof(buf)/sizeof(wxChar)-3; + buf[count]=_T('\r'); + buf[count+1]=_T('\n'); + buf[count+2]=_T('\0'); + + wxMessageOutputDebug dbgout; + dbgout.Printf(buf); +} + + +#if USE_THREADSAFE_MEMORY_ALLOCATION +static bool memSectionOk = false; + +class MemoryCriticalSection : public wxCriticalSection +{ +public: + MemoryCriticalSection() { + memSectionOk = true; + } + ~MemoryCriticalSection() { + memSectionOk = false; + } +}; + +class MemoryCriticalSectionLocker +{ +public: + inline MemoryCriticalSectionLocker(wxCriticalSection& critsect) + : m_critsect(critsect), m_locked(memSectionOk) { if(m_locked) m_critsect.Enter(); } + inline ~MemoryCriticalSectionLocker() { if(m_locked) m_critsect.Leave(); } + +private: + // no assignment operator nor copy ctor + MemoryCriticalSectionLocker(const MemoryCriticalSectionLocker&); + MemoryCriticalSectionLocker& operator=(const MemoryCriticalSectionLocker&); + + wxCriticalSection& m_critsect; + bool m_locked; +}; + +static MemoryCriticalSection memLocker; + +#endif // USE_THREADSAFE_MEMORY_ALLOCATION + + +#ifdef __WXDEBUG__ +#if !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE))) +#if wxUSE_GLOBAL_MEMORY_OPERATORS +void * operator new (size_t size, wxChar * fileName, int lineNum) +{ + return wxDebugAlloc(size, fileName, lineNum, false, false); +} + +void * operator new (size_t size) +{ + return wxDebugAlloc(size, NULL, 0, false); +} + +void operator delete (void * buf) +{ + wxDebugFree(buf, false); +} + +#if wxUSE_ARRAY_MEMORY_OPERATORS +void * operator new[] (size_t size) +{ + return wxDebugAlloc(size, NULL, 0, false, true); +} + +void * operator new[] (size_t size, wxChar * fileName, int lineNum) +{ + return wxDebugAlloc(size, fileName, lineNum, false, true); +} + +void operator delete[] (void * buf) +{ + wxDebugFree(buf, true); +} +#endif // wxUSE_ARRAY_MEMORY_OPERATORS +#endif // wxUSE_GLOBAL_MEMORY_OPERATORS +#endif // !(defined(__WXMSW__) && (defined(WXUSINGDLL) || defined(WXMAKINGDLL_BASE))) + +// TODO: store whether this is a vector or not. +void * wxDebugAlloc(size_t size, wxChar * fileName, int lineNum, bool isObject, bool WXUNUSED(isVect) ) +{ +#if USE_THREADSAFE_MEMORY_ALLOCATION + MemoryCriticalSectionLocker lock(memLocker); +#endif + + // If not in debugging allocation mode, do the normal thing + // so we don't leave any trace of ourselves in the node list. + +#if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ) +// VA 3.0 still has trouble in here + return (void *)malloc(size); +#endif + if (!wxDebugContext::GetDebugMode()) + { + return (void *)malloc(size); + } + + int totSize = wxDebugContext::TotSize (size); + char * buf = (char *) malloc(totSize); + if (!buf) { + wxLogMessage(wxT("Call to malloc (%ld) failed."), (long)size); + return 0; + } + wxMemStruct * st = (wxMemStruct *)buf; + st->m_firstMarker = MemStartCheck; + st->m_reqSize = size; + st->m_fileName = fileName; + st->m_lineNum = lineNum; + st->m_id = MemStructId; + st->m_prev = 0; + st->m_next = 0; + st->m_isObject = isObject; + + // Errors from Append() shouldn't really happen - but just in case! + if (st->Append () == 0) { + st->ErrorMsg ("Trying to append new node"); + } + + if (wxDebugContext::GetCheckPrevious ()) { + if (st->CheckAllPrevious () < 0) { + st->ErrorMsg ("Checking previous nodes"); + } + } + + // Set up the extra markers at the middle and end. + char * ptr = wxDebugContext::MidMarkerPos (buf); + * (wxMarkerType *) ptr = MemMidCheck; + ptr = wxDebugContext::EndMarkerPos (buf, size); + * (wxMarkerType *) ptr = MemEndCheck; + + // pointer returned points to the start of the caller's + // usable area. + void *m_actualData = (void *) wxDebugContext::CallerMemPos (buf); + st->m_actualData = m_actualData; + + return m_actualData; +} + +// TODO: check whether was allocated as a vector +void wxDebugFree(void * buf, bool WXUNUSED(isVect) ) +{ +#if USE_THREADSAFE_MEMORY_ALLOCATION + MemoryCriticalSectionLocker lock(memLocker); +#endif + + if (!buf) + return; + +#if defined(__VISAGECPP__) && (__IBMCPP__ < 400 || __IBMC__ < 400 ) +// VA 3.0 still has trouble in here + free((char *)buf); +#endif + // If not in debugging allocation mode, do the normal thing + // so we don't leave any trace of ourselves in the node list. + if (!wxDebugContext::GetDebugMode()) + { + free((char *)buf); + return; + } + + // Points to the start of the entire allocated area. + char * startPointer = wxDebugContext::StartPos ((char *) buf); + // Find the struct and make sure that it's identifiable. + wxMemStruct * st = (wxMemStruct *) wxDebugContext::StructPos (startPointer); + + if (! st->ValidateNode ()) + return; + + // If this is the current checkpoint, we need to + // move the checkpoint back so it points to a valid + // node. + if (st == wxDebugContext::checkPoint) + wxDebugContext::checkPoint = wxDebugContext::checkPoint->m_prev; + + if (! st->Unlink ()) + { + st->ErrorMsg ("Unlinking deleted node"); + } + + // Now put in the fill char into the id slot and the caller requested + // memory locations. + st->SetDeleted (); + (void) memset (wxDebugContext::CallerMemPos (startPointer), MemFillChar, + st->RequestSize ()); + + free((char *)st); +} + +#endif // __WXDEBUG__ + +// Trace: send output to the current debugging stream +void wxTrace(const wxChar * ...) +{ +#if 1 + wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead.")); +#else + va_list ap; + static wxChar buffer[512]; + + va_start(ap, fmt); + +#ifdef __WXMSW__ + wvsprintf(buffer,fmt,ap) ; +#else + vsprintf(buffer,fmt,ap) ; +#endif + + va_end(ap); + + if (wxDebugContext::HasStream()) + { + wxDebugContext::GetStream() << buffer; + wxDebugContext::GetStream().flush(); + } + else +#ifdef __WXMSW__ +#ifdef __WIN32__ + OutputDebugString((LPCTSTR)buffer) ; +#else + OutputDebugString((const char*) buffer) ; +#endif +#else + fprintf(stderr, buffer); +#endif +#endif +} + +// Trace with level +void wxTraceLevel(int, const wxChar * ...) +{ +#if 1 + wxFAIL_MSG(wxT("wxTrace is now obsolete. Please use wxDebugXXX instead.")); +#else + if (wxDebugContext::GetLevel() < level) + return; + + va_list ap; + static wxChar buffer[512]; + + va_start(ap, fmt); + +#ifdef __WXMSW__ + wxWvsprintf(buffer,fmt,ap) ; +#else + vsprintf(buffer,fmt,ap) ; +#endif + + va_end(ap); + + if (wxDebugContext::HasStream()) + { + wxDebugContext::GetStream() << buffer; + wxDebugContext::GetStream().flush(); + } + else +#ifdef __WXMSW__ +#ifdef __WIN32__ + OutputDebugString((LPCTSTR)buffer) ; +#else + OutputDebugString((const char*) buffer) ; +#endif +#else + fprintf(stderr, buffer); +#endif +#endif +} + +//---------------------------------------------------------------------------- +// Final cleanup after all global objects in all files have been destroyed +//---------------------------------------------------------------------------- + +// Don't set it to 0 by dynamic initialization +// Some compilers will really do the assignment later +// All global variables are initialized to 0 at the very beginning, and this is just fine. +int wxDebugContextDumpDelayCounter::sm_count; + +void wxDebugContextDumpDelayCounter::DoDump() +{ + if (wxDebugContext::CountObjectsLeft(true) > 0) + { + wxDebugContext::OutputDumpLine(wxT("There were memory leaks.\n")); + wxDebugContext::Dump(); + wxDebugContext::PrintStatistics(); + } +} + +// Even if there is nothing else, make sure that there is at +// least one cleanup counter object +static wxDebugContextDumpDelayCounter wxDebugContextDumpDelayCounter_One; + +#endif // (defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING) || wxUSE_DEBUG_CONTEXT diff --git a/Source/3rd Party/wx/src/common/menucmn.cpp b/Source/3rd Party/wx/src/common/menucmn.cpp index 1e2e514db..145fe9b01 100644 --- a/Source/3rd Party/wx/src/common/menucmn.cpp +++ b/Source/3rd Party/wx/src/common/menucmn.cpp @@ -1,1173 +1,1173 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/menucmn.cpp -// Purpose: wxMenu and wxMenuBar methods common to all ports -// Author: Vadim Zeitlin -// Modified by: -// Created: 26.10.99 -// RCS-ID: $Id: menucmn.cpp 57852 2009-01-06 09:40:34Z SC $ -// Copyright: (c) 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_MENUS - -#include - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/menu.h" -#endif - -#include "wx/stockitem.h" - -// ---------------------------------------------------------------------------- -// template lists -// ---------------------------------------------------------------------------- - -#include "wx/listimpl.cpp" - -WX_DEFINE_LIST(wxMenuList) -WX_DEFINE_LIST(wxMenuItemList) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxAcceleratorEntry -// ---------------------------------------------------------------------------- - - -#if wxUSE_ACCEL - -static const struct wxKeyName -{ - wxKeyCode code; - const wxChar *name; -} wxKeyNames[] = -{ - { WXK_DELETE, wxTRANSLATE("DEL") }, - { WXK_DELETE, wxTRANSLATE("DELETE") }, - { WXK_BACK, wxTRANSLATE("BACK") }, - { WXK_INSERT, wxTRANSLATE("INS") }, - { WXK_INSERT, wxTRANSLATE("INSERT") }, - { WXK_RETURN, wxTRANSLATE("ENTER") }, - { WXK_RETURN, wxTRANSLATE("RETURN") }, - { WXK_PAGEUP, wxTRANSLATE("PGUP") }, - { WXK_PAGEDOWN, wxTRANSLATE("PGDN") }, - { WXK_LEFT, wxTRANSLATE("LEFT") }, - { WXK_RIGHT, wxTRANSLATE("RIGHT") }, - { WXK_UP, wxTRANSLATE("UP") }, - { WXK_DOWN, wxTRANSLATE("DOWN") }, - { WXK_HOME, wxTRANSLATE("HOME") }, - { WXK_END, wxTRANSLATE("END") }, - { WXK_SPACE, wxTRANSLATE("SPACE") }, - { WXK_TAB, wxTRANSLATE("TAB") }, - { WXK_ESCAPE, wxTRANSLATE("ESC") }, - { WXK_ESCAPE, wxTRANSLATE("ESCAPE") }, - { WXK_CANCEL, wxTRANSLATE("CANCEL") }, - { WXK_CLEAR, wxTRANSLATE("CLEAR") }, - { WXK_MENU, wxTRANSLATE("MENU") }, - { WXK_PAUSE, wxTRANSLATE("PAUSE") }, - { WXK_CAPITAL, wxTRANSLATE("CAPITAL") }, - { WXK_SELECT, wxTRANSLATE("SELECT") }, - { WXK_PRINT, wxTRANSLATE("PRINT") }, - { WXK_EXECUTE, wxTRANSLATE("EXECUTE") }, - { WXK_SNAPSHOT, wxTRANSLATE("SNAPSHOT") }, - { WXK_HELP, wxTRANSLATE("HELP") }, - { WXK_ADD, wxTRANSLATE("ADD") }, - { WXK_SEPARATOR, wxTRANSLATE("SEPARATOR") }, - { WXK_SUBTRACT, wxTRANSLATE("SUBTRACT") }, - { WXK_DECIMAL, wxTRANSLATE("DECIMAL") }, - { WXK_DIVIDE, wxTRANSLATE("DIVIDE") }, - { WXK_NUMLOCK, wxTRANSLATE("NUM_LOCK") }, - { WXK_SCROLL, wxTRANSLATE("SCROLL_LOCK") }, - { WXK_PAGEUP, wxTRANSLATE("PAGEUP") }, - { WXK_PAGEDOWN, wxTRANSLATE("PAGEDOWN") }, - { WXK_NUMPAD_SPACE, wxTRANSLATE("KP_SPACE") }, - { WXK_NUMPAD_TAB, wxTRANSLATE("KP_TAB") }, - { WXK_NUMPAD_ENTER, wxTRANSLATE("KP_ENTER") }, - { WXK_NUMPAD_HOME, wxTRANSLATE("KP_HOME") }, - { WXK_NUMPAD_LEFT, wxTRANSLATE("KP_LEFT") }, - { WXK_NUMPAD_UP, wxTRANSLATE("KP_UP") }, - { WXK_NUMPAD_RIGHT, wxTRANSLATE("KP_RIGHT") }, - { WXK_NUMPAD_DOWN, wxTRANSLATE("KP_DOWN") }, - { WXK_NUMPAD_PAGEUP, wxTRANSLATE("KP_PRIOR") }, - { WXK_NUMPAD_PAGEUP, wxTRANSLATE("KP_PAGEUP") }, - { WXK_NUMPAD_PAGEDOWN, wxTRANSLATE("KP_NEXT") }, - { WXK_NUMPAD_PAGEDOWN, wxTRANSLATE("KP_PAGEDOWN") }, - { WXK_NUMPAD_END, wxTRANSLATE("KP_END") }, - { WXK_NUMPAD_BEGIN, wxTRANSLATE("KP_BEGIN") }, - { WXK_NUMPAD_INSERT, wxTRANSLATE("KP_INSERT") }, - { WXK_NUMPAD_DELETE, wxTRANSLATE("KP_DELETE") }, - { WXK_NUMPAD_EQUAL, wxTRANSLATE("KP_EQUAL") }, - { WXK_NUMPAD_MULTIPLY, wxTRANSLATE("KP_MULTIPLY") }, - { WXK_NUMPAD_ADD, wxTRANSLATE("KP_ADD") }, - { WXK_NUMPAD_SEPARATOR, wxTRANSLATE("KP_SEPARATOR") }, - { WXK_NUMPAD_SUBTRACT, wxTRANSLATE("KP_SUBTRACT") }, - { WXK_NUMPAD_DECIMAL, wxTRANSLATE("KP_DECIMAL") }, - { WXK_NUMPAD_DIVIDE, wxTRANSLATE("KP_DIVIDE") }, - { WXK_WINDOWS_LEFT, wxTRANSLATE("WINDOWS_LEFT") }, - { WXK_WINDOWS_RIGHT, wxTRANSLATE("WINDOWS_RIGHT") }, - { WXK_WINDOWS_MENU, wxTRANSLATE("WINDOWS_MENU") }, - { WXK_COMMAND, wxTRANSLATE("COMMAND") }, -}; - -// return true if the 2 strings refer to the same accel -// -// as accels can be either translated or not, check for both possibilities and -// also compare case-insensitively as the key names case doesn't count -static inline bool CompareAccelString(const wxString& str, const wxChar *accel) -{ - return str.CmpNoCase(accel) == 0 -#if wxUSE_INTL - || str.CmpNoCase(wxGetTranslation(accel)) == 0 -#endif - ; -} - -// return prefixCode+number if the string is of the form "" and -// 0 if it isn't -// -// first and last parameter specify the valid domain for "number" part -static int - IsNumberedAccelKey(const wxString& str, - const wxChar *prefix, - wxKeyCode prefixCode, - unsigned first, - unsigned last) -{ - const size_t lenPrefix = wxStrlen(prefix); - if ( !CompareAccelString(str.Left(lenPrefix), prefix) ) - return 0; - - unsigned long num; - if ( !str.Mid(lenPrefix).ToULong(&num) ) - return 0; - - if ( num < first || num > last ) - { - // this must be a mistake, chances that this is a valid name of another - // key are vanishingly small - wxLogDebug(_T("Invalid key string \"%s\""), str.c_str()); - return 0; - } - - return prefixCode + num - first; -} - -/* static */ -bool -wxAcceleratorEntry::ParseAccel(const wxString& text, int *flagsOut, int *keyOut) -{ - // the parser won't like trailing spaces - wxString label = text; - label.Trim(true); // the initial \t must be preserved so don't strip leading whitespaces - - // check for accelerators: they are given after '\t' - int posTab = label.Find(wxT('\t')); - if ( posTab == wxNOT_FOUND ) - { - return false; - } - - // parse the accelerator string - int accelFlags = wxACCEL_NORMAL; - wxString current; - for ( size_t n = (size_t)posTab + 1; n < label.length(); n++ ) - { - if ( (label[n] == '+') || (label[n] == '-') ) - { - // differentiate between a ctrl that will be translated to cmd on mac - // and an explicit xctrl that will not be translated and remains a ctrl - if ( CompareAccelString(current, wxTRANSLATE("ctrl")) ) - accelFlags |= wxACCEL_CMD; - else if ( CompareAccelString(current, wxTRANSLATE("xctrl")) ) - accelFlags |= wxACCEL_CTRL; - else if ( CompareAccelString(current, wxTRANSLATE("alt")) ) - accelFlags |= wxACCEL_ALT; - else if ( CompareAccelString(current, wxTRANSLATE("shift")) ) - accelFlags |= wxACCEL_SHIFT; - else // not a recognized modifier name - { - // we may have "Ctrl-+", for example, but we still want to - // catch typos like "Crtl-A" so only give the warning if we - // have something before the current '+' or '-', else take - // it as a literal symbol - if ( current.empty() ) - { - current += label[n]; - - // skip clearing it below - continue; - } - else - { - wxLogDebug(wxT("Unknown accel modifier: '%s'"), - current.c_str()); - } - } - - current.clear(); - } - else // not special character - { - current += (wxChar) wxTolower(label[n]); - } - } - - int keyCode; - const size_t len = current.length(); - switch ( len ) - { - case 0: - wxLogDebug(wxT("No accel key found, accel string ignored.")); - return false; - - case 1: - // it's just a letter - keyCode = current[0U]; - - // if the key is used with any modifiers, make it an uppercase one - // because Ctrl-A and Ctrl-a are the same; but keep it as is if it's - // used alone as 'a' and 'A' are different - if ( accelFlags != wxACCEL_NORMAL ) - keyCode = wxToupper(keyCode); - break; - - default: - keyCode = IsNumberedAccelKey(current, wxTRANSLATE("F"), - WXK_F1, 1, 12); - if ( !keyCode ) - { - for ( size_t n = 0; n < WXSIZEOF(wxKeyNames); n++ ) - { - const wxKeyName& kn = wxKeyNames[n]; - if ( CompareAccelString(current, kn.name) ) - { - keyCode = kn.code; - break; - } - } - } - - if ( !keyCode ) - keyCode = IsNumberedAccelKey(current, wxTRANSLATE("KP_"), - WXK_NUMPAD0, 0, 9); - if ( !keyCode ) - keyCode = IsNumberedAccelKey(current, wxTRANSLATE("SPECIAL"), - WXK_SPECIAL1, 1, 20); - - if ( !keyCode ) - { - wxLogDebug(wxT("Unrecognized accel key '%s', accel string ignored."), - current.c_str()); - return false; - } - } - - - wxASSERT_MSG( keyCode, _T("logic error: should have key code here") ); - - if ( flagsOut ) - *flagsOut = accelFlags; - if ( keyOut ) - *keyOut = keyCode; - - return true; -} - -/* static */ -wxAcceleratorEntry *wxAcceleratorEntry::Create(const wxString& str) -{ - int flags, - keyCode; - if ( !ParseAccel(str, &flags, &keyCode) ) - return NULL; - - return new wxAcceleratorEntry(flags, keyCode); -} - -bool wxAcceleratorEntry::FromString(const wxString& str) -{ - return ParseAccel(str, &m_flags, &m_keyCode); -} - -wxString wxAcceleratorEntry::ToString() const -{ - wxString text; - - int flags = GetFlags(); - if ( flags & wxACCEL_ALT ) - text += _("Alt-"); - if ( flags & wxACCEL_CMD ) - text += _("Ctrl-"); -#ifdef __WXMAC__ - if ( flags & wxACCEL_CTRL ) - text += _("XCtrl-"); -#endif - if ( flags & wxACCEL_SHIFT ) - text += _("Shift-"); - - const int code = GetKeyCode(); - - if ( code >= WXK_F1 && code <= WXK_F12 ) - text << _("F") << code - WXK_F1 + 1; - else if ( code >= WXK_NUMPAD0 && code <= WXK_NUMPAD9 ) - text << _("KP_") << code - WXK_NUMPAD0; - else if ( code >= WXK_SPECIAL1 && code <= WXK_SPECIAL20 ) - text << _("SPECIAL") << code - WXK_SPECIAL1 + 1; - else // check the named keys - { - size_t n; - for ( n = 0; n < WXSIZEOF(wxKeyNames); n++ ) - { - const wxKeyName& kn = wxKeyNames[n]; - if ( code == kn.code ) - { - text << wxGetTranslation(kn.name); - break; - } - } - - if ( n == WXSIZEOF(wxKeyNames) ) - { - // must be a simple key - if ( -#if !wxUSE_UNICODE - isascii(code) && -#endif // ANSI - wxIsalnum(code) ) - { - text << (wxChar)code; - } - else - { - wxFAIL_MSG( wxT("unknown keyboard accelerator code") ); - } - } - } - - return text; -} - -wxAcceleratorEntry *wxGetAccelFromString(const wxString& label) -{ - return wxAcceleratorEntry::Create(label); -} - -#endif // wxUSE_ACCEL - - -// ---------------------------------------------------------------------------- -// wxMenuItem -// ---------------------------------------------------------------------------- - -wxMenuItemBase::wxMenuItemBase(wxMenu *parentMenu, - int id, - const wxString& text, - const wxString& help, - wxItemKind kind, - wxMenu *subMenu) -{ - wxASSERT_MSG( parentMenu != NULL, wxT("menuitem should have a menu") ); - - m_parentMenu = parentMenu; - m_subMenu = subMenu; - m_isEnabled = true; - m_isChecked = false; - m_id = id; - m_kind = kind; - if (m_id == wxID_ANY) - m_id = wxNewId(); - if (m_id == wxID_SEPARATOR) - m_kind = wxITEM_SEPARATOR; - - SetText(text); - SetHelp(help); -} - -wxMenuItemBase::~wxMenuItemBase() -{ - delete m_subMenu; -} - -#if wxUSE_ACCEL - -wxAcceleratorEntry *wxMenuItemBase::GetAccel() const -{ - return wxAcceleratorEntry::Create(GetText()); -} - -void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel) -{ - wxString text = m_text.BeforeFirst(wxT('\t')); - if ( accel ) - { - text += wxT('\t'); - text += accel->ToString(); - } - - SetText(text); -} - -#endif // wxUSE_ACCEL - -void wxMenuItemBase::SetText(const wxString& str) -{ - m_text = str; - - if ( m_text.empty() && !IsSeparator() ) - { - wxASSERT_MSG( wxIsStockID(GetId()), - wxT("A non-stock menu item with an empty label?") ); - m_text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR | - wxSTOCK_WITH_MNEMONIC); - } -} - -void wxMenuItemBase::SetHelp(const wxString& str) -{ - m_help = str; - - if ( m_help.empty() && !IsSeparator() && wxIsStockID(GetId()) ) - { - // get a stock help string - m_help = wxGetStockHelpString(GetId()); - } -} - -wxString wxMenuItemBase::GetLabelText(const wxString& label) -{ - return GetLabelFromText(label); -} - -bool wxMenuBase::ms_locked = true; - -// ---------------------------------------------------------------------------- -// wxMenu ctor and dtor -// ---------------------------------------------------------------------------- - -void wxMenuBase::Init(long style) -{ - m_menuBar = (wxMenuBar *)NULL; - m_menuParent = (wxMenu *)NULL; - - m_invokingWindow = (wxWindow *)NULL; - m_style = style; - m_clientData = (void *)NULL; - m_eventHandler = this; -} - -wxMenuBase::~wxMenuBase() -{ - WX_CLEAR_LIST(wxMenuItemList, m_items); -} - -// ---------------------------------------------------------------------------- -// wxMenu item adding/removing -// ---------------------------------------------------------------------------- - -void wxMenuBase::AddSubMenu(wxMenu *submenu) -{ - wxCHECK_RET( submenu, _T("can't add a NULL submenu") ); - - submenu->SetParent((wxMenu *)this); -} - -wxMenuItem* wxMenuBase::DoAppend(wxMenuItem *item) -{ - wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Append()") ); - - m_items.Append(item); - item->SetMenu((wxMenu*)this); - if ( item->IsSubMenu() ) - { - AddSubMenu(item->GetSubMenu()); - } - - return item; -} - -wxMenuItem* wxMenuBase::Insert(size_t pos, wxMenuItem *item) -{ - wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert") ); - - if ( pos == GetMenuItemCount() ) - { - return DoAppend(item); - } - else - { - wxCHECK_MSG( pos < GetMenuItemCount(), NULL, - wxT("invalid index in wxMenu::Insert") ); - - return DoInsert(pos, item); - } -} - -wxMenuItem* wxMenuBase::DoInsert(size_t pos, wxMenuItem *item) -{ - wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert()") ); - - wxMenuItemList::compatibility_iterator node = m_items.Item(pos); - wxCHECK_MSG( node, NULL, wxT("invalid index in wxMenu::Insert()") ); - - m_items.Insert(node, item); - item->SetMenu((wxMenu*)this); - if ( item->IsSubMenu() ) - { - AddSubMenu(item->GetSubMenu()); - } - - return item; -} - -wxMenuItem *wxMenuBase::Remove(wxMenuItem *item) -{ - wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Remove") ); - - return DoRemove(item); -} - -wxMenuItem *wxMenuBase::DoRemove(wxMenuItem *item) -{ - wxMenuItemList::compatibility_iterator node = m_items.Find(item); - - // if we get here, the item is valid or one of Remove() functions is broken - wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") ); - - // we detach the item, but we do delete the list node (i.e. don't call - // DetachNode() here!) - m_items.Erase(node); - - // item isn't attached to anything any more - item->SetMenu((wxMenu *)NULL); - wxMenu *submenu = item->GetSubMenu(); - if ( submenu ) - { - submenu->SetParent((wxMenu *)NULL); - if ( submenu->IsAttached() ) - submenu->Detach(); - } - - return item; -} - -bool wxMenuBase::Delete(wxMenuItem *item) -{ - wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Delete") ); - - return DoDelete(item); -} - -bool wxMenuBase::DoDelete(wxMenuItem *item) -{ - wxMenuItem *item2 = DoRemove(item); - wxCHECK_MSG( item2, false, wxT("failed to delete menu item") ); - - // don't delete the submenu - item2->SetSubMenu((wxMenu *)NULL); - - delete item2; - - return true; -} - -bool wxMenuBase::Destroy(wxMenuItem *item) -{ - wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Destroy") ); - - return DoDestroy(item); -} - -bool wxMenuBase::DoDestroy(wxMenuItem *item) -{ - wxMenuItem *item2 = DoRemove(item); - wxCHECK_MSG( item2, false, wxT("failed to delete menu item") ); - - delete item2; - - return true; -} - -// ---------------------------------------------------------------------------- -// wxMenu searching for items -// ---------------------------------------------------------------------------- - -// Finds the item id matching the given string, wxNOT_FOUND if not found. -int wxMenuBase::FindItem(const wxString& text) const -{ - wxString label = wxMenuItem::GetLabelFromText(text); - for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst(); - node; - node = node->GetNext() ) - { - wxMenuItem *item = node->GetData(); - if ( item->IsSubMenu() ) - { - int rc = item->GetSubMenu()->FindItem(label); - if ( rc != wxNOT_FOUND ) - return rc; - } - - // we execute this code for submenus as well to alllow finding them by - // name just like the ordinary items - if ( !item->IsSeparator() ) - { - if ( item->GetLabel() == label ) - return item->GetId(); - } - } - - return wxNOT_FOUND; -} - -// recursive search for item by id -wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const -{ - if ( itemMenu ) - *itemMenu = NULL; - - wxMenuItem *item = NULL; - for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst(); - node && !item; - node = node->GetNext() ) - { - item = node->GetData(); - - if ( item->GetId() == itemId ) - { - if ( itemMenu ) - *itemMenu = (wxMenu *)this; - } - else if ( item->IsSubMenu() ) - { - item = item->GetSubMenu()->FindItem(itemId, itemMenu); - } - else - { - // don't exit the loop - item = NULL; - } - } - - return item; -} - -// non recursive search -wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const -{ - wxMenuItem *item = (wxMenuItem *)NULL; - wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst(); - - size_t pos; - for ( pos = 0; node; pos++ ) - { - if ( node->GetData()->GetId() == id ) - { - item = node->GetData(); - - break; - } - - node = node->GetNext(); - } - - if ( ppos ) - { - *ppos = item ? pos : (size_t)wxNOT_FOUND; - } - - return item; -} - -// find by position -wxMenuItem* wxMenuBase::FindItemByPosition(size_t position) const -{ - wxCHECK_MSG( position < m_items.GetCount(), NULL, - _T("wxMenu::FindItemByPosition(): invalid menu index") ); - - return m_items.Item( position )->GetData(); -} - -// ---------------------------------------------------------------------------- -// wxMenu helpers used by derived classes -// ---------------------------------------------------------------------------- - -// Update a menu and all submenus recursively. source is the object that has -// the update event handlers defined for it. If NULL, the menu or associated -// window will be used. -void wxMenuBase::UpdateUI(wxEvtHandler* source) -{ - if (GetInvokingWindow()) - { - // Don't update menus if the parent - // frame is about to get deleted - wxWindow *tlw = wxGetTopLevelParent( GetInvokingWindow() ); - if (tlw && wxPendingDelete.Member(tlw)) - return; - } - - if ( !source && GetInvokingWindow() ) - source = GetInvokingWindow()->GetEventHandler(); - if ( !source ) - source = GetEventHandler(); - if ( !source ) - source = this; - - wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst(); - while ( node ) - { - wxMenuItem* item = node->GetData(); - if ( !item->IsSeparator() ) - { - wxWindowID id = item->GetId(); - wxUpdateUIEvent event(id); - event.SetEventObject( source ); - - if ( source->ProcessEvent(event) ) - { - // if anything changed, update the changed attribute - if (event.GetSetText()) - SetLabel(id, event.GetText()); - if (event.GetSetChecked()) - Check(id, event.GetChecked()); - if (event.GetSetEnabled()) - Enable(id, event.GetEnabled()); - } - - // recurse to the submenus - if ( item->GetSubMenu() ) - item->GetSubMenu()->UpdateUI(source); - } - //else: item is a separator (which doesn't process update UI events) - - node = node->GetNext(); - } -} - -bool wxMenuBase::SendEvent(int id, int checked) -{ - wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id); - event.SetEventObject(this); - event.SetInt(checked); - - bool processed = false; - - // Try the menu's event handler - // if ( !processed ) - { - wxEvtHandler *handler = GetEventHandler(); - if ( handler ) - processed = handler->ProcessEvent(event); - } - - // Try the window the menu was popped up from (and up through the - // hierarchy) - if ( !processed ) - { - const wxMenuBase *menu = this; - while ( menu ) - { - wxWindow *win = menu->GetInvokingWindow(); - if ( win ) - { - processed = win->GetEventHandler()->ProcessEvent(event); - break; - } - - menu = menu->GetParent(); - } - } - - return processed; -} - -// ---------------------------------------------------------------------------- -// wxMenu attaching/detaching to/from menu bar -// ---------------------------------------------------------------------------- - -wxMenuBar* wxMenuBase::GetMenuBar() const -{ - if(GetParent()) - return GetParent()->GetMenuBar(); - return m_menuBar; -} - -void wxMenuBase::Attach(wxMenuBarBase *menubar) -{ - // use Detach() instead! - wxASSERT_MSG( menubar, _T("menu can't be attached to NULL menubar") ); - - // use IsAttached() to prevent this from happening - wxASSERT_MSG( !m_menuBar, _T("attaching menu twice?") ); - - m_menuBar = (wxMenuBar *)menubar; -} - -void wxMenuBase::Detach() -{ - // use IsAttached() to prevent this from happening - wxASSERT_MSG( m_menuBar, _T("detaching unattached menu?") ); - - m_menuBar = NULL; -} - -// ---------------------------------------------------------------------------- -// wxMenu functions forwarded to wxMenuItem -// ---------------------------------------------------------------------------- - -void wxMenuBase::Enable( int id, bool enable ) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") ); - - item->Enable(enable); -} - -bool wxMenuBase::IsEnabled( int id ) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, false, wxT("wxMenu::IsEnabled: no such item") ); - - return item->IsEnabled(); -} - -void wxMenuBase::Check( int id, bool enable ) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenu::Check: no such item") ); - - item->Check(enable); -} - -bool wxMenuBase::IsChecked( int id ) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, false, wxT("wxMenu::IsChecked: no such item") ); - - return item->IsChecked(); -} - -void wxMenuBase::SetLabel( int id, const wxString &label ) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") ); - - item->SetText(label); -} - -wxString wxMenuBase::GetLabel( int id ) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetLabel: no such item") ); - - return item->GetText(); -} - -void wxMenuBase::SetHelpString( int id, const wxString& helpString ) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") ); - - item->SetHelp( helpString ); -} - -wxString wxMenuBase::GetHelpString( int id ) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetHelpString: no such item") ); - - return item->GetHelp(); -} - -// ---------------------------------------------------------------------------- -// wxMenuBarBase ctor and dtor -// ---------------------------------------------------------------------------- - -wxMenuBarBase::wxMenuBarBase() -{ - // not attached yet - m_menuBarFrame = NULL; -} - -wxMenuBarBase::~wxMenuBarBase() -{ - WX_CLEAR_LIST(wxMenuList, m_menus); -} - -// ---------------------------------------------------------------------------- -// wxMenuBar item access: the base class versions manage m_menus list, the -// derived class should reflect the changes in the real menubar -// ---------------------------------------------------------------------------- - -wxMenu *wxMenuBarBase::GetMenu(size_t pos) const -{ - wxMenuList::compatibility_iterator node = m_menus.Item(pos); - wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") ); - - return node->GetData(); -} - -bool wxMenuBarBase::Append(wxMenu *menu, const wxString& WXUNUSED(title)) -{ - wxCHECK_MSG( menu, false, wxT("can't append NULL menu") ); - - m_menus.Append(menu); - menu->Attach(this); - - return true; -} - -bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu, - const wxString& title) -{ - if ( pos == m_menus.GetCount() ) - { - return wxMenuBarBase::Append(menu, title); - } - else // not at the end - { - wxCHECK_MSG( menu, false, wxT("can't insert NULL menu") ); - - wxMenuList::compatibility_iterator node = m_menus.Item(pos); - wxCHECK_MSG( node, false, wxT("bad index in wxMenuBar::Insert()") ); - - m_menus.Insert(node, menu); - menu->Attach(this); - - return true; - } -} - -wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu, - const wxString& WXUNUSED(title)) -{ - wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") ); - - wxMenuList::compatibility_iterator node = m_menus.Item(pos); - wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") ); - - wxMenu *menuOld = node->GetData(); - node->SetData(menu); - - menu->Attach(this); - menuOld->Detach(); - - return menuOld; -} - -wxMenu *wxMenuBarBase::Remove(size_t pos) -{ - wxMenuList::compatibility_iterator node = m_menus.Item(pos); - wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") ); - - wxMenu *menu = node->GetData(); - m_menus.Erase(node); - menu->Detach(); - - return menu; -} - -int wxMenuBarBase::FindMenu(const wxString& title) const -{ - wxString label = wxMenuItem::GetLabelFromText(title); - - size_t count = GetMenuCount(); - for ( size_t i = 0; i < count; i++ ) - { - wxString title2 = GetLabelTop(i); - if ( (title2 == title) || - (wxMenuItem::GetLabelFromText(title2) == label) ) - { - // found - return (int)i; - } - } - - return wxNOT_FOUND; - -} - -// ---------------------------------------------------------------------------- -// wxMenuBar attaching/detaching to/from the frame -// ---------------------------------------------------------------------------- - -void wxMenuBarBase::Attach(wxFrame *frame) -{ - wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") ); - - m_menuBarFrame = frame; -} - -void wxMenuBarBase::Detach() -{ - wxASSERT_MSG( IsAttached(), wxT("detaching unattached menubar") ); - - m_menuBarFrame = NULL; -} - -// ---------------------------------------------------------------------------- -// wxMenuBar searching for items -// ---------------------------------------------------------------------------- - -wxMenuItem *wxMenuBarBase::FindItem(int id, wxMenu **menu) const -{ - if ( menu ) - *menu = NULL; - - wxMenuItem *item = NULL; - size_t count = GetMenuCount(), i; - wxMenuList::const_iterator it; - for ( i = 0, it = m_menus.begin(); !item && (i < count); i++, it++ ) - { - item = (*it)->FindItem(id, menu); - } - - return item; -} - -int wxMenuBarBase::FindMenuItem(const wxString& menu, const wxString& item) const -{ - wxString label = wxMenuItem::GetLabelFromText(menu); - - int i = 0; - wxMenuList::compatibility_iterator node; - for ( node = m_menus.GetFirst(); node; node = node->GetNext(), i++ ) - { - if ( label == wxMenuItem::GetLabelFromText(GetLabelTop(i)) ) - return node->GetData()->FindItem(item); - } - - return wxNOT_FOUND; -} - -// --------------------------------------------------------------------------- -// wxMenuBar functions forwarded to wxMenuItem -// --------------------------------------------------------------------------- - -void wxMenuBarBase::Enable(int id, bool enable) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") ); - - item->Enable(enable); -} - -void wxMenuBarBase::Check(int id, bool check) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") ); - wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") ); - - item->Check(check); -} - -bool wxMenuBarBase::IsChecked(int id) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, false, wxT("wxMenuBar::IsChecked(): no such item") ); - - return item->IsChecked(); -} - -bool wxMenuBarBase::IsEnabled(int id) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, false, wxT("wxMenuBar::IsEnabled(): no such item") ); - - return item->IsEnabled(); -} - -void wxMenuBarBase::SetLabel(int id, const wxString& label) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") ); - - item->SetText(label); -} - -wxString wxMenuBarBase::GetLabel(int id) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, wxEmptyString, - wxT("wxMenuBar::GetLabel(): no such item") ); - - return item->GetText(); -} - -void wxMenuBarBase::SetHelpString(int id, const wxString& helpString) -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") ); - - item->SetHelp(helpString); -} - -wxString wxMenuBarBase::GetHelpString(int id) const -{ - wxMenuItem *item = FindItem(id); - - wxCHECK_MSG( item, wxEmptyString, - wxT("wxMenuBar::GetHelpString(): no such item") ); - - return item->GetHelp(); -} - -void wxMenuBarBase::UpdateMenus( void ) -{ - wxEvtHandler* source; - wxMenu* menu; - int nCount = GetMenuCount(); - for (int n = 0; n < nCount; n++) - { - menu = GetMenu( n ); - if (menu != NULL) - { - source = menu->GetEventHandler(); - if (source != NULL) - menu->UpdateUI( source ); - } - } -} - -// Get the text only, from the label -wxString wxMenuBarBase::GetMenuLabelText(size_t pos) const -{ - return wxMenuItem::GetLabelText(((wxMenuBar*)this)->GetMenuLabel(pos)); -} - - -#endif // wxUSE_MENUS +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/menucmn.cpp +// Purpose: wxMenu and wxMenuBar methods common to all ports +// Author: Vadim Zeitlin +// Modified by: +// Created: 26.10.99 +// RCS-ID: $Id: menucmn.cpp 57852 2009-01-06 09:40:34Z SC $ +// Copyright: (c) 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_MENUS + +#include + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/menu.h" +#endif + +#include "wx/stockitem.h" + +// ---------------------------------------------------------------------------- +// template lists +// ---------------------------------------------------------------------------- + +#include "wx/listimpl.cpp" + +WX_DEFINE_LIST(wxMenuList) +WX_DEFINE_LIST(wxMenuItemList) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxAcceleratorEntry +// ---------------------------------------------------------------------------- + + +#if wxUSE_ACCEL + +static const struct wxKeyName +{ + wxKeyCode code; + const wxChar *name; +} wxKeyNames[] = +{ + { WXK_DELETE, wxTRANSLATE("DEL") }, + { WXK_DELETE, wxTRANSLATE("DELETE") }, + { WXK_BACK, wxTRANSLATE("BACK") }, + { WXK_INSERT, wxTRANSLATE("INS") }, + { WXK_INSERT, wxTRANSLATE("INSERT") }, + { WXK_RETURN, wxTRANSLATE("ENTER") }, + { WXK_RETURN, wxTRANSLATE("RETURN") }, + { WXK_PAGEUP, wxTRANSLATE("PGUP") }, + { WXK_PAGEDOWN, wxTRANSLATE("PGDN") }, + { WXK_LEFT, wxTRANSLATE("LEFT") }, + { WXK_RIGHT, wxTRANSLATE("RIGHT") }, + { WXK_UP, wxTRANSLATE("UP") }, + { WXK_DOWN, wxTRANSLATE("DOWN") }, + { WXK_HOME, wxTRANSLATE("HOME") }, + { WXK_END, wxTRANSLATE("END") }, + { WXK_SPACE, wxTRANSLATE("SPACE") }, + { WXK_TAB, wxTRANSLATE("TAB") }, + { WXK_ESCAPE, wxTRANSLATE("ESC") }, + { WXK_ESCAPE, wxTRANSLATE("ESCAPE") }, + { WXK_CANCEL, wxTRANSLATE("CANCEL") }, + { WXK_CLEAR, wxTRANSLATE("CLEAR") }, + { WXK_MENU, wxTRANSLATE("MENU") }, + { WXK_PAUSE, wxTRANSLATE("PAUSE") }, + { WXK_CAPITAL, wxTRANSLATE("CAPITAL") }, + { WXK_SELECT, wxTRANSLATE("SELECT") }, + { WXK_PRINT, wxTRANSLATE("PRINT") }, + { WXK_EXECUTE, wxTRANSLATE("EXECUTE") }, + { WXK_SNAPSHOT, wxTRANSLATE("SNAPSHOT") }, + { WXK_HELP, wxTRANSLATE("HELP") }, + { WXK_ADD, wxTRANSLATE("ADD") }, + { WXK_SEPARATOR, wxTRANSLATE("SEPARATOR") }, + { WXK_SUBTRACT, wxTRANSLATE("SUBTRACT") }, + { WXK_DECIMAL, wxTRANSLATE("DECIMAL") }, + { WXK_DIVIDE, wxTRANSLATE("DIVIDE") }, + { WXK_NUMLOCK, wxTRANSLATE("NUM_LOCK") }, + { WXK_SCROLL, wxTRANSLATE("SCROLL_LOCK") }, + { WXK_PAGEUP, wxTRANSLATE("PAGEUP") }, + { WXK_PAGEDOWN, wxTRANSLATE("PAGEDOWN") }, + { WXK_NUMPAD_SPACE, wxTRANSLATE("KP_SPACE") }, + { WXK_NUMPAD_TAB, wxTRANSLATE("KP_TAB") }, + { WXK_NUMPAD_ENTER, wxTRANSLATE("KP_ENTER") }, + { WXK_NUMPAD_HOME, wxTRANSLATE("KP_HOME") }, + { WXK_NUMPAD_LEFT, wxTRANSLATE("KP_LEFT") }, + { WXK_NUMPAD_UP, wxTRANSLATE("KP_UP") }, + { WXK_NUMPAD_RIGHT, wxTRANSLATE("KP_RIGHT") }, + { WXK_NUMPAD_DOWN, wxTRANSLATE("KP_DOWN") }, + { WXK_NUMPAD_PAGEUP, wxTRANSLATE("KP_PRIOR") }, + { WXK_NUMPAD_PAGEUP, wxTRANSLATE("KP_PAGEUP") }, + { WXK_NUMPAD_PAGEDOWN, wxTRANSLATE("KP_NEXT") }, + { WXK_NUMPAD_PAGEDOWN, wxTRANSLATE("KP_PAGEDOWN") }, + { WXK_NUMPAD_END, wxTRANSLATE("KP_END") }, + { WXK_NUMPAD_BEGIN, wxTRANSLATE("KP_BEGIN") }, + { WXK_NUMPAD_INSERT, wxTRANSLATE("KP_INSERT") }, + { WXK_NUMPAD_DELETE, wxTRANSLATE("KP_DELETE") }, + { WXK_NUMPAD_EQUAL, wxTRANSLATE("KP_EQUAL") }, + { WXK_NUMPAD_MULTIPLY, wxTRANSLATE("KP_MULTIPLY") }, + { WXK_NUMPAD_ADD, wxTRANSLATE("KP_ADD") }, + { WXK_NUMPAD_SEPARATOR, wxTRANSLATE("KP_SEPARATOR") }, + { WXK_NUMPAD_SUBTRACT, wxTRANSLATE("KP_SUBTRACT") }, + { WXK_NUMPAD_DECIMAL, wxTRANSLATE("KP_DECIMAL") }, + { WXK_NUMPAD_DIVIDE, wxTRANSLATE("KP_DIVIDE") }, + { WXK_WINDOWS_LEFT, wxTRANSLATE("WINDOWS_LEFT") }, + { WXK_WINDOWS_RIGHT, wxTRANSLATE("WINDOWS_RIGHT") }, + { WXK_WINDOWS_MENU, wxTRANSLATE("WINDOWS_MENU") }, + { WXK_COMMAND, wxTRANSLATE("COMMAND") }, +}; + +// return true if the 2 strings refer to the same accel +// +// as accels can be either translated or not, check for both possibilities and +// also compare case-insensitively as the key names case doesn't count +static inline bool CompareAccelString(const wxString& str, const wxChar *accel) +{ + return str.CmpNoCase(accel) == 0 +#if wxUSE_INTL + || str.CmpNoCase(wxGetTranslation(accel)) == 0 +#endif + ; +} + +// return prefixCode+number if the string is of the form "" and +// 0 if it isn't +// +// first and last parameter specify the valid domain for "number" part +static int + IsNumberedAccelKey(const wxString& str, + const wxChar *prefix, + wxKeyCode prefixCode, + unsigned first, + unsigned last) +{ + const size_t lenPrefix = wxStrlen(prefix); + if ( !CompareAccelString(str.Left(lenPrefix), prefix) ) + return 0; + + unsigned long num; + if ( !str.Mid(lenPrefix).ToULong(&num) ) + return 0; + + if ( num < first || num > last ) + { + // this must be a mistake, chances that this is a valid name of another + // key are vanishingly small + wxLogDebug(_T("Invalid key string \"%s\""), str.c_str()); + return 0; + } + + return prefixCode + num - first; +} + +/* static */ +bool +wxAcceleratorEntry::ParseAccel(const wxString& text, int *flagsOut, int *keyOut) +{ + // the parser won't like trailing spaces + wxString label = text; + label.Trim(true); // the initial \t must be preserved so don't strip leading whitespaces + + // check for accelerators: they are given after '\t' + int posTab = label.Find(wxT('\t')); + if ( posTab == wxNOT_FOUND ) + { + return false; + } + + // parse the accelerator string + int accelFlags = wxACCEL_NORMAL; + wxString current; + for ( size_t n = (size_t)posTab + 1; n < label.length(); n++ ) + { + if ( (label[n] == '+') || (label[n] == '-') ) + { + // differentiate between a ctrl that will be translated to cmd on mac + // and an explicit xctrl that will not be translated and remains a ctrl + if ( CompareAccelString(current, wxTRANSLATE("ctrl")) ) + accelFlags |= wxACCEL_CMD; + else if ( CompareAccelString(current, wxTRANSLATE("xctrl")) ) + accelFlags |= wxACCEL_CTRL; + else if ( CompareAccelString(current, wxTRANSLATE("alt")) ) + accelFlags |= wxACCEL_ALT; + else if ( CompareAccelString(current, wxTRANSLATE("shift")) ) + accelFlags |= wxACCEL_SHIFT; + else // not a recognized modifier name + { + // we may have "Ctrl-+", for example, but we still want to + // catch typos like "Crtl-A" so only give the warning if we + // have something before the current '+' or '-', else take + // it as a literal symbol + if ( current.empty() ) + { + current += label[n]; + + // skip clearing it below + continue; + } + else + { + wxLogDebug(wxT("Unknown accel modifier: '%s'"), + current.c_str()); + } + } + + current.clear(); + } + else // not special character + { + current += (wxChar) wxTolower(label[n]); + } + } + + int keyCode; + const size_t len = current.length(); + switch ( len ) + { + case 0: + wxLogDebug(wxT("No accel key found, accel string ignored.")); + return false; + + case 1: + // it's just a letter + keyCode = current[0U]; + + // if the key is used with any modifiers, make it an uppercase one + // because Ctrl-A and Ctrl-a are the same; but keep it as is if it's + // used alone as 'a' and 'A' are different + if ( accelFlags != wxACCEL_NORMAL ) + keyCode = wxToupper(keyCode); + break; + + default: + keyCode = IsNumberedAccelKey(current, wxTRANSLATE("F"), + WXK_F1, 1, 12); + if ( !keyCode ) + { + for ( size_t n = 0; n < WXSIZEOF(wxKeyNames); n++ ) + { + const wxKeyName& kn = wxKeyNames[n]; + if ( CompareAccelString(current, kn.name) ) + { + keyCode = kn.code; + break; + } + } + } + + if ( !keyCode ) + keyCode = IsNumberedAccelKey(current, wxTRANSLATE("KP_"), + WXK_NUMPAD0, 0, 9); + if ( !keyCode ) + keyCode = IsNumberedAccelKey(current, wxTRANSLATE("SPECIAL"), + WXK_SPECIAL1, 1, 20); + + if ( !keyCode ) + { + wxLogDebug(wxT("Unrecognized accel key '%s', accel string ignored."), + current.c_str()); + return false; + } + } + + + wxASSERT_MSG( keyCode, _T("logic error: should have key code here") ); + + if ( flagsOut ) + *flagsOut = accelFlags; + if ( keyOut ) + *keyOut = keyCode; + + return true; +} + +/* static */ +wxAcceleratorEntry *wxAcceleratorEntry::Create(const wxString& str) +{ + int flags, + keyCode; + if ( !ParseAccel(str, &flags, &keyCode) ) + return NULL; + + return new wxAcceleratorEntry(flags, keyCode); +} + +bool wxAcceleratorEntry::FromString(const wxString& str) +{ + return ParseAccel(str, &m_flags, &m_keyCode); +} + +wxString wxAcceleratorEntry::ToString() const +{ + wxString text; + + int flags = GetFlags(); + if ( flags & wxACCEL_ALT ) + text += _("Alt-"); + if ( flags & wxACCEL_CMD ) + text += _("Ctrl-"); +#ifdef __WXMAC__ + if ( flags & wxACCEL_CTRL ) + text += _("XCtrl-"); +#endif + if ( flags & wxACCEL_SHIFT ) + text += _("Shift-"); + + const int code = GetKeyCode(); + + if ( code >= WXK_F1 && code <= WXK_F12 ) + text << _("F") << code - WXK_F1 + 1; + else if ( code >= WXK_NUMPAD0 && code <= WXK_NUMPAD9 ) + text << _("KP_") << code - WXK_NUMPAD0; + else if ( code >= WXK_SPECIAL1 && code <= WXK_SPECIAL20 ) + text << _("SPECIAL") << code - WXK_SPECIAL1 + 1; + else // check the named keys + { + size_t n; + for ( n = 0; n < WXSIZEOF(wxKeyNames); n++ ) + { + const wxKeyName& kn = wxKeyNames[n]; + if ( code == kn.code ) + { + text << wxGetTranslation(kn.name); + break; + } + } + + if ( n == WXSIZEOF(wxKeyNames) ) + { + // must be a simple key + if ( +#if !wxUSE_UNICODE + isascii(code) && +#endif // ANSI + wxIsalnum(code) ) + { + text << (wxChar)code; + } + else + { + wxFAIL_MSG( wxT("unknown keyboard accelerator code") ); + } + } + } + + return text; +} + +wxAcceleratorEntry *wxGetAccelFromString(const wxString& label) +{ + return wxAcceleratorEntry::Create(label); +} + +#endif // wxUSE_ACCEL + + +// ---------------------------------------------------------------------------- +// wxMenuItem +// ---------------------------------------------------------------------------- + +wxMenuItemBase::wxMenuItemBase(wxMenu *parentMenu, + int id, + const wxString& text, + const wxString& help, + wxItemKind kind, + wxMenu *subMenu) +{ + wxASSERT_MSG( parentMenu != NULL, wxT("menuitem should have a menu") ); + + m_parentMenu = parentMenu; + m_subMenu = subMenu; + m_isEnabled = true; + m_isChecked = false; + m_id = id; + m_kind = kind; + if (m_id == wxID_ANY) + m_id = wxNewId(); + if (m_id == wxID_SEPARATOR) + m_kind = wxITEM_SEPARATOR; + + SetText(text); + SetHelp(help); +} + +wxMenuItemBase::~wxMenuItemBase() +{ + delete m_subMenu; +} + +#if wxUSE_ACCEL + +wxAcceleratorEntry *wxMenuItemBase::GetAccel() const +{ + return wxAcceleratorEntry::Create(GetText()); +} + +void wxMenuItemBase::SetAccel(wxAcceleratorEntry *accel) +{ + wxString text = m_text.BeforeFirst(wxT('\t')); + if ( accel ) + { + text += wxT('\t'); + text += accel->ToString(); + } + + SetText(text); +} + +#endif // wxUSE_ACCEL + +void wxMenuItemBase::SetText(const wxString& str) +{ + m_text = str; + + if ( m_text.empty() && !IsSeparator() ) + { + wxASSERT_MSG( wxIsStockID(GetId()), + wxT("A non-stock menu item with an empty label?") ); + m_text = wxGetStockLabel(GetId(), wxSTOCK_WITH_ACCELERATOR | + wxSTOCK_WITH_MNEMONIC); + } +} + +void wxMenuItemBase::SetHelp(const wxString& str) +{ + m_help = str; + + if ( m_help.empty() && !IsSeparator() && wxIsStockID(GetId()) ) + { + // get a stock help string + m_help = wxGetStockHelpString(GetId()); + } +} + +wxString wxMenuItemBase::GetLabelText(const wxString& label) +{ + return GetLabelFromText(label); +} + +bool wxMenuBase::ms_locked = true; + +// ---------------------------------------------------------------------------- +// wxMenu ctor and dtor +// ---------------------------------------------------------------------------- + +void wxMenuBase::Init(long style) +{ + m_menuBar = (wxMenuBar *)NULL; + m_menuParent = (wxMenu *)NULL; + + m_invokingWindow = (wxWindow *)NULL; + m_style = style; + m_clientData = (void *)NULL; + m_eventHandler = this; +} + +wxMenuBase::~wxMenuBase() +{ + WX_CLEAR_LIST(wxMenuItemList, m_items); +} + +// ---------------------------------------------------------------------------- +// wxMenu item adding/removing +// ---------------------------------------------------------------------------- + +void wxMenuBase::AddSubMenu(wxMenu *submenu) +{ + wxCHECK_RET( submenu, _T("can't add a NULL submenu") ); + + submenu->SetParent((wxMenu *)this); +} + +wxMenuItem* wxMenuBase::DoAppend(wxMenuItem *item) +{ + wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Append()") ); + + m_items.Append(item); + item->SetMenu((wxMenu*)this); + if ( item->IsSubMenu() ) + { + AddSubMenu(item->GetSubMenu()); + } + + return item; +} + +wxMenuItem* wxMenuBase::Insert(size_t pos, wxMenuItem *item) +{ + wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert") ); + + if ( pos == GetMenuItemCount() ) + { + return DoAppend(item); + } + else + { + wxCHECK_MSG( pos < GetMenuItemCount(), NULL, + wxT("invalid index in wxMenu::Insert") ); + + return DoInsert(pos, item); + } +} + +wxMenuItem* wxMenuBase::DoInsert(size_t pos, wxMenuItem *item) +{ + wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Insert()") ); + + wxMenuItemList::compatibility_iterator node = m_items.Item(pos); + wxCHECK_MSG( node, NULL, wxT("invalid index in wxMenu::Insert()") ); + + m_items.Insert(node, item); + item->SetMenu((wxMenu*)this); + if ( item->IsSubMenu() ) + { + AddSubMenu(item->GetSubMenu()); + } + + return item; +} + +wxMenuItem *wxMenuBase::Remove(wxMenuItem *item) +{ + wxCHECK_MSG( item, NULL, wxT("invalid item in wxMenu::Remove") ); + + return DoRemove(item); +} + +wxMenuItem *wxMenuBase::DoRemove(wxMenuItem *item) +{ + wxMenuItemList::compatibility_iterator node = m_items.Find(item); + + // if we get here, the item is valid or one of Remove() functions is broken + wxCHECK_MSG( node, NULL, wxT("bug in wxMenu::Remove logic") ); + + // we detach the item, but we do delete the list node (i.e. don't call + // DetachNode() here!) + m_items.Erase(node); + + // item isn't attached to anything any more + item->SetMenu((wxMenu *)NULL); + wxMenu *submenu = item->GetSubMenu(); + if ( submenu ) + { + submenu->SetParent((wxMenu *)NULL); + if ( submenu->IsAttached() ) + submenu->Detach(); + } + + return item; +} + +bool wxMenuBase::Delete(wxMenuItem *item) +{ + wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Delete") ); + + return DoDelete(item); +} + +bool wxMenuBase::DoDelete(wxMenuItem *item) +{ + wxMenuItem *item2 = DoRemove(item); + wxCHECK_MSG( item2, false, wxT("failed to delete menu item") ); + + // don't delete the submenu + item2->SetSubMenu((wxMenu *)NULL); + + delete item2; + + return true; +} + +bool wxMenuBase::Destroy(wxMenuItem *item) +{ + wxCHECK_MSG( item, false, wxT("invalid item in wxMenu::Destroy") ); + + return DoDestroy(item); +} + +bool wxMenuBase::DoDestroy(wxMenuItem *item) +{ + wxMenuItem *item2 = DoRemove(item); + wxCHECK_MSG( item2, false, wxT("failed to delete menu item") ); + + delete item2; + + return true; +} + +// ---------------------------------------------------------------------------- +// wxMenu searching for items +// ---------------------------------------------------------------------------- + +// Finds the item id matching the given string, wxNOT_FOUND if not found. +int wxMenuBase::FindItem(const wxString& text) const +{ + wxString label = wxMenuItem::GetLabelFromText(text); + for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst(); + node; + node = node->GetNext() ) + { + wxMenuItem *item = node->GetData(); + if ( item->IsSubMenu() ) + { + int rc = item->GetSubMenu()->FindItem(label); + if ( rc != wxNOT_FOUND ) + return rc; + } + + // we execute this code for submenus as well to alllow finding them by + // name just like the ordinary items + if ( !item->IsSeparator() ) + { + if ( item->GetLabel() == label ) + return item->GetId(); + } + } + + return wxNOT_FOUND; +} + +// recursive search for item by id +wxMenuItem *wxMenuBase::FindItem(int itemId, wxMenu **itemMenu) const +{ + if ( itemMenu ) + *itemMenu = NULL; + + wxMenuItem *item = NULL; + for ( wxMenuItemList::compatibility_iterator node = m_items.GetFirst(); + node && !item; + node = node->GetNext() ) + { + item = node->GetData(); + + if ( item->GetId() == itemId ) + { + if ( itemMenu ) + *itemMenu = (wxMenu *)this; + } + else if ( item->IsSubMenu() ) + { + item = item->GetSubMenu()->FindItem(itemId, itemMenu); + } + else + { + // don't exit the loop + item = NULL; + } + } + + return item; +} + +// non recursive search +wxMenuItem *wxMenuBase::FindChildItem(int id, size_t *ppos) const +{ + wxMenuItem *item = (wxMenuItem *)NULL; + wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst(); + + size_t pos; + for ( pos = 0; node; pos++ ) + { + if ( node->GetData()->GetId() == id ) + { + item = node->GetData(); + + break; + } + + node = node->GetNext(); + } + + if ( ppos ) + { + *ppos = item ? pos : (size_t)wxNOT_FOUND; + } + + return item; +} + +// find by position +wxMenuItem* wxMenuBase::FindItemByPosition(size_t position) const +{ + wxCHECK_MSG( position < m_items.GetCount(), NULL, + _T("wxMenu::FindItemByPosition(): invalid menu index") ); + + return m_items.Item( position )->GetData(); +} + +// ---------------------------------------------------------------------------- +// wxMenu helpers used by derived classes +// ---------------------------------------------------------------------------- + +// Update a menu and all submenus recursively. source is the object that has +// the update event handlers defined for it. If NULL, the menu or associated +// window will be used. +void wxMenuBase::UpdateUI(wxEvtHandler* source) +{ + if (GetInvokingWindow()) + { + // Don't update menus if the parent + // frame is about to get deleted + wxWindow *tlw = wxGetTopLevelParent( GetInvokingWindow() ); + if (tlw && wxPendingDelete.Member(tlw)) + return; + } + + if ( !source && GetInvokingWindow() ) + source = GetInvokingWindow()->GetEventHandler(); + if ( !source ) + source = GetEventHandler(); + if ( !source ) + source = this; + + wxMenuItemList::compatibility_iterator node = GetMenuItems().GetFirst(); + while ( node ) + { + wxMenuItem* item = node->GetData(); + if ( !item->IsSeparator() ) + { + wxWindowID id = item->GetId(); + wxUpdateUIEvent event(id); + event.SetEventObject( source ); + + if ( source->ProcessEvent(event) ) + { + // if anything changed, update the changed attribute + if (event.GetSetText()) + SetLabel(id, event.GetText()); + if (event.GetSetChecked()) + Check(id, event.GetChecked()); + if (event.GetSetEnabled()) + Enable(id, event.GetEnabled()); + } + + // recurse to the submenus + if ( item->GetSubMenu() ) + item->GetSubMenu()->UpdateUI(source); + } + //else: item is a separator (which doesn't process update UI events) + + node = node->GetNext(); + } +} + +bool wxMenuBase::SendEvent(int id, int checked) +{ + wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, id); + event.SetEventObject(this); + event.SetInt(checked); + + bool processed = false; + + // Try the menu's event handler + // if ( !processed ) + { + wxEvtHandler *handler = GetEventHandler(); + if ( handler ) + processed = handler->ProcessEvent(event); + } + + // Try the window the menu was popped up from (and up through the + // hierarchy) + if ( !processed ) + { + const wxMenuBase *menu = this; + while ( menu ) + { + wxWindow *win = menu->GetInvokingWindow(); + if ( win ) + { + processed = win->GetEventHandler()->ProcessEvent(event); + break; + } + + menu = menu->GetParent(); + } + } + + return processed; +} + +// ---------------------------------------------------------------------------- +// wxMenu attaching/detaching to/from menu bar +// ---------------------------------------------------------------------------- + +wxMenuBar* wxMenuBase::GetMenuBar() const +{ + if(GetParent()) + return GetParent()->GetMenuBar(); + return m_menuBar; +} + +void wxMenuBase::Attach(wxMenuBarBase *menubar) +{ + // use Detach() instead! + wxASSERT_MSG( menubar, _T("menu can't be attached to NULL menubar") ); + + // use IsAttached() to prevent this from happening + wxASSERT_MSG( !m_menuBar, _T("attaching menu twice?") ); + + m_menuBar = (wxMenuBar *)menubar; +} + +void wxMenuBase::Detach() +{ + // use IsAttached() to prevent this from happening + wxASSERT_MSG( m_menuBar, _T("detaching unattached menu?") ); + + m_menuBar = NULL; +} + +// ---------------------------------------------------------------------------- +// wxMenu functions forwarded to wxMenuItem +// ---------------------------------------------------------------------------- + +void wxMenuBase::Enable( int id, bool enable ) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenu::Enable: no such item") ); + + item->Enable(enable); +} + +bool wxMenuBase::IsEnabled( int id ) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, false, wxT("wxMenu::IsEnabled: no such item") ); + + return item->IsEnabled(); +} + +void wxMenuBase::Check( int id, bool enable ) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenu::Check: no such item") ); + + item->Check(enable); +} + +bool wxMenuBase::IsChecked( int id ) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, false, wxT("wxMenu::IsChecked: no such item") ); + + return item->IsChecked(); +} + +void wxMenuBase::SetLabel( int id, const wxString &label ) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenu::SetLabel: no such item") ); + + item->SetText(label); +} + +wxString wxMenuBase::GetLabel( int id ) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetLabel: no such item") ); + + return item->GetText(); +} + +void wxMenuBase::SetHelpString( int id, const wxString& helpString ) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenu::SetHelpString: no such item") ); + + item->SetHelp( helpString ); +} + +wxString wxMenuBase::GetHelpString( int id ) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, wxEmptyString, wxT("wxMenu::GetHelpString: no such item") ); + + return item->GetHelp(); +} + +// ---------------------------------------------------------------------------- +// wxMenuBarBase ctor and dtor +// ---------------------------------------------------------------------------- + +wxMenuBarBase::wxMenuBarBase() +{ + // not attached yet + m_menuBarFrame = NULL; +} + +wxMenuBarBase::~wxMenuBarBase() +{ + WX_CLEAR_LIST(wxMenuList, m_menus); +} + +// ---------------------------------------------------------------------------- +// wxMenuBar item access: the base class versions manage m_menus list, the +// derived class should reflect the changes in the real menubar +// ---------------------------------------------------------------------------- + +wxMenu *wxMenuBarBase::GetMenu(size_t pos) const +{ + wxMenuList::compatibility_iterator node = m_menus.Item(pos); + wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::GetMenu()") ); + + return node->GetData(); +} + +bool wxMenuBarBase::Append(wxMenu *menu, const wxString& WXUNUSED(title)) +{ + wxCHECK_MSG( menu, false, wxT("can't append NULL menu") ); + + m_menus.Append(menu); + menu->Attach(this); + + return true; +} + +bool wxMenuBarBase::Insert(size_t pos, wxMenu *menu, + const wxString& title) +{ + if ( pos == m_menus.GetCount() ) + { + return wxMenuBarBase::Append(menu, title); + } + else // not at the end + { + wxCHECK_MSG( menu, false, wxT("can't insert NULL menu") ); + + wxMenuList::compatibility_iterator node = m_menus.Item(pos); + wxCHECK_MSG( node, false, wxT("bad index in wxMenuBar::Insert()") ); + + m_menus.Insert(node, menu); + menu->Attach(this); + + return true; + } +} + +wxMenu *wxMenuBarBase::Replace(size_t pos, wxMenu *menu, + const wxString& WXUNUSED(title)) +{ + wxCHECK_MSG( menu, NULL, wxT("can't insert NULL menu") ); + + wxMenuList::compatibility_iterator node = m_menus.Item(pos); + wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Replace()") ); + + wxMenu *menuOld = node->GetData(); + node->SetData(menu); + + menu->Attach(this); + menuOld->Detach(); + + return menuOld; +} + +wxMenu *wxMenuBarBase::Remove(size_t pos) +{ + wxMenuList::compatibility_iterator node = m_menus.Item(pos); + wxCHECK_MSG( node, NULL, wxT("bad index in wxMenuBar::Remove()") ); + + wxMenu *menu = node->GetData(); + m_menus.Erase(node); + menu->Detach(); + + return menu; +} + +int wxMenuBarBase::FindMenu(const wxString& title) const +{ + wxString label = wxMenuItem::GetLabelFromText(title); + + size_t count = GetMenuCount(); + for ( size_t i = 0; i < count; i++ ) + { + wxString title2 = GetLabelTop(i); + if ( (title2 == title) || + (wxMenuItem::GetLabelFromText(title2) == label) ) + { + // found + return (int)i; + } + } + + return wxNOT_FOUND; + +} + +// ---------------------------------------------------------------------------- +// wxMenuBar attaching/detaching to/from the frame +// ---------------------------------------------------------------------------- + +void wxMenuBarBase::Attach(wxFrame *frame) +{ + wxASSERT_MSG( !IsAttached(), wxT("menubar already attached!") ); + + m_menuBarFrame = frame; +} + +void wxMenuBarBase::Detach() +{ + wxASSERT_MSG( IsAttached(), wxT("detaching unattached menubar") ); + + m_menuBarFrame = NULL; +} + +// ---------------------------------------------------------------------------- +// wxMenuBar searching for items +// ---------------------------------------------------------------------------- + +wxMenuItem *wxMenuBarBase::FindItem(int id, wxMenu **menu) const +{ + if ( menu ) + *menu = NULL; + + wxMenuItem *item = NULL; + size_t count = GetMenuCount(), i; + wxMenuList::const_iterator it; + for ( i = 0, it = m_menus.begin(); !item && (i < count); i++, it++ ) + { + item = (*it)->FindItem(id, menu); + } + + return item; +} + +int wxMenuBarBase::FindMenuItem(const wxString& menu, const wxString& item) const +{ + wxString label = wxMenuItem::GetLabelFromText(menu); + + int i = 0; + wxMenuList::compatibility_iterator node; + for ( node = m_menus.GetFirst(); node; node = node->GetNext(), i++ ) + { + if ( label == wxMenuItem::GetLabelFromText(GetLabelTop(i)) ) + return node->GetData()->FindItem(item); + } + + return wxNOT_FOUND; +} + +// --------------------------------------------------------------------------- +// wxMenuBar functions forwarded to wxMenuItem +// --------------------------------------------------------------------------- + +void wxMenuBarBase::Enable(int id, bool enable) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("attempt to enable an item which doesn't exist") ); + + item->Enable(enable); +} + +void wxMenuBarBase::Check(int id, bool check) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("attempt to check an item which doesn't exist") ); + wxCHECK_RET( item->IsCheckable(), wxT("attempt to check an uncheckable item") ); + + item->Check(check); +} + +bool wxMenuBarBase::IsChecked(int id) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, false, wxT("wxMenuBar::IsChecked(): no such item") ); + + return item->IsChecked(); +} + +bool wxMenuBarBase::IsEnabled(int id) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, false, wxT("wxMenuBar::IsEnabled(): no such item") ); + + return item->IsEnabled(); +} + +void wxMenuBarBase::SetLabel(int id, const wxString& label) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenuBar::SetLabel(): no such item") ); + + item->SetText(label); +} + +wxString wxMenuBarBase::GetLabel(int id) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, wxEmptyString, + wxT("wxMenuBar::GetLabel(): no such item") ); + + return item->GetText(); +} + +void wxMenuBarBase::SetHelpString(int id, const wxString& helpString) +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_RET( item, wxT("wxMenuBar::SetHelpString(): no such item") ); + + item->SetHelp(helpString); +} + +wxString wxMenuBarBase::GetHelpString(int id) const +{ + wxMenuItem *item = FindItem(id); + + wxCHECK_MSG( item, wxEmptyString, + wxT("wxMenuBar::GetHelpString(): no such item") ); + + return item->GetHelp(); +} + +void wxMenuBarBase::UpdateMenus( void ) +{ + wxEvtHandler* source; + wxMenu* menu; + int nCount = GetMenuCount(); + for (int n = 0; n < nCount; n++) + { + menu = GetMenu( n ); + if (menu != NULL) + { + source = menu->GetEventHandler(); + if (source != NULL) + menu->UpdateUI( source ); + } + } +} + +// Get the text only, from the label +wxString wxMenuBarBase::GetMenuLabelText(size_t pos) const +{ + return wxMenuItem::GetLabelText(((wxMenuBar*)this)->GetMenuLabel(pos)); +} + + +#endif // wxUSE_MENUS diff --git a/Source/3rd Party/wx/src/common/mimecmn.cpp b/Source/3rd Party/wx/src/common/mimecmn.cpp index 87320c149..8f914e347 100644 --- a/Source/3rd Party/wx/src/common/mimecmn.cpp +++ b/Source/3rd Party/wx/src/common/mimecmn.cpp @@ -1,752 +1,752 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/mimecmn.cpp -// Purpose: classes and functions to manage MIME types -// Author: Vadim Zeitlin -// Modified by: -// Chris Elliott (biol75@york.ac.uk) 5 Dec 00: write support for Win32 -// Created: 23.09.98 -// RCS-ID: $Id: mimecmn.cpp 47027 2007-06-29 18:23:39Z VZ $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence (part of wxExtra library) -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_MIMETYPE - -#include "wx/mimetype.h" - -#ifndef WX_PRECOMP - #include "wx/dynarray.h" - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/module.h" -#endif //WX_PRECOMP - -#include "wx/file.h" -#include "wx/iconloc.h" -#include "wx/confbase.h" - -// other standard headers -#include - -// implementation classes: -#if defined(__WXMSW__) - #include "wx/msw/mimetype.h" -#elif defined(__WXMAC__) - #include "wx/mac/mimetype.h" -#elif defined(__WXPM__) || defined (__EMX__) - #include "wx/os2/mimetype.h" - #undef __UNIX__ -#elif defined(__DOS__) - #include "wx/msdos/mimetype.h" -#else // Unix - #include "wx/unix/mimetype.h" -#endif - -// ============================================================================ -// common classes -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxMimeTypeCommands -// ---------------------------------------------------------------------------- - -void -wxMimeTypeCommands::AddOrReplaceVerb(const wxString& verb, const wxString& cmd) -{ - int n = m_verbs.Index(verb, false /* ignore case */); - if ( n == wxNOT_FOUND ) - { - m_verbs.Add(verb); - m_commands.Add(cmd); - } - else - { - m_commands[n] = cmd; - } -} - -wxString -wxMimeTypeCommands::GetCommandForVerb(const wxString& verb, size_t *idx) const -{ - wxString s; - - int n = m_verbs.Index(verb); - if ( n != wxNOT_FOUND ) - { - s = m_commands[(size_t)n]; - if ( idx ) - *idx = n; - } - else if ( idx ) - { - // different from any valid index - *idx = (size_t)-1; - } - - return s; -} - -wxString wxMimeTypeCommands::GetVerbCmd(size_t n) const -{ - return m_verbs[n] + wxT('=') + m_commands[n]; -} - -// ---------------------------------------------------------------------------- -// wxFileTypeInfo -// ---------------------------------------------------------------------------- - -wxFileTypeInfo::wxFileTypeInfo(const wxChar *mimeType, - const wxChar *openCmd, - const wxChar *printCmd, - const wxChar *desc, - ...) - : m_mimeType(mimeType), - m_openCmd(openCmd), - m_printCmd(printCmd), - m_desc(desc) -{ - va_list argptr; - va_start(argptr, desc); - - for ( ;; ) - { - // icc gives this warning in its own va_arg() macro, argh -#ifdef __INTELC__ - #pragma warning(push) - #pragma warning(disable: 1684) -#endif - - const wxChar *ext = va_arg(argptr, const wxChar *); - -#ifdef __INTELC__ - #pragma warning(pop) -#endif - if ( !ext ) - { - // NULL terminates the list - break; - } - - m_exts.Add(ext); - } - - va_end(argptr); -} - - -wxFileTypeInfo::wxFileTypeInfo(const wxArrayString& sArray) -{ - m_mimeType = sArray [0u]; - m_openCmd = sArray [1u]; - m_printCmd = sArray [2u]; - m_desc = sArray [3u]; - - size_t count = sArray.GetCount(); - for ( size_t i = 4; i < count; i++ ) - { - m_exts.Add(sArray[i]); - } -} - -#include "wx/arrimpl.cpp" -WX_DEFINE_OBJARRAY(wxArrayFileTypeInfo) - -// ============================================================================ -// implementation of the wrapper classes -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxFileType -// ---------------------------------------------------------------------------- - -/* static */ -wxString wxFileType::ExpandCommand(const wxString& command, - const wxFileType::MessageParameters& params) -{ - bool hasFilename = false; - - wxString str; - for ( const wxChar *pc = command.c_str(); *pc != wxT('\0'); pc++ ) { - if ( *pc == wxT('%') ) { - switch ( *++pc ) { - case wxT('s'): - // '%s' expands into file name (quoted because it might - // contain spaces) - except if there are already quotes - // there because otherwise some programs may get confused - // by double double quotes -#if 0 - if ( *(pc - 2) == wxT('"') ) - str << params.GetFileName(); - else - str << wxT('"') << params.GetFileName() << wxT('"'); -#endif - str << params.GetFileName(); - hasFilename = true; - break; - - case wxT('t'): - // '%t' expands into MIME type (quote it too just to be - // consistent) - str << wxT('\'') << params.GetMimeType() << wxT('\''); - break; - - case wxT('{'): - { - const wxChar *pEnd = wxStrchr(pc, wxT('}')); - if ( pEnd == NULL ) { - wxString mimetype; - wxLogWarning(_("Unmatched '{' in an entry for mime type %s."), - params.GetMimeType().c_str()); - str << wxT("%{"); - } - else { - wxString param(pc + 1, pEnd - pc - 1); - str << wxT('\'') << params.GetParamValue(param) << wxT('\''); - pc = pEnd; - } - } - break; - - case wxT('n'): - case wxT('F'): - // TODO %n is the number of parts, %F is an array containing - // the names of temp files these parts were written to - // and their mime types. - break; - - default: - wxLogDebug(wxT("Unknown field %%%c in command '%s'."), - *pc, command.c_str()); - str << *pc; - } - } - else { - str << *pc; - } - } - - // metamail(1) man page states that if the mailcap entry doesn't have '%s' - // the program will accept the data on stdin so normally we should append - // "< %s" to the end of the command in such case, but not all commands - // behave like this, in particular a common test is 'test -n "$DISPLAY"' - // and appending "< %s" to this command makes the test fail... I don't - // know of the correct solution, try to guess what we have to do. - - // test now carried out on reading file so test should never get here - if ( !hasFilename && !str.empty() -#ifdef __UNIX__ - && !str.StartsWith(_T("test ")) -#endif // Unix - ) { - str << wxT(" < '") << params.GetFileName() << wxT('\''); - } - - return str; -} - -wxFileType::wxFileType(const wxFileTypeInfo& info) -{ - m_info = &info; - m_impl = NULL; -} - -wxFileType::wxFileType() -{ - m_info = NULL; - m_impl = new wxFileTypeImpl; -} - -wxFileType::~wxFileType() -{ - if ( m_impl ) - delete m_impl; -} - -bool wxFileType::GetExtensions(wxArrayString& extensions) -{ - if ( m_info ) - { - extensions = m_info->GetExtensions(); - return true; - } - - return m_impl->GetExtensions(extensions); -} - -bool wxFileType::GetMimeType(wxString *mimeType) const -{ - wxCHECK_MSG( mimeType, false, _T("invalid parameter in GetMimeType") ); - - if ( m_info ) - { - *mimeType = m_info->GetMimeType(); - - return true; - } - - return m_impl->GetMimeType(mimeType); -} - -bool wxFileType::GetMimeTypes(wxArrayString& mimeTypes) const -{ - if ( m_info ) - { - mimeTypes.Clear(); - mimeTypes.Add(m_info->GetMimeType()); - - return true; - } - - return m_impl->GetMimeTypes(mimeTypes); -} - -bool wxFileType::GetIcon(wxIconLocation *iconLoc) const -{ - if ( m_info ) - { - if ( iconLoc ) - { - iconLoc->SetFileName(m_info->GetIconFile()); -#ifdef __WXMSW__ - iconLoc->SetIndex(m_info->GetIconIndex()); -#endif // __WXMSW__ - } - - return true; - } - - return m_impl->GetIcon(iconLoc); -} - -bool -wxFileType::GetIcon(wxIconLocation *iconloc, - const MessageParameters& params) const -{ - if ( !GetIcon(iconloc) ) - { - return false; - } - - // we may have "%s" in the icon location string, at least under Windows, so - // expand this - if ( iconloc ) - { - iconloc->SetFileName(ExpandCommand(iconloc->GetFileName(), params)); - } - - return true; -} - -bool wxFileType::GetDescription(wxString *desc) const -{ - wxCHECK_MSG( desc, false, _T("invalid parameter in GetDescription") ); - - if ( m_info ) - { - *desc = m_info->GetDescription(); - - return true; - } - - return m_impl->GetDescription(desc); -} - -bool -wxFileType::GetOpenCommand(wxString *openCmd, - const wxFileType::MessageParameters& params) const -{ - wxCHECK_MSG( openCmd, false, _T("invalid parameter in GetOpenCommand") ); - - if ( m_info ) - { - *openCmd = ExpandCommand(m_info->GetOpenCommand(), params); - - return true; - } - - return m_impl->GetOpenCommand(openCmd, params); -} - -wxString wxFileType::GetOpenCommand(const wxString& filename) const -{ - wxString cmd; - if ( !GetOpenCommand(&cmd, filename) ) - { - // return empty string to indicate an error - cmd.clear(); - } - - return cmd; -} - -bool -wxFileType::GetPrintCommand(wxString *printCmd, - const wxFileType::MessageParameters& params) const -{ - wxCHECK_MSG( printCmd, false, _T("invalid parameter in GetPrintCommand") ); - - if ( m_info ) - { - *printCmd = ExpandCommand(m_info->GetPrintCommand(), params); - - return true; - } - - return m_impl->GetPrintCommand(printCmd, params); -} - - -size_t wxFileType::GetAllCommands(wxArrayString *verbs, - wxArrayString *commands, - const wxFileType::MessageParameters& params) const -{ - if ( verbs ) - verbs->Clear(); - if ( commands ) - commands->Clear(); - -#if defined (__WXMSW__) || defined(__UNIX__) - return m_impl->GetAllCommands(verbs, commands, params); -#else // !__WXMSW__ || Unix - // we don't know how to retrieve all commands, so just try the 2 we know - // about - size_t count = 0; - wxString cmd; - if ( GetOpenCommand(&cmd, params) ) - { - if ( verbs ) - verbs->Add(_T("Open")); - if ( commands ) - commands->Add(cmd); - count++; - } - - if ( GetPrintCommand(&cmd, params) ) - { - if ( verbs ) - verbs->Add(_T("Print")); - if ( commands ) - commands->Add(cmd); - - count++; - } - - return count; -#endif // __WXMSW__/| __UNIX__ -} - -bool wxFileType::Unassociate() -{ -#if defined(__WXMSW__) - return m_impl->Unassociate(); -#elif defined(__UNIX__) - return m_impl->Unassociate(this); -#else - wxFAIL_MSG( _T("not implemented") ); // TODO - return false; -#endif -} - -bool wxFileType::SetCommand(const wxString& cmd, - const wxString& verb, - bool overwriteprompt) -{ -#if defined (__WXMSW__) || defined(__UNIX__) - return m_impl->SetCommand(cmd, verb, overwriteprompt); -#else - wxUnusedVar(cmd); - wxUnusedVar(verb); - wxUnusedVar(overwriteprompt); - wxFAIL_MSG(_T("not implemented")); - return false; -#endif -} - -bool wxFileType::SetDefaultIcon(const wxString& cmd, int index) -{ - wxString sTmp = cmd; -#ifdef __WXMSW__ - // VZ: should we do this? - // chris elliott : only makes sense in MS windows - if ( sTmp.empty() ) - GetOpenCommand(&sTmp, wxFileType::MessageParameters(wxEmptyString, wxEmptyString)); -#endif - wxCHECK_MSG( !sTmp.empty(), false, _T("need the icon file") ); - -#if defined (__WXMSW__) || defined(__UNIX__) - return m_impl->SetDefaultIcon (cmd, index); -#else - wxUnusedVar(index); - wxFAIL_MSG(_T("not implemented")); - return false; -#endif -} - -// ---------------------------------------------------------------------------- -// wxMimeTypesManagerFactory -// ---------------------------------------------------------------------------- - -wxMimeTypesManagerFactory *wxMimeTypesManagerFactory::m_factory = NULL; - -/* static */ -void wxMimeTypesManagerFactory::Set(wxMimeTypesManagerFactory *factory) -{ - delete m_factory; - - m_factory = factory; -} - -/* static */ -wxMimeTypesManagerFactory *wxMimeTypesManagerFactory::Get() -{ - if ( !m_factory ) - m_factory = new wxMimeTypesManagerFactory; - - return m_factory; -} - -wxMimeTypesManagerImpl *wxMimeTypesManagerFactory::CreateMimeTypesManagerImpl() -{ - return new wxMimeTypesManagerImpl; -} - -// ---------------------------------------------------------------------------- -// wxMimeTypesManager -// ---------------------------------------------------------------------------- - -void wxMimeTypesManager::EnsureImpl() -{ - if ( !m_impl ) - m_impl = wxMimeTypesManagerFactory::Get()->CreateMimeTypesManagerImpl(); -} - -bool wxMimeTypesManager::IsOfType(const wxString& mimeType, - const wxString& wildcard) -{ - wxASSERT_MSG( mimeType.Find(wxT('*')) == wxNOT_FOUND, - wxT("first MIME type can't contain wildcards") ); - - // all comparaisons are case insensitive (2nd arg of IsSameAs() is false) - if ( wildcard.BeforeFirst(wxT('/')). - IsSameAs(mimeType.BeforeFirst(wxT('/')), false) ) - { - wxString strSubtype = wildcard.AfterFirst(wxT('/')); - - if ( strSubtype == wxT("*") || - strSubtype.IsSameAs(mimeType.AfterFirst(wxT('/')), false) ) - { - // matches (either exactly or it's a wildcard) - return true; - } - } - - return false; -} - -wxMimeTypesManager::wxMimeTypesManager() -{ - m_impl = NULL; -} - -wxMimeTypesManager::~wxMimeTypesManager() -{ - if ( m_impl ) - delete m_impl; -} - -bool wxMimeTypesManager::Unassociate(wxFileType *ft) -{ - EnsureImpl(); - -#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__) - return m_impl->Unassociate(ft); -#else - return ft->Unassociate(); -#endif -} - - -wxFileType * -wxMimeTypesManager::Associate(const wxFileTypeInfo& ftInfo) -{ - EnsureImpl(); - -#if defined(__WXMSW__) || defined(__UNIX__) - return m_impl->Associate(ftInfo); -#else // other platforms - wxUnusedVar(ftInfo); - wxFAIL_MSG( _T("not implemented") ); // TODO - return NULL; -#endif // platforms -} - -wxFileType * -wxMimeTypesManager::GetFileTypeFromExtension(const wxString& ext) -{ - EnsureImpl(); - - wxString::const_iterator i = ext.begin(); - const wxString::const_iterator end = ext.end(); - wxString extWithoutDot; - if ( i != end && *i == '.' ) - extWithoutDot.assign(++i, ext.end()); - else - extWithoutDot = ext; - - wxCHECK_MSG( !ext.empty(), NULL, _T("extension can't be empty") ); - - wxFileType *ft = m_impl->GetFileTypeFromExtension(extWithoutDot); - - if ( !ft ) { - // check the fallbacks - // - // TODO linear search is potentially slow, perhaps we should use a - // sorted array? - size_t count = m_fallbacks.GetCount(); - for ( size_t n = 0; n < count; n++ ) { - if ( m_fallbacks[n].GetExtensions().Index(ext) != wxNOT_FOUND ) { - ft = new wxFileType(m_fallbacks[n]); - - break; - } - } - } - - return ft; -} - -wxFileType * -wxMimeTypesManager::GetFileTypeFromMimeType(const wxString& mimeType) -{ - EnsureImpl(); - wxFileType *ft = m_impl->GetFileTypeFromMimeType(mimeType); - - if ( !ft ) { - // check the fallbacks - // - // TODO linear search is potentially slow, perhaps we should use a - // sorted array? - size_t count = m_fallbacks.GetCount(); - for ( size_t n = 0; n < count; n++ ) { - if ( wxMimeTypesManager::IsOfType(mimeType, - m_fallbacks[n].GetMimeType()) ) { - ft = new wxFileType(m_fallbacks[n]); - - break; - } - } - } - - return ft; -} - -bool wxMimeTypesManager::ReadMailcap(const wxString& filename, bool fallback) -{ - EnsureImpl(); - return m_impl->ReadMailcap(filename, fallback); -} - -bool wxMimeTypesManager::ReadMimeTypes(const wxString& filename) -{ - EnsureImpl(); - return m_impl->ReadMimeTypes(filename); -} - -void wxMimeTypesManager::AddFallbacks(const wxFileTypeInfo *filetypes) -{ - EnsureImpl(); - for ( const wxFileTypeInfo *ft = filetypes; ft && ft->IsValid(); ft++ ) { - AddFallback(*ft); - } -} - -size_t wxMimeTypesManager::EnumAllFileTypes(wxArrayString& mimetypes) -{ - EnsureImpl(); - size_t countAll = m_impl->EnumAllFileTypes(mimetypes); - - // add the fallback filetypes - size_t count = m_fallbacks.GetCount(); - for ( size_t n = 0; n < count; n++ ) { - if ( mimetypes.Index(m_fallbacks[n].GetMimeType()) == wxNOT_FOUND ) { - mimetypes.Add(m_fallbacks[n].GetMimeType()); - countAll++; - } - } - - return countAll; -} - -void wxMimeTypesManager::Initialize(int mcapStyle, - const wxString& sExtraDir) -{ -#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__) - EnsureImpl(); - - m_impl->Initialize(mcapStyle, sExtraDir); -#else - (void)mcapStyle; - (void)sExtraDir; -#endif // Unix -} - -// and this function clears all the data from the manager -void wxMimeTypesManager::ClearData() -{ -#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__) - EnsureImpl(); - - m_impl->ClearData(); -#endif // Unix -} - -// ---------------------------------------------------------------------------- -// global data and wxMimeTypeCmnModule -// ---------------------------------------------------------------------------- - -// private object -static wxMimeTypesManager gs_mimeTypesManager; - -// and public pointer -wxMimeTypesManager *wxTheMimeTypesManager = &gs_mimeTypesManager; - -class wxMimeTypeCmnModule: public wxModule -{ -public: - wxMimeTypeCmnModule() : wxModule() { } - - virtual bool OnInit() { return true; } - virtual void OnExit() - { - wxMimeTypesManagerFactory::Set(NULL); - - if ( gs_mimeTypesManager.m_impl != NULL ) - { - delete gs_mimeTypesManager.m_impl; - gs_mimeTypesManager.m_impl = NULL; - gs_mimeTypesManager.m_fallbacks.Clear(); - } - } - - DECLARE_DYNAMIC_CLASS(wxMimeTypeCmnModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxMimeTypeCmnModule, wxModule) - -#endif // wxUSE_MIMETYPE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/mimecmn.cpp +// Purpose: classes and functions to manage MIME types +// Author: Vadim Zeitlin +// Modified by: +// Chris Elliott (biol75@york.ac.uk) 5 Dec 00: write support for Win32 +// Created: 23.09.98 +// RCS-ID: $Id: mimecmn.cpp 47027 2007-06-29 18:23:39Z VZ $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence (part of wxExtra library) +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_MIMETYPE + +#include "wx/mimetype.h" + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/module.h" +#endif //WX_PRECOMP + +#include "wx/file.h" +#include "wx/iconloc.h" +#include "wx/confbase.h" + +// other standard headers +#include + +// implementation classes: +#if defined(__WXMSW__) + #include "wx/msw/mimetype.h" +#elif defined(__WXMAC__) + #include "wx/mac/mimetype.h" +#elif defined(__WXPM__) || defined (__EMX__) + #include "wx/os2/mimetype.h" + #undef __UNIX__ +#elif defined(__DOS__) + #include "wx/msdos/mimetype.h" +#else // Unix + #include "wx/unix/mimetype.h" +#endif + +// ============================================================================ +// common classes +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxMimeTypeCommands +// ---------------------------------------------------------------------------- + +void +wxMimeTypeCommands::AddOrReplaceVerb(const wxString& verb, const wxString& cmd) +{ + int n = m_verbs.Index(verb, false /* ignore case */); + if ( n == wxNOT_FOUND ) + { + m_verbs.Add(verb); + m_commands.Add(cmd); + } + else + { + m_commands[n] = cmd; + } +} + +wxString +wxMimeTypeCommands::GetCommandForVerb(const wxString& verb, size_t *idx) const +{ + wxString s; + + int n = m_verbs.Index(verb); + if ( n != wxNOT_FOUND ) + { + s = m_commands[(size_t)n]; + if ( idx ) + *idx = n; + } + else if ( idx ) + { + // different from any valid index + *idx = (size_t)-1; + } + + return s; +} + +wxString wxMimeTypeCommands::GetVerbCmd(size_t n) const +{ + return m_verbs[n] + wxT('=') + m_commands[n]; +} + +// ---------------------------------------------------------------------------- +// wxFileTypeInfo +// ---------------------------------------------------------------------------- + +wxFileTypeInfo::wxFileTypeInfo(const wxChar *mimeType, + const wxChar *openCmd, + const wxChar *printCmd, + const wxChar *desc, + ...) + : m_mimeType(mimeType), + m_openCmd(openCmd), + m_printCmd(printCmd), + m_desc(desc) +{ + va_list argptr; + va_start(argptr, desc); + + for ( ;; ) + { + // icc gives this warning in its own va_arg() macro, argh +#ifdef __INTELC__ + #pragma warning(push) + #pragma warning(disable: 1684) +#endif + + const wxChar *ext = va_arg(argptr, const wxChar *); + +#ifdef __INTELC__ + #pragma warning(pop) +#endif + if ( !ext ) + { + // NULL terminates the list + break; + } + + m_exts.Add(ext); + } + + va_end(argptr); +} + + +wxFileTypeInfo::wxFileTypeInfo(const wxArrayString& sArray) +{ + m_mimeType = sArray [0u]; + m_openCmd = sArray [1u]; + m_printCmd = sArray [2u]; + m_desc = sArray [3u]; + + size_t count = sArray.GetCount(); + for ( size_t i = 4; i < count; i++ ) + { + m_exts.Add(sArray[i]); + } +} + +#include "wx/arrimpl.cpp" +WX_DEFINE_OBJARRAY(wxArrayFileTypeInfo) + +// ============================================================================ +// implementation of the wrapper classes +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxFileType +// ---------------------------------------------------------------------------- + +/* static */ +wxString wxFileType::ExpandCommand(const wxString& command, + const wxFileType::MessageParameters& params) +{ + bool hasFilename = false; + + wxString str; + for ( const wxChar *pc = command.c_str(); *pc != wxT('\0'); pc++ ) { + if ( *pc == wxT('%') ) { + switch ( *++pc ) { + case wxT('s'): + // '%s' expands into file name (quoted because it might + // contain spaces) - except if there are already quotes + // there because otherwise some programs may get confused + // by double double quotes +#if 0 + if ( *(pc - 2) == wxT('"') ) + str << params.GetFileName(); + else + str << wxT('"') << params.GetFileName() << wxT('"'); +#endif + str << params.GetFileName(); + hasFilename = true; + break; + + case wxT('t'): + // '%t' expands into MIME type (quote it too just to be + // consistent) + str << wxT('\'') << params.GetMimeType() << wxT('\''); + break; + + case wxT('{'): + { + const wxChar *pEnd = wxStrchr(pc, wxT('}')); + if ( pEnd == NULL ) { + wxString mimetype; + wxLogWarning(_("Unmatched '{' in an entry for mime type %s."), + params.GetMimeType().c_str()); + str << wxT("%{"); + } + else { + wxString param(pc + 1, pEnd - pc - 1); + str << wxT('\'') << params.GetParamValue(param) << wxT('\''); + pc = pEnd; + } + } + break; + + case wxT('n'): + case wxT('F'): + // TODO %n is the number of parts, %F is an array containing + // the names of temp files these parts were written to + // and their mime types. + break; + + default: + wxLogDebug(wxT("Unknown field %%%c in command '%s'."), + *pc, command.c_str()); + str << *pc; + } + } + else { + str << *pc; + } + } + + // metamail(1) man page states that if the mailcap entry doesn't have '%s' + // the program will accept the data on stdin so normally we should append + // "< %s" to the end of the command in such case, but not all commands + // behave like this, in particular a common test is 'test -n "$DISPLAY"' + // and appending "< %s" to this command makes the test fail... I don't + // know of the correct solution, try to guess what we have to do. + + // test now carried out on reading file so test should never get here + if ( !hasFilename && !str.empty() +#ifdef __UNIX__ + && !str.StartsWith(_T("test ")) +#endif // Unix + ) { + str << wxT(" < '") << params.GetFileName() << wxT('\''); + } + + return str; +} + +wxFileType::wxFileType(const wxFileTypeInfo& info) +{ + m_info = &info; + m_impl = NULL; +} + +wxFileType::wxFileType() +{ + m_info = NULL; + m_impl = new wxFileTypeImpl; +} + +wxFileType::~wxFileType() +{ + if ( m_impl ) + delete m_impl; +} + +bool wxFileType::GetExtensions(wxArrayString& extensions) +{ + if ( m_info ) + { + extensions = m_info->GetExtensions(); + return true; + } + + return m_impl->GetExtensions(extensions); +} + +bool wxFileType::GetMimeType(wxString *mimeType) const +{ + wxCHECK_MSG( mimeType, false, _T("invalid parameter in GetMimeType") ); + + if ( m_info ) + { + *mimeType = m_info->GetMimeType(); + + return true; + } + + return m_impl->GetMimeType(mimeType); +} + +bool wxFileType::GetMimeTypes(wxArrayString& mimeTypes) const +{ + if ( m_info ) + { + mimeTypes.Clear(); + mimeTypes.Add(m_info->GetMimeType()); + + return true; + } + + return m_impl->GetMimeTypes(mimeTypes); +} + +bool wxFileType::GetIcon(wxIconLocation *iconLoc) const +{ + if ( m_info ) + { + if ( iconLoc ) + { + iconLoc->SetFileName(m_info->GetIconFile()); +#ifdef __WXMSW__ + iconLoc->SetIndex(m_info->GetIconIndex()); +#endif // __WXMSW__ + } + + return true; + } + + return m_impl->GetIcon(iconLoc); +} + +bool +wxFileType::GetIcon(wxIconLocation *iconloc, + const MessageParameters& params) const +{ + if ( !GetIcon(iconloc) ) + { + return false; + } + + // we may have "%s" in the icon location string, at least under Windows, so + // expand this + if ( iconloc ) + { + iconloc->SetFileName(ExpandCommand(iconloc->GetFileName(), params)); + } + + return true; +} + +bool wxFileType::GetDescription(wxString *desc) const +{ + wxCHECK_MSG( desc, false, _T("invalid parameter in GetDescription") ); + + if ( m_info ) + { + *desc = m_info->GetDescription(); + + return true; + } + + return m_impl->GetDescription(desc); +} + +bool +wxFileType::GetOpenCommand(wxString *openCmd, + const wxFileType::MessageParameters& params) const +{ + wxCHECK_MSG( openCmd, false, _T("invalid parameter in GetOpenCommand") ); + + if ( m_info ) + { + *openCmd = ExpandCommand(m_info->GetOpenCommand(), params); + + return true; + } + + return m_impl->GetOpenCommand(openCmd, params); +} + +wxString wxFileType::GetOpenCommand(const wxString& filename) const +{ + wxString cmd; + if ( !GetOpenCommand(&cmd, filename) ) + { + // return empty string to indicate an error + cmd.clear(); + } + + return cmd; +} + +bool +wxFileType::GetPrintCommand(wxString *printCmd, + const wxFileType::MessageParameters& params) const +{ + wxCHECK_MSG( printCmd, false, _T("invalid parameter in GetPrintCommand") ); + + if ( m_info ) + { + *printCmd = ExpandCommand(m_info->GetPrintCommand(), params); + + return true; + } + + return m_impl->GetPrintCommand(printCmd, params); +} + + +size_t wxFileType::GetAllCommands(wxArrayString *verbs, + wxArrayString *commands, + const wxFileType::MessageParameters& params) const +{ + if ( verbs ) + verbs->Clear(); + if ( commands ) + commands->Clear(); + +#if defined (__WXMSW__) || defined(__UNIX__) + return m_impl->GetAllCommands(verbs, commands, params); +#else // !__WXMSW__ || Unix + // we don't know how to retrieve all commands, so just try the 2 we know + // about + size_t count = 0; + wxString cmd; + if ( GetOpenCommand(&cmd, params) ) + { + if ( verbs ) + verbs->Add(_T("Open")); + if ( commands ) + commands->Add(cmd); + count++; + } + + if ( GetPrintCommand(&cmd, params) ) + { + if ( verbs ) + verbs->Add(_T("Print")); + if ( commands ) + commands->Add(cmd); + + count++; + } + + return count; +#endif // __WXMSW__/| __UNIX__ +} + +bool wxFileType::Unassociate() +{ +#if defined(__WXMSW__) + return m_impl->Unassociate(); +#elif defined(__UNIX__) + return m_impl->Unassociate(this); +#else + wxFAIL_MSG( _T("not implemented") ); // TODO + return false; +#endif +} + +bool wxFileType::SetCommand(const wxString& cmd, + const wxString& verb, + bool overwriteprompt) +{ +#if defined (__WXMSW__) || defined(__UNIX__) + return m_impl->SetCommand(cmd, verb, overwriteprompt); +#else + wxUnusedVar(cmd); + wxUnusedVar(verb); + wxUnusedVar(overwriteprompt); + wxFAIL_MSG(_T("not implemented")); + return false; +#endif +} + +bool wxFileType::SetDefaultIcon(const wxString& cmd, int index) +{ + wxString sTmp = cmd; +#ifdef __WXMSW__ + // VZ: should we do this? + // chris elliott : only makes sense in MS windows + if ( sTmp.empty() ) + GetOpenCommand(&sTmp, wxFileType::MessageParameters(wxEmptyString, wxEmptyString)); +#endif + wxCHECK_MSG( !sTmp.empty(), false, _T("need the icon file") ); + +#if defined (__WXMSW__) || defined(__UNIX__) + return m_impl->SetDefaultIcon (cmd, index); +#else + wxUnusedVar(index); + wxFAIL_MSG(_T("not implemented")); + return false; +#endif +} + +// ---------------------------------------------------------------------------- +// wxMimeTypesManagerFactory +// ---------------------------------------------------------------------------- + +wxMimeTypesManagerFactory *wxMimeTypesManagerFactory::m_factory = NULL; + +/* static */ +void wxMimeTypesManagerFactory::Set(wxMimeTypesManagerFactory *factory) +{ + delete m_factory; + + m_factory = factory; +} + +/* static */ +wxMimeTypesManagerFactory *wxMimeTypesManagerFactory::Get() +{ + if ( !m_factory ) + m_factory = new wxMimeTypesManagerFactory; + + return m_factory; +} + +wxMimeTypesManagerImpl *wxMimeTypesManagerFactory::CreateMimeTypesManagerImpl() +{ + return new wxMimeTypesManagerImpl; +} + +// ---------------------------------------------------------------------------- +// wxMimeTypesManager +// ---------------------------------------------------------------------------- + +void wxMimeTypesManager::EnsureImpl() +{ + if ( !m_impl ) + m_impl = wxMimeTypesManagerFactory::Get()->CreateMimeTypesManagerImpl(); +} + +bool wxMimeTypesManager::IsOfType(const wxString& mimeType, + const wxString& wildcard) +{ + wxASSERT_MSG( mimeType.Find(wxT('*')) == wxNOT_FOUND, + wxT("first MIME type can't contain wildcards") ); + + // all comparaisons are case insensitive (2nd arg of IsSameAs() is false) + if ( wildcard.BeforeFirst(wxT('/')). + IsSameAs(mimeType.BeforeFirst(wxT('/')), false) ) + { + wxString strSubtype = wildcard.AfterFirst(wxT('/')); + + if ( strSubtype == wxT("*") || + strSubtype.IsSameAs(mimeType.AfterFirst(wxT('/')), false) ) + { + // matches (either exactly or it's a wildcard) + return true; + } + } + + return false; +} + +wxMimeTypesManager::wxMimeTypesManager() +{ + m_impl = NULL; +} + +wxMimeTypesManager::~wxMimeTypesManager() +{ + if ( m_impl ) + delete m_impl; +} + +bool wxMimeTypesManager::Unassociate(wxFileType *ft) +{ + EnsureImpl(); + +#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__) + return m_impl->Unassociate(ft); +#else + return ft->Unassociate(); +#endif +} + + +wxFileType * +wxMimeTypesManager::Associate(const wxFileTypeInfo& ftInfo) +{ + EnsureImpl(); + +#if defined(__WXMSW__) || defined(__UNIX__) + return m_impl->Associate(ftInfo); +#else // other platforms + wxUnusedVar(ftInfo); + wxFAIL_MSG( _T("not implemented") ); // TODO + return NULL; +#endif // platforms +} + +wxFileType * +wxMimeTypesManager::GetFileTypeFromExtension(const wxString& ext) +{ + EnsureImpl(); + + wxString::const_iterator i = ext.begin(); + const wxString::const_iterator end = ext.end(); + wxString extWithoutDot; + if ( i != end && *i == '.' ) + extWithoutDot.assign(++i, ext.end()); + else + extWithoutDot = ext; + + wxCHECK_MSG( !ext.empty(), NULL, _T("extension can't be empty") ); + + wxFileType *ft = m_impl->GetFileTypeFromExtension(extWithoutDot); + + if ( !ft ) { + // check the fallbacks + // + // TODO linear search is potentially slow, perhaps we should use a + // sorted array? + size_t count = m_fallbacks.GetCount(); + for ( size_t n = 0; n < count; n++ ) { + if ( m_fallbacks[n].GetExtensions().Index(ext) != wxNOT_FOUND ) { + ft = new wxFileType(m_fallbacks[n]); + + break; + } + } + } + + return ft; +} + +wxFileType * +wxMimeTypesManager::GetFileTypeFromMimeType(const wxString& mimeType) +{ + EnsureImpl(); + wxFileType *ft = m_impl->GetFileTypeFromMimeType(mimeType); + + if ( !ft ) { + // check the fallbacks + // + // TODO linear search is potentially slow, perhaps we should use a + // sorted array? + size_t count = m_fallbacks.GetCount(); + for ( size_t n = 0; n < count; n++ ) { + if ( wxMimeTypesManager::IsOfType(mimeType, + m_fallbacks[n].GetMimeType()) ) { + ft = new wxFileType(m_fallbacks[n]); + + break; + } + } + } + + return ft; +} + +bool wxMimeTypesManager::ReadMailcap(const wxString& filename, bool fallback) +{ + EnsureImpl(); + return m_impl->ReadMailcap(filename, fallback); +} + +bool wxMimeTypesManager::ReadMimeTypes(const wxString& filename) +{ + EnsureImpl(); + return m_impl->ReadMimeTypes(filename); +} + +void wxMimeTypesManager::AddFallbacks(const wxFileTypeInfo *filetypes) +{ + EnsureImpl(); + for ( const wxFileTypeInfo *ft = filetypes; ft && ft->IsValid(); ft++ ) { + AddFallback(*ft); + } +} + +size_t wxMimeTypesManager::EnumAllFileTypes(wxArrayString& mimetypes) +{ + EnsureImpl(); + size_t countAll = m_impl->EnumAllFileTypes(mimetypes); + + // add the fallback filetypes + size_t count = m_fallbacks.GetCount(); + for ( size_t n = 0; n < count; n++ ) { + if ( mimetypes.Index(m_fallbacks[n].GetMimeType()) == wxNOT_FOUND ) { + mimetypes.Add(m_fallbacks[n].GetMimeType()); + countAll++; + } + } + + return countAll; +} + +void wxMimeTypesManager::Initialize(int mcapStyle, + const wxString& sExtraDir) +{ +#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__) + EnsureImpl(); + + m_impl->Initialize(mcapStyle, sExtraDir); +#else + (void)mcapStyle; + (void)sExtraDir; +#endif // Unix +} + +// and this function clears all the data from the manager +void wxMimeTypesManager::ClearData() +{ +#if defined(__UNIX__) && !defined(__CYGWIN__) && !defined(__WINE__) + EnsureImpl(); + + m_impl->ClearData(); +#endif // Unix +} + +// ---------------------------------------------------------------------------- +// global data and wxMimeTypeCmnModule +// ---------------------------------------------------------------------------- + +// private object +static wxMimeTypesManager gs_mimeTypesManager; + +// and public pointer +wxMimeTypesManager *wxTheMimeTypesManager = &gs_mimeTypesManager; + +class wxMimeTypeCmnModule: public wxModule +{ +public: + wxMimeTypeCmnModule() : wxModule() { } + + virtual bool OnInit() { return true; } + virtual void OnExit() + { + wxMimeTypesManagerFactory::Set(NULL); + + if ( gs_mimeTypesManager.m_impl != NULL ) + { + delete gs_mimeTypesManager.m_impl; + gs_mimeTypesManager.m_impl = NULL; + gs_mimeTypesManager.m_fallbacks.Clear(); + } + } + + DECLARE_DYNAMIC_CLASS(wxMimeTypeCmnModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxMimeTypeCmnModule, wxModule) + +#endif // wxUSE_MIMETYPE diff --git a/Source/3rd Party/wx/src/common/module.cpp b/Source/3rd Party/wx/src/common/module.cpp index ba5732e78..d4d963b63 100644 --- a/Source/3rd Party/wx/src/common/module.cpp +++ b/Source/3rd Party/wx/src/common/module.cpp @@ -1,202 +1,202 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/module.cpp -// Purpose: Modules initialization/destruction -// Author: Wolfram Gloger/adapted by Guilhem Lavaux -// Modified by: -// Created: 04/11/98 -// RCS-ID: $Id: module.cpp 39677 2006-06-11 22:19:12Z VZ $ -// Copyright: (c) Wolfram Gloger and Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/module.h" - -#ifndef WX_PRECOMP - #include "wx/hash.h" - #include "wx/intl.h" - #include "wx/log.h" -#endif - -#include "wx/listimpl.cpp" - -#define TRACE_MODULE _T("module") - -WX_DEFINE_LIST(wxModuleList) - -IMPLEMENT_CLASS(wxModule, wxObject) - -wxModuleList wxModule::m_modules; - -void wxModule::RegisterModule(wxModule* module) -{ - module->m_state = State_Registered; - m_modules.Append(module); -} - -void wxModule::UnregisterModule(wxModule* module) -{ - m_modules.DeleteObject(module); - delete module; -} - -// Collect up all module-derived classes, create an instance of each, -// and register them. -void wxModule::RegisterModules() -{ - wxHashTable::compatibility_iterator node; - wxClassInfo* classInfo; - - wxClassInfo::sm_classTable->BeginFind(); - node = wxClassInfo::sm_classTable->Next(); - while (node) - { - classInfo = (wxClassInfo *)node->GetData(); - if ( classInfo->IsKindOf(CLASSINFO(wxModule)) && - (classInfo != (& (wxModule::ms_classInfo))) ) - { - wxLogTrace(TRACE_MODULE, wxT("Registering module %s"), - classInfo->GetClassName()); - wxModule* module = (wxModule *)classInfo->CreateObject(); - RegisterModule(module); - } - node = wxClassInfo::sm_classTable->Next(); - } -} - -bool wxModule::DoInitializeModule(wxModule *module, - wxModuleList &initializedModules) -{ - if ( module->m_state == State_Initializing ) - { - wxLogError(_("Circular dependency involving module \"%s\" detected."), - module->GetClassInfo()->GetClassName()); - return false; - } - - module->m_state = State_Initializing; - - const wxArrayClassInfo& dependencies = module->m_dependencies; - - // satisfy module dependencies by loading them before the current module - for ( unsigned int i = 0; i < dependencies.size(); ++i ) - { - wxClassInfo * cinfo = dependencies[i]; - - // Check if the module is already initialized - wxModuleList::compatibility_iterator node; - for ( node = initializedModules.GetFirst(); node; node = node->GetNext() ) - { - if ( node->GetData()->GetClassInfo() == cinfo ) - break; - } - - if ( node ) - { - // this dependency is already initialized, nothing to do - continue; - } - - // find the module in the registered modules list - for ( node = m_modules.GetFirst(); node; node = node->GetNext() ) - { - wxModule *moduleDep = node->GetData(); - if ( moduleDep->GetClassInfo() == cinfo ) - { - if ( !DoInitializeModule(moduleDep, initializedModules ) ) - { - // failed to initialize a dependency, so fail this one too - return false; - } - - break; - } - } - - if ( !node ) - { - wxLogError(_("Dependency \"%s\" of module \"%s\" doesn't exist."), - cinfo->GetClassName(), - module->GetClassInfo()->GetClassName()); - return false; - } - } - - if ( !module->Init() ) - { - wxLogError(_("Module \"%s\" initialization failed"), - module->GetClassInfo()->GetClassName()); - return false; - } - - wxLogTrace(TRACE_MODULE, wxT("Module \"%s\" initialized"), - module->GetClassInfo()->GetClassName()); - - module->m_state = State_Initialized; - initializedModules.Append(module); - - return true; -} - -// Initialize user-defined modules -bool wxModule::InitializeModules() -{ - wxModuleList initializedModules; - - for ( wxModuleList::compatibility_iterator node = m_modules.GetFirst(); - node; - node = node->GetNext() ) - { - wxModule *module = node->GetData(); - - // the module could have been already initialized as dependency of - // another one - if ( module->m_state == State_Registered ) - { - if ( !DoInitializeModule( module, initializedModules ) ) - { - // failed to initialize all modules, so clean up the already - // initialized ones - DoCleanUpModules(initializedModules); - - return false; - } - } - } - - // remember the real initialisation order - m_modules = initializedModules; - - return true; -} - -// Clean up all currently initialized modules -void wxModule::DoCleanUpModules(const wxModuleList& modules) -{ - // cleanup user-defined modules in the reverse order compared to their - // initialization -- this ensures that dependencies are respected - for ( wxModuleList::compatibility_iterator node = modules.GetLast(); - node; - node = node->GetPrevious() ) - { - wxLogTrace(TRACE_MODULE, wxT("Cleanup module %s"), - node->GetData()->GetClassInfo()->GetClassName()); - - wxModule * module = node->GetData(); - - wxASSERT_MSG( module->m_state == State_Initialized, - _T("not initialized module being cleaned up") ); - - module->Exit(); - module->m_state = State_Registered; - } - - // clear all modules, even the non-initialized ones - WX_CLEAR_LIST(wxModuleList, m_modules); -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/module.cpp +// Purpose: Modules initialization/destruction +// Author: Wolfram Gloger/adapted by Guilhem Lavaux +// Modified by: +// Created: 04/11/98 +// RCS-ID: $Id: module.cpp 39677 2006-06-11 22:19:12Z VZ $ +// Copyright: (c) Wolfram Gloger and Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/module.h" + +#ifndef WX_PRECOMP + #include "wx/hash.h" + #include "wx/intl.h" + #include "wx/log.h" +#endif + +#include "wx/listimpl.cpp" + +#define TRACE_MODULE _T("module") + +WX_DEFINE_LIST(wxModuleList) + +IMPLEMENT_CLASS(wxModule, wxObject) + +wxModuleList wxModule::m_modules; + +void wxModule::RegisterModule(wxModule* module) +{ + module->m_state = State_Registered; + m_modules.Append(module); +} + +void wxModule::UnregisterModule(wxModule* module) +{ + m_modules.DeleteObject(module); + delete module; +} + +// Collect up all module-derived classes, create an instance of each, +// and register them. +void wxModule::RegisterModules() +{ + wxHashTable::compatibility_iterator node; + wxClassInfo* classInfo; + + wxClassInfo::sm_classTable->BeginFind(); + node = wxClassInfo::sm_classTable->Next(); + while (node) + { + classInfo = (wxClassInfo *)node->GetData(); + if ( classInfo->IsKindOf(CLASSINFO(wxModule)) && + (classInfo != (& (wxModule::ms_classInfo))) ) + { + wxLogTrace(TRACE_MODULE, wxT("Registering module %s"), + classInfo->GetClassName()); + wxModule* module = (wxModule *)classInfo->CreateObject(); + RegisterModule(module); + } + node = wxClassInfo::sm_classTable->Next(); + } +} + +bool wxModule::DoInitializeModule(wxModule *module, + wxModuleList &initializedModules) +{ + if ( module->m_state == State_Initializing ) + { + wxLogError(_("Circular dependency involving module \"%s\" detected."), + module->GetClassInfo()->GetClassName()); + return false; + } + + module->m_state = State_Initializing; + + const wxArrayClassInfo& dependencies = module->m_dependencies; + + // satisfy module dependencies by loading them before the current module + for ( unsigned int i = 0; i < dependencies.size(); ++i ) + { + wxClassInfo * cinfo = dependencies[i]; + + // Check if the module is already initialized + wxModuleList::compatibility_iterator node; + for ( node = initializedModules.GetFirst(); node; node = node->GetNext() ) + { + if ( node->GetData()->GetClassInfo() == cinfo ) + break; + } + + if ( node ) + { + // this dependency is already initialized, nothing to do + continue; + } + + // find the module in the registered modules list + for ( node = m_modules.GetFirst(); node; node = node->GetNext() ) + { + wxModule *moduleDep = node->GetData(); + if ( moduleDep->GetClassInfo() == cinfo ) + { + if ( !DoInitializeModule(moduleDep, initializedModules ) ) + { + // failed to initialize a dependency, so fail this one too + return false; + } + + break; + } + } + + if ( !node ) + { + wxLogError(_("Dependency \"%s\" of module \"%s\" doesn't exist."), + cinfo->GetClassName(), + module->GetClassInfo()->GetClassName()); + return false; + } + } + + if ( !module->Init() ) + { + wxLogError(_("Module \"%s\" initialization failed"), + module->GetClassInfo()->GetClassName()); + return false; + } + + wxLogTrace(TRACE_MODULE, wxT("Module \"%s\" initialized"), + module->GetClassInfo()->GetClassName()); + + module->m_state = State_Initialized; + initializedModules.Append(module); + + return true; +} + +// Initialize user-defined modules +bool wxModule::InitializeModules() +{ + wxModuleList initializedModules; + + for ( wxModuleList::compatibility_iterator node = m_modules.GetFirst(); + node; + node = node->GetNext() ) + { + wxModule *module = node->GetData(); + + // the module could have been already initialized as dependency of + // another one + if ( module->m_state == State_Registered ) + { + if ( !DoInitializeModule( module, initializedModules ) ) + { + // failed to initialize all modules, so clean up the already + // initialized ones + DoCleanUpModules(initializedModules); + + return false; + } + } + } + + // remember the real initialisation order + m_modules = initializedModules; + + return true; +} + +// Clean up all currently initialized modules +void wxModule::DoCleanUpModules(const wxModuleList& modules) +{ + // cleanup user-defined modules in the reverse order compared to their + // initialization -- this ensures that dependencies are respected + for ( wxModuleList::compatibility_iterator node = modules.GetLast(); + node; + node = node->GetPrevious() ) + { + wxLogTrace(TRACE_MODULE, wxT("Cleanup module %s"), + node->GetData()->GetClassInfo()->GetClassName()); + + wxModule * module = node->GetData(); + + wxASSERT_MSG( module->m_state == State_Initialized, + _T("not initialized module being cleaned up") ); + + module->Exit(); + module->m_state = State_Registered; + } + + // clear all modules, even the non-initialized ones + WX_CLEAR_LIST(wxModuleList, m_modules); +} diff --git a/Source/3rd Party/wx/src/common/msgout.cpp b/Source/3rd Party/wx/src/common/msgout.cpp index 1b2026ba9..ebeed13be 100644 --- a/Source/3rd Party/wx/src/common/msgout.cpp +++ b/Source/3rd Party/wx/src/common/msgout.cpp @@ -1,222 +1,222 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/msgout.cpp -// Purpose: wxMessageOutput implementation -// Author: Mattia Barbon -// Modified by: -// Created: 17.07.02 -// RCS-ID: $Id: msgout.cpp 38920 2006-04-26 08:21:31Z ABX $ -// Copyright: (c) the wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/ffile.h" - #include "wx/app.h" - #include "wx/intl.h" - #include "wx/log.h" - #if wxUSE_GUI - #include "wx/msgdlg.h" - #endif // wxUSE_GUI -#endif - -#include "wx/msgout.h" -#include "wx/apptrait.h" -#include -#include - -#if defined(__WINDOWS__) - #include "wx/msw/private.h" -#endif -#ifdef __WXMAC__ - #include "wx/mac/private.h" -#endif - -// =========================================================================== -// implementation -// =========================================================================== - -#if wxUSE_BASE - -// ---------------------------------------------------------------------------- -// wxMessageOutput -// ---------------------------------------------------------------------------- - -wxMessageOutput* wxMessageOutput::ms_msgOut = 0; - -wxMessageOutput* wxMessageOutput::Get() -{ - if ( !ms_msgOut && wxTheApp ) - { - ms_msgOut = wxTheApp->GetTraits()->CreateMessageOutput(); - } - - return ms_msgOut; -} - -wxMessageOutput* wxMessageOutput::Set(wxMessageOutput* msgout) -{ - wxMessageOutput* old = ms_msgOut; - ms_msgOut = msgout; - return old; -} - -// ---------------------------------------------------------------------------- -// wxMessageOutputBest -// ---------------------------------------------------------------------------- - -#ifdef __WINDOWS__ - -// check if we're running in a console under Windows -static inline bool IsInConsole() -{ -#ifdef __WXWINCE__ - return false; -#else // !__WXWINCE__ - HANDLE hStdErr = ::GetStdHandle(STD_ERROR_HANDLE); - return hStdErr && hStdErr != INVALID_HANDLE_VALUE; -#endif // __WXWINCE__/!__WXWINCE__ -} - -#endif // __WINDOWS__ - -void wxMessageOutputBest::Printf(const wxChar* format, ...) -{ - va_list args; - va_start(args, format); - wxString out; - - out.PrintfV(format, args); - va_end(args); - -#ifdef __WINDOWS__ - if ( !IsInConsole() ) - { - ::MessageBox(NULL, out, _T("wxWidgets"), MB_ICONINFORMATION | MB_OK); - } - else -#endif // __WINDOWS__/!__WINDOWS__ - { - fprintf(stderr, "%s", (const char*) out.mb_str()); - } -} - -// ---------------------------------------------------------------------------- -// wxMessageOutputStderr -// ---------------------------------------------------------------------------- - -void wxMessageOutputStderr::Printf(const wxChar* format, ...) -{ - va_list args; - va_start(args, format); - wxString out; - - out.PrintfV(format, args); - va_end(args); - - fprintf(stderr, "%s", (const char*) out.mb_str()); -} - -// ---------------------------------------------------------------------------- -// wxMessageOutputDebug -// ---------------------------------------------------------------------------- - -void wxMessageOutputDebug::Printf(const wxChar* format, ...) -{ - wxString out; - - va_list args; - va_start(args, format); - - out.PrintfV(format, args); - va_end(args); - -#if defined(__WXMSW__) && !defined(__WXMICROWIN__) - out.Replace(wxT("\t"), wxT(" ")); - out.Replace(wxT("\n"), wxT("\r\n")); - ::OutputDebugString(out); -#elif defined(__WXMAC__) && !defined(__DARWIN__) - if ( wxIsDebuggerRunning() ) - { - Str255 pstr; - wxString output = out + wxT(";g") ; - wxMacStringToPascal(output.c_str(), pstr); - - #ifdef __powerc - DebugStr(pstr); - #else - SysBreakStr(pstr); - #endif - } -#else - wxFputs( out , stderr ) ; - if ( out.Right(1) != wxT("\n") ) - wxFputs( wxT("\n") , stderr ) ; - fflush( stderr ) ; -#endif // platform -} - -// ---------------------------------------------------------------------------- -// wxMessageOutputLog -// ---------------------------------------------------------------------------- - -void wxMessageOutputLog::Printf(const wxChar* format, ...) -{ - wxString out; - - va_list args; - va_start(args, format); - - out.PrintfV(format, args); - va_end(args); - - out.Replace(wxT("\t"), wxT(" ")); - - ::wxLogMessage(wxT("%s"), out.c_str()); -} - -#endif // wxUSE_BASE - -// ---------------------------------------------------------------------------- -// wxMessageOutputMessageBox -// ---------------------------------------------------------------------------- - -#if wxUSE_GUI - -void wxMessageOutputMessageBox::Printf(const wxChar* format, ...) -{ - va_list args; - va_start(args, format); - wxString out; - - out.PrintfV(format, args); - va_end(args); - - // the native MSW msg box understands the TABs, others don't -#ifndef __WXMSW__ - out.Replace(wxT("\t"), wxT(" ")); -#endif - - wxString title; - if ( wxTheApp ) - title.Printf(_("%s message"), wxTheApp->GetAppName().c_str()); - - ::wxMessageBox(out, title); -} - -#endif // wxUSE_GUI +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/msgout.cpp +// Purpose: wxMessageOutput implementation +// Author: Mattia Barbon +// Modified by: +// Created: 17.07.02 +// RCS-ID: $Id: msgout.cpp 38920 2006-04-26 08:21:31Z ABX $ +// Copyright: (c) the wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/ffile.h" + #include "wx/app.h" + #include "wx/intl.h" + #include "wx/log.h" + #if wxUSE_GUI + #include "wx/msgdlg.h" + #endif // wxUSE_GUI +#endif + +#include "wx/msgout.h" +#include "wx/apptrait.h" +#include +#include + +#if defined(__WINDOWS__) + #include "wx/msw/private.h" +#endif +#ifdef __WXMAC__ + #include "wx/mac/private.h" +#endif + +// =========================================================================== +// implementation +// =========================================================================== + +#if wxUSE_BASE + +// ---------------------------------------------------------------------------- +// wxMessageOutput +// ---------------------------------------------------------------------------- + +wxMessageOutput* wxMessageOutput::ms_msgOut = 0; + +wxMessageOutput* wxMessageOutput::Get() +{ + if ( !ms_msgOut && wxTheApp ) + { + ms_msgOut = wxTheApp->GetTraits()->CreateMessageOutput(); + } + + return ms_msgOut; +} + +wxMessageOutput* wxMessageOutput::Set(wxMessageOutput* msgout) +{ + wxMessageOutput* old = ms_msgOut; + ms_msgOut = msgout; + return old; +} + +// ---------------------------------------------------------------------------- +// wxMessageOutputBest +// ---------------------------------------------------------------------------- + +#ifdef __WINDOWS__ + +// check if we're running in a console under Windows +static inline bool IsInConsole() +{ +#ifdef __WXWINCE__ + return false; +#else // !__WXWINCE__ + HANDLE hStdErr = ::GetStdHandle(STD_ERROR_HANDLE); + return hStdErr && hStdErr != INVALID_HANDLE_VALUE; +#endif // __WXWINCE__/!__WXWINCE__ +} + +#endif // __WINDOWS__ + +void wxMessageOutputBest::Printf(const wxChar* format, ...) +{ + va_list args; + va_start(args, format); + wxString out; + + out.PrintfV(format, args); + va_end(args); + +#ifdef __WINDOWS__ + if ( !IsInConsole() ) + { + ::MessageBox(NULL, out, _T("wxWidgets"), MB_ICONINFORMATION | MB_OK); + } + else +#endif // __WINDOWS__/!__WINDOWS__ + { + fprintf(stderr, "%s", (const char*) out.mb_str()); + } +} + +// ---------------------------------------------------------------------------- +// wxMessageOutputStderr +// ---------------------------------------------------------------------------- + +void wxMessageOutputStderr::Printf(const wxChar* format, ...) +{ + va_list args; + va_start(args, format); + wxString out; + + out.PrintfV(format, args); + va_end(args); + + fprintf(stderr, "%s", (const char*) out.mb_str()); +} + +// ---------------------------------------------------------------------------- +// wxMessageOutputDebug +// ---------------------------------------------------------------------------- + +void wxMessageOutputDebug::Printf(const wxChar* format, ...) +{ + wxString out; + + va_list args; + va_start(args, format); + + out.PrintfV(format, args); + va_end(args); + +#if defined(__WXMSW__) && !defined(__WXMICROWIN__) + out.Replace(wxT("\t"), wxT(" ")); + out.Replace(wxT("\n"), wxT("\r\n")); + ::OutputDebugString(out); +#elif defined(__WXMAC__) && !defined(__DARWIN__) + if ( wxIsDebuggerRunning() ) + { + Str255 pstr; + wxString output = out + wxT(";g") ; + wxMacStringToPascal(output.c_str(), pstr); + + #ifdef __powerc + DebugStr(pstr); + #else + SysBreakStr(pstr); + #endif + } +#else + wxFputs( out , stderr ) ; + if ( out.Right(1) != wxT("\n") ) + wxFputs( wxT("\n") , stderr ) ; + fflush( stderr ) ; +#endif // platform +} + +// ---------------------------------------------------------------------------- +// wxMessageOutputLog +// ---------------------------------------------------------------------------- + +void wxMessageOutputLog::Printf(const wxChar* format, ...) +{ + wxString out; + + va_list args; + va_start(args, format); + + out.PrintfV(format, args); + va_end(args); + + out.Replace(wxT("\t"), wxT(" ")); + + ::wxLogMessage(wxT("%s"), out.c_str()); +} + +#endif // wxUSE_BASE + +// ---------------------------------------------------------------------------- +// wxMessageOutputMessageBox +// ---------------------------------------------------------------------------- + +#if wxUSE_GUI + +void wxMessageOutputMessageBox::Printf(const wxChar* format, ...) +{ + va_list args; + va_start(args, format); + wxString out; + + out.PrintfV(format, args); + va_end(args); + + // the native MSW msg box understands the TABs, others don't +#ifndef __WXMSW__ + out.Replace(wxT("\t"), wxT(" ")); +#endif + + wxString title; + if ( wxTheApp ) + title.Printf(_("%s message"), wxTheApp->GetAppName().c_str()); + + ::wxMessageBox(out, title); +} + +#endif // wxUSE_GUI diff --git a/Source/3rd Party/wx/src/common/mstream.cpp b/Source/3rd Party/wx/src/common/mstream.cpp index 35aac9292..cbefd2a7c 100644 --- a/Source/3rd Party/wx/src/common/mstream.cpp +++ b/Source/3rd Party/wx/src/common/mstream.cpp @@ -1,174 +1,174 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/mstream.cpp -// Purpose: "Memory stream" classes -// Author: Guilhem Lavaux -// Modified by: VZ (23.11.00): general code review -// Created: 04/01/98 -// RCS-ID: $Id: mstream.cpp 39001 2006-05-03 21:50:35Z ABX $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#include "wx/mstream.h" - -#ifndef WX_PRECOMP - #include "wx/stream.h" -#endif //WX_PRECOMP - -#include - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxMemoryInputStream -// ---------------------------------------------------------------------------- - -wxMemoryInputStream::wxMemoryInputStream(const void *data, size_t len) -{ - m_i_streambuf = new wxStreamBuffer(wxStreamBuffer::read); - m_i_streambuf->SetBufferIO((void *)data, len); // const_cast - m_i_streambuf->SetIntPosition(0); // seek to start pos - m_i_streambuf->Fixed(true); - - m_length = len; -} - -wxMemoryInputStream::wxMemoryInputStream(const wxMemoryOutputStream& stream) -{ - const wxFileOffset lenFile = stream.GetLength(); - if ( lenFile == wxInvalidOffset ) - { - m_i_streambuf = NULL; - m_lasterror = wxSTREAM_EOF; - return; - } - - const size_t len = wx_truncate_cast(size_t, lenFile); - wxASSERT_MSG( len == lenFile + size_t(0), _T("huge files not supported") ); - - m_i_streambuf = new wxStreamBuffer(wxStreamBuffer::read); - m_i_streambuf->SetBufferIO(len); // create buffer - stream.CopyTo(m_i_streambuf->GetBufferStart(), len); - m_i_streambuf->SetIntPosition(0); // seek to start pos - m_i_streambuf->Fixed(true); - m_length = len; -} - -wxMemoryInputStream::~wxMemoryInputStream() -{ - delete m_i_streambuf; -} - -char wxMemoryInputStream::Peek() -{ - char *buf = (char *)m_i_streambuf->GetBufferStart(); - size_t pos = m_i_streambuf->GetIntPosition(); - if ( pos == m_length ) - { - m_lasterror = wxSTREAM_READ_ERROR; - - return 0; - } - - return buf[pos]; -} - -size_t wxMemoryInputStream::OnSysRead(void *buffer, size_t nbytes) -{ - size_t pos = m_i_streambuf->GetIntPosition(); - if ( pos == m_length ) - { - m_lasterror = wxSTREAM_EOF; - - return 0; - } - - m_i_streambuf->Read(buffer, nbytes); - m_lasterror = wxSTREAM_NO_ERROR; - - return m_i_streambuf->GetIntPosition() - pos; -} - -wxFileOffset wxMemoryInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - return m_i_streambuf->Seek(pos, mode); -} - -wxFileOffset wxMemoryInputStream::OnSysTell() const -{ - return m_i_streambuf->Tell(); -} - -// ---------------------------------------------------------------------------- -// wxMemoryOutputStream -// ---------------------------------------------------------------------------- - -wxMemoryOutputStream::wxMemoryOutputStream(void *data, size_t len) -{ - m_o_streambuf = new wxStreamBuffer(wxStreamBuffer::write); - if ( data ) - m_o_streambuf->SetBufferIO(data, len); - m_o_streambuf->Fixed(false); - m_o_streambuf->Flushable(false); -} - -wxMemoryOutputStream::~wxMemoryOutputStream() -{ - delete m_o_streambuf; -} - -size_t wxMemoryOutputStream::OnSysWrite(const void *buffer, size_t nbytes) -{ - size_t oldpos = m_o_streambuf->GetIntPosition(); - m_o_streambuf->Write(buffer, nbytes); - size_t newpos = m_o_streambuf->GetIntPosition(); - - // FIXME can someone please explain what this does? (VZ) - if ( !newpos ) - newpos = m_o_streambuf->GetBufferSize(); - - return newpos - oldpos; -} - -wxFileOffset wxMemoryOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - return m_o_streambuf->Seek(pos, mode); -} - -wxFileOffset wxMemoryOutputStream::OnSysTell() const -{ - return m_o_streambuf->Tell(); -} - -size_t wxMemoryOutputStream::CopyTo(void *buffer, size_t len) const -{ - wxCHECK_MSG( buffer, 0, _T("must have buffer to CopyTo") ); - - if ( len > GetSize() ) - len = GetSize(); - - memcpy(buffer, m_o_streambuf->GetBufferStart(), len); - - return len; -} - -#endif // wxUSE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/mstream.cpp +// Purpose: "Memory stream" classes +// Author: Guilhem Lavaux +// Modified by: VZ (23.11.00): general code review +// Created: 04/01/98 +// RCS-ID: $Id: mstream.cpp 39001 2006-05-03 21:50:35Z ABX $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#include "wx/mstream.h" + +#ifndef WX_PRECOMP + #include "wx/stream.h" +#endif //WX_PRECOMP + +#include + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxMemoryInputStream +// ---------------------------------------------------------------------------- + +wxMemoryInputStream::wxMemoryInputStream(const void *data, size_t len) +{ + m_i_streambuf = new wxStreamBuffer(wxStreamBuffer::read); + m_i_streambuf->SetBufferIO((void *)data, len); // const_cast + m_i_streambuf->SetIntPosition(0); // seek to start pos + m_i_streambuf->Fixed(true); + + m_length = len; +} + +wxMemoryInputStream::wxMemoryInputStream(const wxMemoryOutputStream& stream) +{ + const wxFileOffset lenFile = stream.GetLength(); + if ( lenFile == wxInvalidOffset ) + { + m_i_streambuf = NULL; + m_lasterror = wxSTREAM_EOF; + return; + } + + const size_t len = wx_truncate_cast(size_t, lenFile); + wxASSERT_MSG( len == lenFile + size_t(0), _T("huge files not supported") ); + + m_i_streambuf = new wxStreamBuffer(wxStreamBuffer::read); + m_i_streambuf->SetBufferIO(len); // create buffer + stream.CopyTo(m_i_streambuf->GetBufferStart(), len); + m_i_streambuf->SetIntPosition(0); // seek to start pos + m_i_streambuf->Fixed(true); + m_length = len; +} + +wxMemoryInputStream::~wxMemoryInputStream() +{ + delete m_i_streambuf; +} + +char wxMemoryInputStream::Peek() +{ + char *buf = (char *)m_i_streambuf->GetBufferStart(); + size_t pos = m_i_streambuf->GetIntPosition(); + if ( pos == m_length ) + { + m_lasterror = wxSTREAM_READ_ERROR; + + return 0; + } + + return buf[pos]; +} + +size_t wxMemoryInputStream::OnSysRead(void *buffer, size_t nbytes) +{ + size_t pos = m_i_streambuf->GetIntPosition(); + if ( pos == m_length ) + { + m_lasterror = wxSTREAM_EOF; + + return 0; + } + + m_i_streambuf->Read(buffer, nbytes); + m_lasterror = wxSTREAM_NO_ERROR; + + return m_i_streambuf->GetIntPosition() - pos; +} + +wxFileOffset wxMemoryInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + return m_i_streambuf->Seek(pos, mode); +} + +wxFileOffset wxMemoryInputStream::OnSysTell() const +{ + return m_i_streambuf->Tell(); +} + +// ---------------------------------------------------------------------------- +// wxMemoryOutputStream +// ---------------------------------------------------------------------------- + +wxMemoryOutputStream::wxMemoryOutputStream(void *data, size_t len) +{ + m_o_streambuf = new wxStreamBuffer(wxStreamBuffer::write); + if ( data ) + m_o_streambuf->SetBufferIO(data, len); + m_o_streambuf->Fixed(false); + m_o_streambuf->Flushable(false); +} + +wxMemoryOutputStream::~wxMemoryOutputStream() +{ + delete m_o_streambuf; +} + +size_t wxMemoryOutputStream::OnSysWrite(const void *buffer, size_t nbytes) +{ + size_t oldpos = m_o_streambuf->GetIntPosition(); + m_o_streambuf->Write(buffer, nbytes); + size_t newpos = m_o_streambuf->GetIntPosition(); + + // FIXME can someone please explain what this does? (VZ) + if ( !newpos ) + newpos = m_o_streambuf->GetBufferSize(); + + return newpos - oldpos; +} + +wxFileOffset wxMemoryOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + return m_o_streambuf->Seek(pos, mode); +} + +wxFileOffset wxMemoryOutputStream::OnSysTell() const +{ + return m_o_streambuf->Tell(); +} + +size_t wxMemoryOutputStream::CopyTo(void *buffer, size_t len) const +{ + wxCHECK_MSG( buffer, 0, _T("must have buffer to CopyTo") ); + + if ( len > GetSize() ) + len = GetSize(); + + memcpy(buffer, m_o_streambuf->GetBufferStart(), len); + + return len; +} + +#endif // wxUSE_STREAMS diff --git a/Source/3rd Party/wx/src/common/nbkbase.cpp b/Source/3rd Party/wx/src/common/nbkbase.cpp index b63c93585..011f53e16 100644 --- a/Source/3rd Party/wx/src/common/nbkbase.cpp +++ b/Source/3rd Party/wx/src/common/nbkbase.cpp @@ -1,84 +1,84 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/nbkbase.cpp -// Purpose: common wxNotebook methods -// Author: Vadim Zeitlin -// Modified by: -// Created: 02.07.01 -// RCS-ID: $Id: nbkbase.cpp 41764 2006-10-08 23:41:52Z VZ $ -// Copyright: (c) 2001 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_NOTEBOOK - -#ifndef WX_PRECOMP -#endif //WX_PRECOMP - -#include "wx/notebook.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// geometry -// ---------------------------------------------------------------------------- - -wxSize wxNotebookBase::CalcSizeFromPage(const wxSize& sizePage) const -{ - // this is, of course, totally bogus -- but we must do something by - // default because not all ports implement this - wxSize sizeTotal = sizePage; - - if ( HasFlag(wxBK_LEFT) || HasFlag(wxBK_RIGHT) ) - { - sizeTotal.x += 90; - sizeTotal.y += 10; - } - else // tabs on top/bottom side - { - sizeTotal.x += 10; - sizeTotal.y += 40; - } - - return sizeTotal; -} - -// ---------------------------------------------------------------------------- -// events -// ---------------------------------------------------------------------------- - -bool wxNotebookBase::SendPageChangingEvent(int nPage) -{ - wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, GetId()); - event.SetSelection(nPage); - event.SetOldSelection(GetSelection()); - event.SetEventObject(this); - return !GetEventHandler()->ProcessEvent(event) || event.IsAllowed(); -} - -void wxNotebookBase::SendPageChangedEvent(int nPageOld, int nPageNew) -{ - wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, GetId()); - event.SetSelection(nPageNew == -1 ? GetSelection() : nPageNew); - event.SetOldSelection(nPageOld); - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); -} - -#endif // wxUSE_NOTEBOOK +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/nbkbase.cpp +// Purpose: common wxNotebook methods +// Author: Vadim Zeitlin +// Modified by: +// Created: 02.07.01 +// RCS-ID: $Id: nbkbase.cpp 41764 2006-10-08 23:41:52Z VZ $ +// Copyright: (c) 2001 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_NOTEBOOK + +#ifndef WX_PRECOMP +#endif //WX_PRECOMP + +#include "wx/notebook.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// geometry +// ---------------------------------------------------------------------------- + +wxSize wxNotebookBase::CalcSizeFromPage(const wxSize& sizePage) const +{ + // this is, of course, totally bogus -- but we must do something by + // default because not all ports implement this + wxSize sizeTotal = sizePage; + + if ( HasFlag(wxBK_LEFT) || HasFlag(wxBK_RIGHT) ) + { + sizeTotal.x += 90; + sizeTotal.y += 10; + } + else // tabs on top/bottom side + { + sizeTotal.x += 10; + sizeTotal.y += 40; + } + + return sizeTotal; +} + +// ---------------------------------------------------------------------------- +// events +// ---------------------------------------------------------------------------- + +bool wxNotebookBase::SendPageChangingEvent(int nPage) +{ + wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, GetId()); + event.SetSelection(nPage); + event.SetOldSelection(GetSelection()); + event.SetEventObject(this); + return !GetEventHandler()->ProcessEvent(event) || event.IsAllowed(); +} + +void wxNotebookBase::SendPageChangedEvent(int nPageOld, int nPageNew) +{ + wxNotebookEvent event(wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, GetId()); + event.SetSelection(nPageNew == -1 ? GetSelection() : nPageNew); + event.SetOldSelection(nPageOld); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); +} + +#endif // wxUSE_NOTEBOOK diff --git a/Source/3rd Party/wx/src/common/object.cpp b/Source/3rd Party/wx/src/common/object.cpp index f4370c40c..24eddcde7 100644 --- a/Source/3rd Party/wx/src/common/object.cpp +++ b/Source/3rd Party/wx/src/common/object.cpp @@ -1,390 +1,390 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/object.cpp -// Purpose: wxObject implementation -// Author: Julian Smart -// Modified by: Ron Lee -// Created: 04/01/98 -// RCS-ID: $Id: object.cpp 56500 2008-10-23 14:48:31Z MW $ -// Copyright: (c) 1998 Julian Smart -// (c) 2001 Ron Lee -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/hash.h" - #include "wx/memory.h" -#endif - -#include - -#if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT - #if defined(__VISAGECPP__) - #define DEBUG_PRINTF(NAME) { static int raz=0; \ - printf( #NAME " %i\n",raz); fflush(stdout); raz++; } - #else - #define DEBUG_PRINTF(NAME) - #endif -#endif // __WXDEBUG__ || wxUSE_DEBUG_CONTEXT - -// we must disable optimizations for VC.NET because otherwise its too eager -// linker discards wxClassInfo objects in release build thus breaking many, -// many things -#if defined __VISUALC__ && __VISUALC__ >= 1300 - #pragma optimize("", off) -#endif - -#if wxUSE_EXTENDED_RTTI -const wxClassInfo* wxObject::ms_classParents[] = { NULL } ; - wxObject* wxVariantToObjectConverterwxObject ( wxxVariant &data ) -{ return data.wxTEMPLATED_MEMBER_CALL(Get , wxObject*) ; } - wxObject* wxVariantOfPtrToObjectConverterwxObject ( wxxVariant &data ) -{ return &data.wxTEMPLATED_MEMBER_CALL(Get , wxObject) ; } - wxxVariant wxObjectToVariantConverterwxObject ( wxObject *data ) - { return wxxVariant( dynamic_cast (data) ) ; } - wxClassInfo wxObject::ms_classInfo(ms_classParents , wxEmptyString , wxT("wxObject"), - (int) sizeof(wxObject), \ - (wxObjectConstructorFn) 0 , - (wxPropertyInfo*) NULL,(wxHandlerInfo*) NULL,0 , 0 , - 0 , wxVariantOfPtrToObjectConverterwxObject , wxVariantToObjectConverterwxObject , wxObjectToVariantConverterwxObject); - template<> void wxStringReadValue(const wxString & , wxObject * & ){assert(0) ;} - template<> void wxStringWriteValue(wxString & , wxObject* const & ){assert(0) ;} - template<> void wxStringReadValue(const wxString & , wxObject & ){assert(0) ;} - template<> void wxStringWriteValue(wxString & , wxObject const & ){assert(0) ;} - wxClassTypeInfo s_typeInfo(wxT_OBJECT_PTR , &wxObject::ms_classInfo , NULL , NULL , typeid(wxObject*).name() ) ; - wxClassTypeInfo s_typeInfowxObject(wxT_OBJECT , &wxObject::ms_classInfo , NULL , NULL , typeid(wxObject).name() ) ; -#else -wxClassInfo wxObject::ms_classInfo( wxT("wxObject"), 0, 0, - (int) sizeof(wxObject), - (wxObjectConstructorFn) 0 ); -#endif - -// restore optimizations -#if defined __VISUALC__ && __VISUALC__ >= 1300 - #pragma optimize("", on) -#endif - -wxClassInfo* wxClassInfo::sm_first = NULL; -wxHashTable* wxClassInfo::sm_classTable = NULL; - -// when using XTI, this method is already implemented inline inside -// DECLARE_DYNAMIC_CLASS but otherwise we intentionally make this function -// non-inline because this allows us to have a non-inline virtual function in -// all wx classes and this solves linking problems for HP-UX native toolchain -// and possibly others (we could make dtor non-inline as well but it's more -// useful to keep it inline than this function) -#if !wxUSE_EXTENDED_RTTI - -wxClassInfo *wxObject::GetClassInfo() const -{ - return &wxObject::ms_classInfo; -} - -#endif // wxUSE_EXTENDED_RTTI - -// this variable exists only so that we can avoid 'always true/false' warnings -const bool wxFalse = false; - -// Is this object a kind of (a subclass of) 'info'? -// E.g. is wxWindow a kind of wxObject? -// Go from this class to superclass, taking into account -// two possible base classes. -bool wxObject::IsKindOf(wxClassInfo *info) const -{ - wxClassInfo *thisInfo = GetClassInfo(); - return (thisInfo) ? thisInfo->IsKindOf(info) : false ; -} - -#if defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING && defined( new ) - #undef new -#endif - - -#ifdef _WX_WANT_NEW_SIZET_WXCHAR_INT -void *wxObject::operator new ( size_t size, const wxChar *fileName, int lineNum ) -{ - return wxDebugAlloc(size, (wxChar*) fileName, lineNum, true); -} -#endif - -#ifdef _WX_WANT_DELETE_VOID -void wxObject::operator delete ( void *buf ) -{ - wxDebugFree(buf); -} -#endif - -#ifdef _WX_WANT_DELETE_VOID_CONSTCHAR_SIZET -void wxObject::operator delete ( void *buf, const char *_fname, size_t _line ) -{ - wxDebugFree(buf); -} -#endif - -#ifdef _WX_WANT_DELETE_VOID_WXCHAR_INT -void wxObject::operator delete ( void *buf, const wxChar *WXUNUSED(fileName), int WXUNUSED(lineNum) ) -{ - wxDebugFree(buf); -} -#endif - -#ifdef _WX_WANT_ARRAY_NEW_SIZET_WXCHAR_INT -void *wxObject::operator new[] ( size_t size, const wxChar* fileName, int lineNum ) -{ - return wxDebugAlloc(size, (wxChar*) fileName, lineNum, true, true); -} -#endif - -#ifdef _WX_WANT_ARRAY_DELETE_VOID -void wxObject::operator delete[] ( void *buf ) -{ - wxDebugFree(buf, true); -} -#endif - -#ifdef _WX_WANT_ARRAY_DELETE_VOID_WXCHAR_INT -void wxObject::operator delete[] (void * buf, const wxChar* WXUNUSED(fileName), int WXUNUSED(lineNum) ) -{ - wxDebugFree(buf, true); -} -#endif - - -// ---------------------------------------------------------------------------- -// wxClassInfo -// ---------------------------------------------------------------------------- - -wxClassInfo::~wxClassInfo() -{ - // remove this object from the linked list of all class infos: if we don't - // do it, loading/unloading a DLL containing static wxClassInfo objects is - // not going to work - if ( this == sm_first ) - { - sm_first = m_next; - } - else - { - wxClassInfo *info = sm_first; - while (info) - { - if ( info->m_next == this ) - { - info->m_next = m_next; - break; - } - - info = info->m_next; - } - } - Unregister(); -} - -wxClassInfo *wxClassInfo::FindClass(const wxChar *className) -{ - if ( sm_classTable ) - { - return (wxClassInfo *)wxClassInfo::sm_classTable->Get(className); - } - else - { - for ( wxClassInfo *info = sm_first; info ; info = info->m_next ) - { - if ( wxStrcmp(info->GetClassName(), className) == 0 ) - return info; - } - - return NULL; - } -} - -// Reentrance can occur on some platforms (Solaris for one), as the use of hash -// and string objects can cause other modules to load and register classes -// before the original call returns. This is handled by keeping the hash table -// local when it is first created and only assigning it to the global variable -// when the function is ready to return. -// -// That does make the assumption that after the function has completed the -// first time the problem will no longer happen; all the modules it depends on -// will have been loaded. The assumption is checked using the 'entry' variable -// as a reentrance guard, it checks that once the hash table is global it is -// not accessed multiple times simulateously. - -void wxClassInfo::Register() -{ -#ifdef __WXDEBUG__ - // reentrance guard - see note above - static int entry = 0; -#endif - - wxHashTable *classTable; - - if ( !sm_classTable ) - { - // keep the hash local initially, reentrance is possible - classTable = new wxHashTable(wxKEY_STRING); - } - else - { - // guard againt reentrance once the global has been created - wxASSERT_MSG(++entry == 1, _T("wxClassInfo::Register() reentrance")); - classTable = sm_classTable; - } - - // Using IMPLEMENT_DYNAMIC_CLASS() macro twice (which may happen if you - // link any object module twice mistakenly, or link twice against wx shared - // library) will break this function because it will enter an infinite loop - // and eventually die with "out of memory" - as this is quite hard to - // detect if you're unaware of this, try to do some checks here. - wxASSERT_MSG( classTable->Get(m_className) == NULL, - wxString::Format - ( - _T("Class \"%s\" already in RTTI table - have you used IMPLEMENT_DYNAMIC_CLASS() multiple times or linked some object file twice)?"), - m_className - ) - ); - - classTable->Put(m_className, (wxObject *)this); - - // if we're using a local hash we need to try to make it global - if ( sm_classTable != classTable ) - { - if ( !sm_classTable ) - { - // make the hash global - sm_classTable = classTable; - } - else - { - // the gobal hash has already been created by a reentrant call, - // so delete the local hash and try again - delete classTable; - Register(); - } - } - -#ifdef __WXDEBUG__ - entry = 0; -#endif -} - -void wxClassInfo::Unregister() -{ - if ( sm_classTable ) - { - sm_classTable->Delete(m_className); - if ( sm_classTable->GetCount() == 0 ) - { - delete sm_classTable; - sm_classTable = NULL; - } - } -} - -wxObject *wxCreateDynamicObject(const wxChar *name) -{ -#if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT - DEBUG_PRINTF(wxObject *wxCreateDynamicObject) -#endif - - if ( wxClassInfo::sm_classTable ) - { - wxClassInfo *info = (wxClassInfo *)wxClassInfo::sm_classTable->Get(name); - return info ? info->CreateObject() : NULL; - } - else // no sm_classTable yet - { - for ( wxClassInfo *info = wxClassInfo::sm_first; - info; - info = info->m_next ) - { - if (info->m_className && wxStrcmp(info->m_className, name) == 0) - return info->CreateObject(); - } - - return NULL; - } -} - - -// ---------------------------------------------------------------------------- -// wxObject -// ---------------------------------------------------------------------------- - -void wxObject::Ref(const wxObject& clone) -{ -#if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT - DEBUG_PRINTF(wxObject::Ref) -#endif - - // nothing to be done - if (m_refData == clone.m_refData) - return; - - // delete reference to old data - UnRef(); - - // reference new data - if ( clone.m_refData ) - { - m_refData = clone.m_refData; - ++(m_refData->m_count); - } -} - -void wxObject::UnRef() -{ - if ( m_refData ) - { - wxASSERT_MSG( m_refData->m_count > 0, _T("invalid ref data count") ); - - if ( --m_refData->m_count == 0 ) - delete m_refData; - m_refData = NULL; - } -} - -void wxObject::AllocExclusive() -{ - if ( !m_refData ) - { - m_refData = CreateRefData(); - } - else if ( m_refData->GetRefCount() > 1 ) - { - // note that ref is not going to be destroyed in this case - const wxObjectRefData* ref = m_refData; - UnRef(); - - // ... so we can still access it - m_refData = CloneRefData(ref); - } - //else: ref count is 1, we are exclusive owners of m_refData anyhow - - wxASSERT_MSG( m_refData && m_refData->GetRefCount() == 1, - _T("wxObject::AllocExclusive() failed.") ); -} - -wxObjectRefData *wxObject::CreateRefData() const -{ - // if you use AllocExclusive() you must override this method - wxFAIL_MSG( _T("CreateRefData() must be overridden if called!") ); - - return NULL; -} - -wxObjectRefData * -wxObject::CloneRefData(const wxObjectRefData * WXUNUSED(data)) const -{ - // if you use AllocExclusive() you must override this method - wxFAIL_MSG( _T("CloneRefData() must be overridden if called!") ); - - return NULL; -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/object.cpp +// Purpose: wxObject implementation +// Author: Julian Smart +// Modified by: Ron Lee +// Created: 04/01/98 +// RCS-ID: $Id: object.cpp 56500 2008-10-23 14:48:31Z MW $ +// Copyright: (c) 1998 Julian Smart +// (c) 2001 Ron Lee +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/hash.h" + #include "wx/memory.h" +#endif + +#include + +#if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT + #if defined(__VISAGECPP__) + #define DEBUG_PRINTF(NAME) { static int raz=0; \ + printf( #NAME " %i\n",raz); fflush(stdout); raz++; } + #else + #define DEBUG_PRINTF(NAME) + #endif +#endif // __WXDEBUG__ || wxUSE_DEBUG_CONTEXT + +// we must disable optimizations for VC.NET because otherwise its too eager +// linker discards wxClassInfo objects in release build thus breaking many, +// many things +#if defined __VISUALC__ && __VISUALC__ >= 1300 + #pragma optimize("", off) +#endif + +#if wxUSE_EXTENDED_RTTI +const wxClassInfo* wxObject::ms_classParents[] = { NULL } ; + wxObject* wxVariantToObjectConverterwxObject ( wxxVariant &data ) +{ return data.wxTEMPLATED_MEMBER_CALL(Get , wxObject*) ; } + wxObject* wxVariantOfPtrToObjectConverterwxObject ( wxxVariant &data ) +{ return &data.wxTEMPLATED_MEMBER_CALL(Get , wxObject) ; } + wxxVariant wxObjectToVariantConverterwxObject ( wxObject *data ) + { return wxxVariant( dynamic_cast (data) ) ; } + wxClassInfo wxObject::ms_classInfo(ms_classParents , wxEmptyString , wxT("wxObject"), + (int) sizeof(wxObject), \ + (wxObjectConstructorFn) 0 , + (wxPropertyInfo*) NULL,(wxHandlerInfo*) NULL,0 , 0 , + 0 , wxVariantOfPtrToObjectConverterwxObject , wxVariantToObjectConverterwxObject , wxObjectToVariantConverterwxObject); + template<> void wxStringReadValue(const wxString & , wxObject * & ){assert(0) ;} + template<> void wxStringWriteValue(wxString & , wxObject* const & ){assert(0) ;} + template<> void wxStringReadValue(const wxString & , wxObject & ){assert(0) ;} + template<> void wxStringWriteValue(wxString & , wxObject const & ){assert(0) ;} + wxClassTypeInfo s_typeInfo(wxT_OBJECT_PTR , &wxObject::ms_classInfo , NULL , NULL , typeid(wxObject*).name() ) ; + wxClassTypeInfo s_typeInfowxObject(wxT_OBJECT , &wxObject::ms_classInfo , NULL , NULL , typeid(wxObject).name() ) ; +#else +wxClassInfo wxObject::ms_classInfo( wxT("wxObject"), 0, 0, + (int) sizeof(wxObject), + (wxObjectConstructorFn) 0 ); +#endif + +// restore optimizations +#if defined __VISUALC__ && __VISUALC__ >= 1300 + #pragma optimize("", on) +#endif + +wxClassInfo* wxClassInfo::sm_first = NULL; +wxHashTable* wxClassInfo::sm_classTable = NULL; + +// when using XTI, this method is already implemented inline inside +// DECLARE_DYNAMIC_CLASS but otherwise we intentionally make this function +// non-inline because this allows us to have a non-inline virtual function in +// all wx classes and this solves linking problems for HP-UX native toolchain +// and possibly others (we could make dtor non-inline as well but it's more +// useful to keep it inline than this function) +#if !wxUSE_EXTENDED_RTTI + +wxClassInfo *wxObject::GetClassInfo() const +{ + return &wxObject::ms_classInfo; +} + +#endif // wxUSE_EXTENDED_RTTI + +// this variable exists only so that we can avoid 'always true/false' warnings +const bool wxFalse = false; + +// Is this object a kind of (a subclass of) 'info'? +// E.g. is wxWindow a kind of wxObject? +// Go from this class to superclass, taking into account +// two possible base classes. +bool wxObject::IsKindOf(wxClassInfo *info) const +{ + wxClassInfo *thisInfo = GetClassInfo(); + return (thisInfo) ? thisInfo->IsKindOf(info) : false ; +} + +#if defined(__WXDEBUG__) && wxUSE_MEMORY_TRACING && defined( new ) + #undef new +#endif + + +#ifdef _WX_WANT_NEW_SIZET_WXCHAR_INT +void *wxObject::operator new ( size_t size, const wxChar *fileName, int lineNum ) +{ + return wxDebugAlloc(size, (wxChar*) fileName, lineNum, true); +} +#endif + +#ifdef _WX_WANT_DELETE_VOID +void wxObject::operator delete ( void *buf ) +{ + wxDebugFree(buf); +} +#endif + +#ifdef _WX_WANT_DELETE_VOID_CONSTCHAR_SIZET +void wxObject::operator delete ( void *buf, const char *_fname, size_t _line ) +{ + wxDebugFree(buf); +} +#endif + +#ifdef _WX_WANT_DELETE_VOID_WXCHAR_INT +void wxObject::operator delete ( void *buf, const wxChar *WXUNUSED(fileName), int WXUNUSED(lineNum) ) +{ + wxDebugFree(buf); +} +#endif + +#ifdef _WX_WANT_ARRAY_NEW_SIZET_WXCHAR_INT +void *wxObject::operator new[] ( size_t size, const wxChar* fileName, int lineNum ) +{ + return wxDebugAlloc(size, (wxChar*) fileName, lineNum, true, true); +} +#endif + +#ifdef _WX_WANT_ARRAY_DELETE_VOID +void wxObject::operator delete[] ( void *buf ) +{ + wxDebugFree(buf, true); +} +#endif + +#ifdef _WX_WANT_ARRAY_DELETE_VOID_WXCHAR_INT +void wxObject::operator delete[] (void * buf, const wxChar* WXUNUSED(fileName), int WXUNUSED(lineNum) ) +{ + wxDebugFree(buf, true); +} +#endif + + +// ---------------------------------------------------------------------------- +// wxClassInfo +// ---------------------------------------------------------------------------- + +wxClassInfo::~wxClassInfo() +{ + // remove this object from the linked list of all class infos: if we don't + // do it, loading/unloading a DLL containing static wxClassInfo objects is + // not going to work + if ( this == sm_first ) + { + sm_first = m_next; + } + else + { + wxClassInfo *info = sm_first; + while (info) + { + if ( info->m_next == this ) + { + info->m_next = m_next; + break; + } + + info = info->m_next; + } + } + Unregister(); +} + +wxClassInfo *wxClassInfo::FindClass(const wxChar *className) +{ + if ( sm_classTable ) + { + return (wxClassInfo *)wxClassInfo::sm_classTable->Get(className); + } + else + { + for ( wxClassInfo *info = sm_first; info ; info = info->m_next ) + { + if ( wxStrcmp(info->GetClassName(), className) == 0 ) + return info; + } + + return NULL; + } +} + +// Reentrance can occur on some platforms (Solaris for one), as the use of hash +// and string objects can cause other modules to load and register classes +// before the original call returns. This is handled by keeping the hash table +// local when it is first created and only assigning it to the global variable +// when the function is ready to return. +// +// That does make the assumption that after the function has completed the +// first time the problem will no longer happen; all the modules it depends on +// will have been loaded. The assumption is checked using the 'entry' variable +// as a reentrance guard, it checks that once the hash table is global it is +// not accessed multiple times simulateously. + +void wxClassInfo::Register() +{ +#ifdef __WXDEBUG__ + // reentrance guard - see note above + static int entry = 0; +#endif + + wxHashTable *classTable; + + if ( !sm_classTable ) + { + // keep the hash local initially, reentrance is possible + classTable = new wxHashTable(wxKEY_STRING); + } + else + { + // guard againt reentrance once the global has been created + wxASSERT_MSG(++entry == 1, _T("wxClassInfo::Register() reentrance")); + classTable = sm_classTable; + } + + // Using IMPLEMENT_DYNAMIC_CLASS() macro twice (which may happen if you + // link any object module twice mistakenly, or link twice against wx shared + // library) will break this function because it will enter an infinite loop + // and eventually die with "out of memory" - as this is quite hard to + // detect if you're unaware of this, try to do some checks here. + wxASSERT_MSG( classTable->Get(m_className) == NULL, + wxString::Format + ( + _T("Class \"%s\" already in RTTI table - have you used IMPLEMENT_DYNAMIC_CLASS() multiple times or linked some object file twice)?"), + m_className + ) + ); + + classTable->Put(m_className, (wxObject *)this); + + // if we're using a local hash we need to try to make it global + if ( sm_classTable != classTable ) + { + if ( !sm_classTable ) + { + // make the hash global + sm_classTable = classTable; + } + else + { + // the gobal hash has already been created by a reentrant call, + // so delete the local hash and try again + delete classTable; + Register(); + } + } + +#ifdef __WXDEBUG__ + entry = 0; +#endif +} + +void wxClassInfo::Unregister() +{ + if ( sm_classTable ) + { + sm_classTable->Delete(m_className); + if ( sm_classTable->GetCount() == 0 ) + { + delete sm_classTable; + sm_classTable = NULL; + } + } +} + +wxObject *wxCreateDynamicObject(const wxChar *name) +{ +#if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT + DEBUG_PRINTF(wxObject *wxCreateDynamicObject) +#endif + + if ( wxClassInfo::sm_classTable ) + { + wxClassInfo *info = (wxClassInfo *)wxClassInfo::sm_classTable->Get(name); + return info ? info->CreateObject() : NULL; + } + else // no sm_classTable yet + { + for ( wxClassInfo *info = wxClassInfo::sm_first; + info; + info = info->m_next ) + { + if (info->m_className && wxStrcmp(info->m_className, name) == 0) + return info->CreateObject(); + } + + return NULL; + } +} + + +// ---------------------------------------------------------------------------- +// wxObject +// ---------------------------------------------------------------------------- + +void wxObject::Ref(const wxObject& clone) +{ +#if defined(__WXDEBUG__) || wxUSE_DEBUG_CONTEXT + DEBUG_PRINTF(wxObject::Ref) +#endif + + // nothing to be done + if (m_refData == clone.m_refData) + return; + + // delete reference to old data + UnRef(); + + // reference new data + if ( clone.m_refData ) + { + m_refData = clone.m_refData; + ++(m_refData->m_count); + } +} + +void wxObject::UnRef() +{ + if ( m_refData ) + { + wxASSERT_MSG( m_refData->m_count > 0, _T("invalid ref data count") ); + + if ( --m_refData->m_count == 0 ) + delete m_refData; + m_refData = NULL; + } +} + +void wxObject::AllocExclusive() +{ + if ( !m_refData ) + { + m_refData = CreateRefData(); + } + else if ( m_refData->GetRefCount() > 1 ) + { + // note that ref is not going to be destroyed in this case + const wxObjectRefData* ref = m_refData; + UnRef(); + + // ... so we can still access it + m_refData = CloneRefData(ref); + } + //else: ref count is 1, we are exclusive owners of m_refData anyhow + + wxASSERT_MSG( m_refData && m_refData->GetRefCount() == 1, + _T("wxObject::AllocExclusive() failed.") ); +} + +wxObjectRefData *wxObject::CreateRefData() const +{ + // if you use AllocExclusive() you must override this method + wxFAIL_MSG( _T("CreateRefData() must be overridden if called!") ); + + return NULL; +} + +wxObjectRefData * +wxObject::CloneRefData(const wxObjectRefData * WXUNUSED(data)) const +{ + // if you use AllocExclusive() you must override this method + wxFAIL_MSG( _T("CloneRefData() must be overridden if called!") ); + + return NULL; +} diff --git a/Source/3rd Party/wx/src/common/overlaycmn.cpp b/Source/3rd Party/wx/src/common/overlaycmn.cpp index d74528985..7867edb0e 100644 --- a/Source/3rd Party/wx/src/common/overlaycmn.cpp +++ b/Source/3rd Party/wx/src/common/overlaycmn.cpp @@ -1,197 +1,197 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/overlaycmn.cpp -// Purpose: common wxOverlay code -// Author: Stefan Csomor -// Modified by: -// Created: 2006-10-20 -// RCS-ID: $Id: overlaycmn.cpp 42397 2006-10-25 12:12:56Z VS $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/overlay.h" -#include "wx/private/overlay.h" -#include "wx/dcclient.h" -#include "wx/dcmemory.h" - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxOverlay -// ---------------------------------------------------------------------------- - -wxOverlay::wxOverlay() -{ - m_impl = new wxOverlayImpl(); - m_inDrawing = false; -} - -wxOverlay::~wxOverlay() -{ - delete m_impl; -} - -bool wxOverlay::IsOk() -{ - return m_impl->IsOk(); -} - -void wxOverlay::Init( wxWindowDC* dc, int x , int y , int width , int height ) -{ - m_impl->Init(dc, x, y, width, height); -} - -void wxOverlay::BeginDrawing( wxWindowDC* dc) -{ - m_impl->BeginDrawing(dc); - m_inDrawing = true ; -} - -void wxOverlay::EndDrawing( wxWindowDC* dc) -{ - m_impl->EndDrawing(dc); - m_inDrawing = false ; -} - -void wxOverlay::Clear( wxWindowDC* dc) -{ - m_impl->Clear(dc); -} - -void wxOverlay::Reset() -{ - wxASSERT_MSG(m_inDrawing==false,wxT("cannot reset overlay during drawing")); - m_impl->Reset(); -} - - -// ---------------------------------------------------------------------------- -// wxDCOverlay -// ---------------------------------------------------------------------------- - -wxDCOverlay::wxDCOverlay(wxOverlay &overlay, wxWindowDC *dc, int x , int y , int width , int height) : - m_overlay(overlay) -{ - Init(dc, x, y, width, height); -} - -wxDCOverlay::wxDCOverlay(wxOverlay &overlay, wxWindowDC *dc) : - m_overlay(overlay) -{ - int width; - int height; - dc->GetSize(&width,&height); - Init(dc, 0, 0, width, height); -} - -wxDCOverlay::~wxDCOverlay() -{ - m_overlay.EndDrawing(m_dc); -} - -void wxDCOverlay::Init(wxWindowDC *dc, int x , int y , int width , int height ) -{ - m_dc = dc ; - if ( !m_overlay.IsOk() ) - { - m_overlay.Init(dc,x,y,width,height); - } - m_overlay.BeginDrawing(dc); -} - -void wxDCOverlay::Clear() -{ - m_overlay.Clear(m_dc); -} - -// ---------------------------------------------------------------------------- -// generic implementation of wxOverlayImpl -// ---------------------------------------------------------------------------- - -#ifndef wxHAS_NATIVE_OVERLAY - -wxOverlayImpl::wxOverlayImpl() -{ -#if defined(__WXGTK__) || defined(__WXMSW__) - m_window = NULL ; -#endif - m_x = m_y = m_width = m_height = 0 ; -} - -wxOverlayImpl::~wxOverlayImpl() -{ -} - -bool wxOverlayImpl::IsOk() -{ - return m_bmpSaved.Ok() ; -} - -void wxOverlayImpl::Init( wxWindowDC* dc, int x , int y , int width , int height ) -{ -#if defined(__WXGTK__) - m_window = dc->m_owner; -#else - #if defined (__WXMSW__) - m_window = dc->GetWindow(); - #endif // __WXMSW__ - -#endif - wxMemoryDC dcMem ; - m_bmpSaved.Create( width, height ); - dcMem.SelectObject( m_bmpSaved ); - m_x = x ; - m_y = y ; - m_width = width ; - m_height = height ; -#if defined(__WXGTK__) && !defined(__WX_DC_BLIT_FIXED__) - wxPoint pt = dc->GetDeviceOrigin(); - x += pt.x; - y += pt.y; -#endif // broken wxGTK wxDC::Blit - dcMem.Blit(0, 0, m_width, m_height, - dc, x, y); - dcMem.SelectObject( wxNullBitmap ); -} - -void wxOverlayImpl::Clear(wxWindowDC* dc) -{ - wxMemoryDC dcMem ; - dcMem.SelectObject( m_bmpSaved ); - dc->Blit( m_x, m_y, m_width, m_height , &dcMem , 0 , 0 ); - dcMem.SelectObject( wxNullBitmap ); -} - -void wxOverlayImpl::Reset() -{ - m_bmpSaved = wxBitmap(); -} - -void wxOverlayImpl::BeginDrawing(wxWindowDC* WXUNUSED(dc)) -{ -} - -void wxOverlayImpl::EndDrawing(wxWindowDC* WXUNUSED(dc)) -{ -} - -#endif // !wxHAS_NATIVE_OVERLAY - - +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/overlaycmn.cpp +// Purpose: common wxOverlay code +// Author: Stefan Csomor +// Modified by: +// Created: 2006-10-20 +// RCS-ID: $Id: overlaycmn.cpp 42397 2006-10-25 12:12:56Z VS $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/overlay.h" +#include "wx/private/overlay.h" +#include "wx/dcclient.h" +#include "wx/dcmemory.h" + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxOverlay +// ---------------------------------------------------------------------------- + +wxOverlay::wxOverlay() +{ + m_impl = new wxOverlayImpl(); + m_inDrawing = false; +} + +wxOverlay::~wxOverlay() +{ + delete m_impl; +} + +bool wxOverlay::IsOk() +{ + return m_impl->IsOk(); +} + +void wxOverlay::Init( wxWindowDC* dc, int x , int y , int width , int height ) +{ + m_impl->Init(dc, x, y, width, height); +} + +void wxOverlay::BeginDrawing( wxWindowDC* dc) +{ + m_impl->BeginDrawing(dc); + m_inDrawing = true ; +} + +void wxOverlay::EndDrawing( wxWindowDC* dc) +{ + m_impl->EndDrawing(dc); + m_inDrawing = false ; +} + +void wxOverlay::Clear( wxWindowDC* dc) +{ + m_impl->Clear(dc); +} + +void wxOverlay::Reset() +{ + wxASSERT_MSG(m_inDrawing==false,wxT("cannot reset overlay during drawing")); + m_impl->Reset(); +} + + +// ---------------------------------------------------------------------------- +// wxDCOverlay +// ---------------------------------------------------------------------------- + +wxDCOverlay::wxDCOverlay(wxOverlay &overlay, wxWindowDC *dc, int x , int y , int width , int height) : + m_overlay(overlay) +{ + Init(dc, x, y, width, height); +} + +wxDCOverlay::wxDCOverlay(wxOverlay &overlay, wxWindowDC *dc) : + m_overlay(overlay) +{ + int width; + int height; + dc->GetSize(&width,&height); + Init(dc, 0, 0, width, height); +} + +wxDCOverlay::~wxDCOverlay() +{ + m_overlay.EndDrawing(m_dc); +} + +void wxDCOverlay::Init(wxWindowDC *dc, int x , int y , int width , int height ) +{ + m_dc = dc ; + if ( !m_overlay.IsOk() ) + { + m_overlay.Init(dc,x,y,width,height); + } + m_overlay.BeginDrawing(dc); +} + +void wxDCOverlay::Clear() +{ + m_overlay.Clear(m_dc); +} + +// ---------------------------------------------------------------------------- +// generic implementation of wxOverlayImpl +// ---------------------------------------------------------------------------- + +#ifndef wxHAS_NATIVE_OVERLAY + +wxOverlayImpl::wxOverlayImpl() +{ +#if defined(__WXGTK__) || defined(__WXMSW__) + m_window = NULL ; +#endif + m_x = m_y = m_width = m_height = 0 ; +} + +wxOverlayImpl::~wxOverlayImpl() +{ +} + +bool wxOverlayImpl::IsOk() +{ + return m_bmpSaved.Ok() ; +} + +void wxOverlayImpl::Init( wxWindowDC* dc, int x , int y , int width , int height ) +{ +#if defined(__WXGTK__) + m_window = dc->m_owner; +#else + #if defined (__WXMSW__) + m_window = dc->GetWindow(); + #endif // __WXMSW__ + +#endif + wxMemoryDC dcMem ; + m_bmpSaved.Create( width, height ); + dcMem.SelectObject( m_bmpSaved ); + m_x = x ; + m_y = y ; + m_width = width ; + m_height = height ; +#if defined(__WXGTK__) && !defined(__WX_DC_BLIT_FIXED__) + wxPoint pt = dc->GetDeviceOrigin(); + x += pt.x; + y += pt.y; +#endif // broken wxGTK wxDC::Blit + dcMem.Blit(0, 0, m_width, m_height, + dc, x, y); + dcMem.SelectObject( wxNullBitmap ); +} + +void wxOverlayImpl::Clear(wxWindowDC* dc) +{ + wxMemoryDC dcMem ; + dcMem.SelectObject( m_bmpSaved ); + dc->Blit( m_x, m_y, m_width, m_height , &dcMem , 0 , 0 ); + dcMem.SelectObject( wxNullBitmap ); +} + +void wxOverlayImpl::Reset() +{ + m_bmpSaved = wxBitmap(); +} + +void wxOverlayImpl::BeginDrawing(wxWindowDC* WXUNUSED(dc)) +{ +} + +void wxOverlayImpl::EndDrawing(wxWindowDC* WXUNUSED(dc)) +{ +} + +#endif // !wxHAS_NATIVE_OVERLAY + + diff --git a/Source/3rd Party/wx/src/common/paper.cpp b/Source/3rd Party/wx/src/common/paper.cpp index a787652b3..714eee286 100644 --- a/Source/3rd Party/wx/src/common/paper.cpp +++ b/Source/3rd Party/wx/src/common/paper.cpp @@ -1,376 +1,376 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/paper.cpp -// Purpose: Paper size classes -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: paper.cpp 60706 2009-05-21 10:17:44Z JS $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_PRINTING_ARCHITECTURE - -#ifndef WX_PRECOMP - #if defined(__WXMSW__) - #include "wx/msw/wrapcdlg.h" - #endif // MSW - #include "wx/utils.h" - #include "wx/settings.h" - #include "wx/intl.h" - #include "wx/module.h" -#endif - -#include "wx/paper.h" - -#include -#include - -#ifdef __WXMSW__ - #ifndef __WIN32__ - #include - #endif -#endif - // End __WXMSW__ - -IMPLEMENT_DYNAMIC_CLASS(wxPrintPaperType, wxObject) -// IMPLEMENT_DYNAMIC_CLASS(wxPrintPaperDatabase, wxList) - -/* - * Paper size database for all platforms - */ - -wxPrintPaperType::wxPrintPaperType() -{ - m_paperId = wxPAPER_NONE; - m_platformId = 0; - m_paperName = wxEmptyString; - m_width = 0; - m_height = 0; -} - -wxPrintPaperType::wxPrintPaperType(wxPaperSize paperId, int platformId, const wxString& name, int w, int h) -{ - m_paperId = paperId; - m_platformId = platformId; - m_paperName = name; - m_width = w; - m_height = h; -} - -// Get width and height in points (1/72th of an inch) -wxSize wxPrintPaperType::GetSizeDeviceUnits() const -{ - return wxSize( (int) ((m_width / 10.0) / (25.4 / 72.0)), (int) ((m_height / 10.0) / (25.4 / 72.0)) ); -} - -/* - * Print paper database for PostScript - */ - -WX_DECLARE_LIST(wxPrintPaperType, wxPrintPaperTypeList); -#include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxPrintPaperTypeList) - -wxPrintPaperDatabase* wxThePrintPaperDatabase = (wxPrintPaperDatabase*) NULL; - -wxPrintPaperDatabase::wxPrintPaperDatabase() -{ - m_map = new wxStringToPrintPaperTypeHashMap; - m_list = new wxPrintPaperTypeList; -} - -wxPrintPaperDatabase::~wxPrintPaperDatabase() -{ - ClearDatabase(); -} - -void wxPrintPaperDatabase::CreateDatabase() -{ - WXADDPAPER(wxPAPER_LETTER, DMPAPER_LETTER, wxTRANSLATE("Letter, 8 1/2 x 11 in"), 2159, 2794); - WXADDPAPER(wxPAPER_LEGAL, DMPAPER_LEGAL, wxTRANSLATE("Legal, 8 1/2 x 14 in"), 2159, 3556); - WXADDPAPER(wxPAPER_A4, DMPAPER_A4, wxTRANSLATE("A4 sheet, 210 x 297 mm"), 2100, 2970); - WXADDPAPER(wxPAPER_CSHEET, DMPAPER_CSHEET, wxTRANSLATE("C sheet, 17 x 22 in"), 4318, 5588); - WXADDPAPER(wxPAPER_DSHEET, DMPAPER_DSHEET, wxTRANSLATE("D sheet, 22 x 34 in"), 5588, 8636); - WXADDPAPER(wxPAPER_ESHEET, DMPAPER_ESHEET, wxTRANSLATE("E sheet, 34 x 44 in"), 8636, 11176); - WXADDPAPER(wxPAPER_LETTERSMALL, DMPAPER_LETTERSMALL, wxTRANSLATE("Letter Small, 8 1/2 x 11 in"), 2159, 2794); - WXADDPAPER(wxPAPER_TABLOID, DMPAPER_TABLOID, wxTRANSLATE("Tabloid, 11 x 17 in"), 2794, 4318); - WXADDPAPER(wxPAPER_LEDGER, DMPAPER_LEDGER, wxTRANSLATE("Ledger, 17 x 11 in"), 4318, 2794); - WXADDPAPER(wxPAPER_STATEMENT, DMPAPER_STATEMENT, wxTRANSLATE("Statement, 5 1/2 x 8 1/2 in"), 1397, 2159); - WXADDPAPER(wxPAPER_EXECUTIVE, DMPAPER_EXECUTIVE, wxTRANSLATE("Executive, 7 1/4 x 10 1/2 in"), 1842, 2667); - WXADDPAPER(wxPAPER_A3, DMPAPER_A3, wxTRANSLATE("A3 sheet, 297 x 420 mm"), 2970, 4200); - WXADDPAPER(wxPAPER_A4SMALL, DMPAPER_A4SMALL, wxTRANSLATE("A4 small sheet, 210 x 297 mm"), 2100, 2970); - WXADDPAPER(wxPAPER_A5, DMPAPER_A5, wxTRANSLATE("A5 sheet, 148 x 210 mm"), 1480, 2100); - WXADDPAPER(wxPAPER_B4, DMPAPER_B4, wxTRANSLATE("B4 sheet, 250 x 354 mm"), 2500, 3540); - WXADDPAPER(wxPAPER_B5, DMPAPER_B5, wxTRANSLATE("B5 sheet, 182 x 257 millimeter"), 1820, 2570); - WXADDPAPER(wxPAPER_FOLIO, DMPAPER_FOLIO, wxTRANSLATE("Folio, 8 1/2 x 13 in"), 2159, 3302); - WXADDPAPER(wxPAPER_QUARTO, DMPAPER_QUARTO, wxTRANSLATE("Quarto, 215 x 275 mm"), 2150, 2750); - WXADDPAPER(wxPAPER_10X14, DMPAPER_10X14, wxTRANSLATE("10 x 14 in"), 2540, 3556); - WXADDPAPER(wxPAPER_11X17, DMPAPER_11X17, wxTRANSLATE("11 x 17 in"), 2794, 4318); - WXADDPAPER(wxPAPER_NOTE, DMPAPER_NOTE, wxTRANSLATE("Note, 8 1/2 x 11 in"), 2159, 2794); - WXADDPAPER(wxPAPER_ENV_9, DMPAPER_ENV_9, wxTRANSLATE("#9 Envelope, 3 7/8 x 8 7/8 in"), 984, 2254); - WXADDPAPER(wxPAPER_ENV_10, DMPAPER_ENV_10, wxTRANSLATE("#10 Envelope, 4 1/8 x 9 1/2 in"), 1048, 2413); - WXADDPAPER(wxPAPER_ENV_11, DMPAPER_ENV_11, wxTRANSLATE("#11 Envelope, 4 1/2 x 10 3/8 in"), 1143, 2635); - WXADDPAPER(wxPAPER_ENV_12, DMPAPER_ENV_12, wxTRANSLATE("#12 Envelope, 4 3/4 x 11 in"), 1206, 2794); - WXADDPAPER(wxPAPER_ENV_14, DMPAPER_ENV_14, wxTRANSLATE("#14 Envelope, 5 x 11 1/2 in"), 1270, 2921); - WXADDPAPER(wxPAPER_ENV_DL, DMPAPER_ENV_DL, wxTRANSLATE("DL Envelope, 110 x 220 mm"), 1100, 2200); - WXADDPAPER(wxPAPER_ENV_C5, DMPAPER_ENV_C5, wxTRANSLATE("C5 Envelope, 162 x 229 mm"), 1620, 2290); - WXADDPAPER(wxPAPER_ENV_C3, DMPAPER_ENV_C3, wxTRANSLATE("C3 Envelope, 324 x 458 mm"), 3240, 4580); - WXADDPAPER(wxPAPER_ENV_C4, DMPAPER_ENV_C4, wxTRANSLATE("C4 Envelope, 229 x 324 mm"), 2290, 3240); - WXADDPAPER(wxPAPER_ENV_C6, DMPAPER_ENV_C6, wxTRANSLATE("C6 Envelope, 114 x 162 mm"), 1140, 1620); - WXADDPAPER(wxPAPER_ENV_C65, DMPAPER_ENV_C65, wxTRANSLATE("C65 Envelope, 114 x 229 mm"), 1140, 2290); - WXADDPAPER(wxPAPER_ENV_B4, DMPAPER_ENV_B4, wxTRANSLATE("B4 Envelope, 250 x 353 mm"), 2500, 3530); - WXADDPAPER(wxPAPER_ENV_B5, DMPAPER_ENV_B5, wxTRANSLATE("B5 Envelope, 176 x 250 mm"), 1760, 2500); - WXADDPAPER(wxPAPER_ENV_B6, DMPAPER_ENV_B6, wxTRANSLATE("B6 Envelope, 176 x 125 mm"), 1760, 1250); - WXADDPAPER(wxPAPER_ENV_ITALY, DMPAPER_ENV_ITALY, wxTRANSLATE("Italy Envelope, 110 x 230 mm"), 1100, 2300); - WXADDPAPER(wxPAPER_ENV_MONARCH, DMPAPER_ENV_MONARCH, wxTRANSLATE("Monarch Envelope, 3 7/8 x 7 1/2 in"), 984, 1905); - WXADDPAPER(wxPAPER_ENV_PERSONAL, DMPAPER_ENV_PERSONAL, wxTRANSLATE("6 3/4 Envelope, 3 5/8 x 6 1/2 in"), 921, 1651); - WXADDPAPER(wxPAPER_FANFOLD_US, DMPAPER_FANFOLD_US, wxTRANSLATE("US Std Fanfold, 14 7/8 x 11 in"), 3778, 2794); - WXADDPAPER(wxPAPER_FANFOLD_STD_GERMAN, DMPAPER_FANFOLD_STD_GERMAN, wxTRANSLATE("German Std Fanfold, 8 1/2 x 12 in"), 2159, 3048); - WXADDPAPER(wxPAPER_FANFOLD_LGL_GERMAN, DMPAPER_FANFOLD_LGL_GERMAN, wxTRANSLATE("German Legal Fanfold, 8 1/2 x 13 in"), 2159, 3302); - - WXADDPAPER(wxPAPER_ISO_B4, DMPAPER_ISO_B4, wxTRANSLATE("B4 (ISO) 250 x 353 mm"), 2500, 2530); - WXADDPAPER(wxPAPER_JAPANESE_POSTCARD, DMPAPER_JAPANESE_POSTCARD, wxTRANSLATE("Japanese Postcard 100 x 148 mm"), 1000, 1480); - WXADDPAPER(wxPAPER_9X11, DMPAPER_9X11, wxTRANSLATE("9 x 11 in"), 2286, 2794); - WXADDPAPER(wxPAPER_10X11, DMPAPER_10X11, wxTRANSLATE("10 x 11 in"), 2540, 2794); - WXADDPAPER(wxPAPER_15X11, DMPAPER_15X11, wxTRANSLATE("15 x 11 in"), 3810, 2794); - WXADDPAPER(wxPAPER_ENV_INVITE, DMPAPER_ENV_INVITE, wxTRANSLATE("Envelope Invite 220 x 220 mm"), 2200, 2200); - WXADDPAPER(wxPAPER_LETTER_EXTRA, DMPAPER_LETTER_EXTRA, wxTRANSLATE("Letter Extra 9 1/2 x 12 in"), 2413, 3048); - WXADDPAPER(wxPAPER_LEGAL_EXTRA, DMPAPER_LEGAL_EXTRA, wxTRANSLATE("Legal Extra 9 1/2 x 15 in"), 2413, 3810); - WXADDPAPER(wxPAPER_TABLOID_EXTRA, DMPAPER_TABLOID_EXTRA, wxTRANSLATE("Tabloid Extra 11.69 x 18 in"), 2969, 4572); - WXADDPAPER(wxPAPER_A4_EXTRA, DMPAPER_A4_EXTRA, wxTRANSLATE("A4 Extra 9.27 x 12.69 in"), 2355, 3223); - WXADDPAPER(wxPAPER_LETTER_TRANSVERSE, DMPAPER_LETTER_TRANSVERSE, wxTRANSLATE("Letter Transverse 8 1/2 x 11 in"), 2159, 2794); - WXADDPAPER(wxPAPER_A4_TRANSVERSE, DMPAPER_A4_TRANSVERSE, wxTRANSLATE("A4 Transverse 210 x 297 mm"), 2100, 2970); - WXADDPAPER(wxPAPER_LETTER_EXTRA_TRANSVERSE, DMPAPER_LETTER_EXTRA_TRANSVERSE, wxTRANSLATE("Letter Extra Transverse 9.275 x 12 in"), 2355, 3048); - WXADDPAPER(wxPAPER_A_PLUS, DMPAPER_A_PLUS, wxTRANSLATE("SuperA/SuperA/A4 227 x 356 mm"), 2270, 3560); - WXADDPAPER(wxPAPER_B_PLUS, DMPAPER_B_PLUS, wxTRANSLATE("SuperB/SuperB/A3 305 x 487 mm"), 3050, 4870); - WXADDPAPER(wxPAPER_LETTER_PLUS, DMPAPER_LETTER_PLUS, wxTRANSLATE("Letter Plus 8 1/2 x 12.69 in"), 2159, 3223); - WXADDPAPER(wxPAPER_A4_PLUS, DMPAPER_A4_PLUS, wxTRANSLATE("A4 Plus 210 x 330 mm"), 2100, 3300); - WXADDPAPER(wxPAPER_A5_TRANSVERSE, DMPAPER_A5_TRANSVERSE, wxTRANSLATE("A5 Transverse 148 x 210 mm"), 1480, 2100); - WXADDPAPER(wxPAPER_B5_TRANSVERSE, DMPAPER_B5_TRANSVERSE, wxTRANSLATE("B5 (JIS) Transverse 182 x 257 mm"), 1820, 2570); - WXADDPAPER(wxPAPER_A3_EXTRA, DMPAPER_A3_EXTRA, wxTRANSLATE("A3 Extra 322 x 445 mm"), 3220, 4450); - WXADDPAPER(wxPAPER_A5_EXTRA, DMPAPER_A5_EXTRA, wxTRANSLATE("A5 Extra 174 x 235 mm"), 1740, 2350); - WXADDPAPER(wxPAPER_B5_EXTRA, DMPAPER_B5_EXTRA, wxTRANSLATE("B5 (ISO) Extra 201 x 276 mm"), 2010, 2760); - WXADDPAPER(wxPAPER_A2, DMPAPER_A2, wxTRANSLATE("A2 420 x 594 mm"), 4200, 5940); - WXADDPAPER(wxPAPER_A3_TRANSVERSE, DMPAPER_A3_TRANSVERSE, wxTRANSLATE("A3 Transverse 297 x 420 mm"), 2970, 4200); - WXADDPAPER(wxPAPER_A3_EXTRA_TRANSVERSE,DMPAPER_A3_EXTRA_TRANSVERSE,wxTRANSLATE("A3 Extra Transverse 322 x 445 mm"), 3220, 4450); - - WXADDPAPER(wxPAPER_DBL_JAPANESE_POSTCARD, 69, wxTRANSLATE("Japanese Double Postcard 200 x 148 mm"), 2000, 1480); - WXADDPAPER(wxPAPER_A6, 70, wxTRANSLATE("A6 105 x 148 mm"), 1050, 1480); - WXADDPAPER(wxPAPER_JENV_KAKU2, 71, wxTRANSLATE("Japanese Envelope Kaku #2"), 2400, 3320); - WXADDPAPER(wxPAPER_JENV_KAKU3, 72, wxTRANSLATE("Japanese Envelope Kaku #3"), 2160, 2770); - WXADDPAPER(wxPAPER_JENV_CHOU3, 73, wxTRANSLATE("Japanese Envelope Chou #3"), 1200, 2350); - WXADDPAPER(wxPAPER_JENV_CHOU4, 74, wxTRANSLATE("Japanese Envelope Chou #4"), 900, 2050); - WXADDPAPER(wxPAPER_LETTER_ROTATED, 75, wxTRANSLATE("Letter Rotated 11 x 8 1/2 in"), 2794, 2159); - WXADDPAPER(wxPAPER_A3_ROTATED, 76, wxTRANSLATE("A3 Rotated 420 x 297 mm"), 4200, 2970); - WXADDPAPER(wxPAPER_A4_ROTATED, 77, wxTRANSLATE("A4 Rotated 297 x 210 mm"), 2970, 2100); - WXADDPAPER(wxPAPER_A5_ROTATED, 78, wxTRANSLATE("A5 Rotated 210 x 148 mm"), 2100, 1480); - WXADDPAPER(wxPAPER_B4_JIS_ROTATED, 79, wxTRANSLATE("B4 (JIS) Rotated 364 x 257 mm"), 3640, 2570); - WXADDPAPER(wxPAPER_B5_JIS_ROTATED, 80, wxTRANSLATE("B5 (JIS) Rotated 257 x 182 mm"), 2570, 1820); - WXADDPAPER(wxPAPER_JAPANESE_POSTCARD_ROTATED, 81, wxTRANSLATE("Japanese Postcard Rotated 148 x 100 mm"), 1480, 1000); - WXADDPAPER(wxPAPER_DBL_JAPANESE_POSTCARD_ROTATED, 82, wxTRANSLATE("Double Japanese Postcard Rotated 148 x 200 mm"), 1480, 2000); - WXADDPAPER(wxPAPER_A6_ROTATED, 83, wxTRANSLATE("A6 Rotated 148 x 105 mm"), 1480, 1050); - WXADDPAPER(wxPAPER_JENV_KAKU2_ROTATED, 84, wxTRANSLATE("Japanese Envelope Kaku #2 Rotated"), 3320, 2400); - WXADDPAPER(wxPAPER_JENV_KAKU3_ROTATED, 85, wxTRANSLATE("Japanese Envelope Kaku #3 Rotated"), 2770, 2160); - WXADDPAPER(wxPAPER_JENV_CHOU3_ROTATED, 86, wxTRANSLATE("Japanese Envelope Chou #3 Rotated"), 2350, 1200); - WXADDPAPER(wxPAPER_JENV_CHOU4_ROTATED, 87, wxTRANSLATE("Japanese Envelope Chou #4 Rotated"), 2050, 900); - WXADDPAPER(wxPAPER_B6_JIS, 88, wxTRANSLATE("B6 (JIS) 128 x 182 mm"), 1280, 1820); - WXADDPAPER(wxPAPER_B6_JIS_ROTATED, 89, wxTRANSLATE("B6 (JIS) Rotated 182 x 128 mm"), 1920, 1280); - WXADDPAPER(wxPAPER_12X11, 90, wxTRANSLATE("12 x 11 in"), 3048, 2794); - WXADDPAPER(wxPAPER_JENV_YOU4, 91, wxTRANSLATE("Japanese Envelope You #4"), 2350, 1050); - WXADDPAPER(wxPAPER_JENV_YOU4_ROTATED, 92, wxTRANSLATE("Japanese Envelope You #4 Rotated"), 1050, 2350); - WXADDPAPER(wxPAPER_P16K, 93, wxTRANSLATE("PRC 16K 146 x 215 mm"), 1460, 2150); - WXADDPAPER(wxPAPER_P32K, 94, wxTRANSLATE("PRC 32K 97 x 151 mm"), 970, 1510); - WXADDPAPER(wxPAPER_P32KBIG, 95, wxTRANSLATE("PRC 32K(Big) 97 x 151 mm"), 970, 1510); - WXADDPAPER(wxPAPER_PENV_1, 96, wxTRANSLATE("PRC Envelope #1 102 x 165 mm"), 1020, 1650); - WXADDPAPER(wxPAPER_PENV_2, 97, wxTRANSLATE("PRC Envelope #2 102 x 176 mm"), 1020, 1760); - WXADDPAPER(wxPAPER_PENV_3, 98, wxTRANSLATE("PRC Envelope #3 125 x 176 mm"), 1250, 1760); - WXADDPAPER(wxPAPER_PENV_4, 99, wxTRANSLATE("PRC Envelope #4 110 x 208 mm"), 1100, 2080); - WXADDPAPER(wxPAPER_PENV_5, 100, wxTRANSLATE("PRC Envelope #5 110 x 220 mm"), 1100, 2200); - WXADDPAPER(wxPAPER_PENV_6, 101, wxTRANSLATE("PRC Envelope #6 120 x 230 mm"), 1200, 2300); - WXADDPAPER(wxPAPER_PENV_7, 102, wxTRANSLATE("PRC Envelope #7 160 x 230 mm"), 1600, 2300); - WXADDPAPER(wxPAPER_PENV_8, 103, wxTRANSLATE("PRC Envelope #8 120 x 309 mm"), 1200, 3090); - WXADDPAPER(wxPAPER_PENV_9, 104, wxTRANSLATE("PRC Envelope #9 229 x 324 mm"), 2290, 3240); - WXADDPAPER(wxPAPER_PENV_10, 105, wxTRANSLATE("PRC Envelope #10 324 x 458 mm"), 3240, 4580); - WXADDPAPER(wxPAPER_P16K_ROTATED, 106, wxTRANSLATE("PRC 16K Rotated"), 2150, 1460); - WXADDPAPER(wxPAPER_P32K_ROTATED, 107, wxTRANSLATE("PRC 32K Rotated"), 1510, 970); - WXADDPAPER(wxPAPER_P32KBIG_ROTATED, 108, wxTRANSLATE("PRC 32K(Big) Rotated"), 1510, 970); - WXADDPAPER(wxPAPER_PENV_1_ROTATED, 109, wxTRANSLATE("PRC Envelope #1 Rotated 165 x 102 mm"), 1650, 1020); - WXADDPAPER(wxPAPER_PENV_2_ROTATED, 110, wxTRANSLATE("PRC Envelope #2 Rotated 176 x 102 mm"), 1760, 1020); - WXADDPAPER(wxPAPER_PENV_3_ROTATED, 111, wxTRANSLATE("PRC Envelope #3 Rotated 176 x 125 mm"), 1760, 1250); - WXADDPAPER(wxPAPER_PENV_4_ROTATED, 112, wxTRANSLATE("PRC Envelope #4 Rotated 208 x 110 mm"), 2080, 1100); - WXADDPAPER(wxPAPER_PENV_5_ROTATED, 113, wxTRANSLATE("PRC Envelope #5 Rotated 220 x 110 mm"), 2200, 1100); - WXADDPAPER(wxPAPER_PENV_6_ROTATED, 114, wxTRANSLATE("PRC Envelope #6 Rotated 230 x 120 mm"), 2300, 1200); - WXADDPAPER(wxPAPER_PENV_7_ROTATED, 115, wxTRANSLATE("PRC Envelope #7 Rotated 230 x 160 mm"), 2300, 1600); - WXADDPAPER(wxPAPER_PENV_8_ROTATED, 116, wxTRANSLATE("PRC Envelope #8 Rotated 309 x 120 mm"), 3090, 1200); - WXADDPAPER(wxPAPER_PENV_9_ROTATED, 117, wxTRANSLATE("PRC Envelope #9 Rotated 324 x 229 mm"), 3240, 2290); - WXADDPAPER(wxPAPER_PENV_10_ROTATED, 118, wxTRANSLATE("PRC Envelope #10 Rotated 458 x 324 mm"), 4580, 3240); -} - -void wxPrintPaperDatabase::ClearDatabase() -{ - delete m_list; - WX_CLEAR_HASH_MAP(wxStringToPrintPaperTypeHashMap, *m_map); - delete m_map; -} - -void wxPrintPaperDatabase::AddPaperType(wxPaperSize paperId, const wxString& name, int w, int h) -{ - wxPrintPaperType* tmp = new wxPrintPaperType(paperId, 0, name, w, h); - (*m_map)[name] = tmp; - m_list->push_back(tmp); -} - -void wxPrintPaperDatabase::AddPaperType(wxPaperSize paperId, int platformId, const wxString& name, int w, int h) -{ - wxPrintPaperType* tmp = new wxPrintPaperType(paperId, platformId, name, w, h); - (*m_map)[name] = tmp; - m_list->push_back(tmp); -} - -wxPrintPaperType *wxPrintPaperDatabase::FindPaperType(const wxString& name) -{ - wxStringToPrintPaperTypeHashMap::iterator it = m_map->find(name); - if (it != m_map->end()) - return it->second; - else - return NULL; -} - -wxPrintPaperType *wxPrintPaperDatabase::FindPaperType(wxPaperSize id) -{ - typedef wxStringToPrintPaperTypeHashMap::iterator iterator; - - for (iterator it = m_map->begin(), en = m_map->end(); it != en; ++it) - { - wxPrintPaperType* paperType = it->second; - if (paperType->GetId() == id) - return paperType; - } - - return NULL; -} - -wxPrintPaperType *wxPrintPaperDatabase::FindPaperTypeByPlatformId(int id) -{ - typedef wxStringToPrintPaperTypeHashMap::iterator iterator; - - for (iterator it = m_map->begin(), en = m_map->end(); it != en; ++it) - { - wxPrintPaperType* paperType = it->second; - if (paperType->GetPlatformId() == id) - return paperType; - } - - return NULL; -} - -wxPrintPaperType *wxPrintPaperDatabase::FindPaperType(const wxSize& sz) -{ - // Take the item ordering into account so that the more common types - // are likely to be taken into account first. This fixes problems with, - // for example, Letter reverting to A4 in the page setup dialog because - // it was wrongly translated to Note. - size_t i; - for (i = 0; i < GetCount(); i++) - { - wxPrintPaperType* paperType = Item(i); - wxSize paperSize = paperType->GetSize() ; - if ( abs( paperSize.x - sz.x ) < 10 && abs( paperSize.y - sz.y ) < 10 ) - return paperType; - } - - return NULL; -} - -// Convert name to size id -wxPaperSize wxPrintPaperDatabase::ConvertNameToId(const wxString& name) -{ - wxPrintPaperType* type = FindPaperType(name); - if (type) - return type->GetId(); - else - return wxPAPER_NONE; -} - -// Convert size id to name -wxString wxPrintPaperDatabase::ConvertIdToName(wxPaperSize paperId) -{ - wxPrintPaperType* type = FindPaperType(paperId); - if (type) - return type->GetName(); - else - return wxEmptyString; -} - -// Get the paper size -wxSize wxPrintPaperDatabase::GetSize(wxPaperSize paperId) -{ - wxPrintPaperType* type = FindPaperType(paperId); - if (type) - return type->GetSize(); - else - return wxSize(0,0); -} - -// Get the paper size -wxPaperSize wxPrintPaperDatabase::GetSize(const wxSize& size) -{ - wxPrintPaperType* type = FindPaperType(size); - if (type) - return type->GetId(); - else - return wxPAPER_NONE; -} - -// QUICK and DIRTY -size_t wxPrintPaperDatabase::GetCount() const -{ - return m_list->GetCount(); -} - -wxPrintPaperType* wxPrintPaperDatabase::Item(size_t index) const -{ - return m_list->Item(index)->GetData(); -} - -// A module to allow initialization/cleanup of print paper -// things without calling these functions from app.cpp. - -class WXDLLEXPORT wxPrintPaperModule: public wxModule -{ -DECLARE_DYNAMIC_CLASS(wxPrintPaperModule) -public: - wxPrintPaperModule() {} - bool OnInit(); - void OnExit(); -}; - -IMPLEMENT_DYNAMIC_CLASS(wxPrintPaperModule, wxModule) - -/* - * Initialization/cleanup module - */ - -bool wxPrintPaperModule::OnInit() -{ - wxThePrintPaperDatabase = new wxPrintPaperDatabase; - wxThePrintPaperDatabase->CreateDatabase(); - - return true; -} - -void wxPrintPaperModule::OnExit() -{ - delete wxThePrintPaperDatabase; - wxThePrintPaperDatabase = NULL; -} - -#endif // wxUSE_PRINTING_ARCHITECTURE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/paper.cpp +// Purpose: Paper size classes +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: paper.cpp 60706 2009-05-21 10:17:44Z JS $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_PRINTING_ARCHITECTURE + +#ifndef WX_PRECOMP + #if defined(__WXMSW__) + #include "wx/msw/wrapcdlg.h" + #endif // MSW + #include "wx/utils.h" + #include "wx/settings.h" + #include "wx/intl.h" + #include "wx/module.h" +#endif + +#include "wx/paper.h" + +#include +#include + +#ifdef __WXMSW__ + #ifndef __WIN32__ + #include + #endif +#endif + // End __WXMSW__ + +IMPLEMENT_DYNAMIC_CLASS(wxPrintPaperType, wxObject) +// IMPLEMENT_DYNAMIC_CLASS(wxPrintPaperDatabase, wxList) + +/* + * Paper size database for all platforms + */ + +wxPrintPaperType::wxPrintPaperType() +{ + m_paperId = wxPAPER_NONE; + m_platformId = 0; + m_paperName = wxEmptyString; + m_width = 0; + m_height = 0; +} + +wxPrintPaperType::wxPrintPaperType(wxPaperSize paperId, int platformId, const wxString& name, int w, int h) +{ + m_paperId = paperId; + m_platformId = platformId; + m_paperName = name; + m_width = w; + m_height = h; +} + +// Get width and height in points (1/72th of an inch) +wxSize wxPrintPaperType::GetSizeDeviceUnits() const +{ + return wxSize( (int) ((m_width / 10.0) / (25.4 / 72.0)), (int) ((m_height / 10.0) / (25.4 / 72.0)) ); +} + +/* + * Print paper database for PostScript + */ + +WX_DECLARE_LIST(wxPrintPaperType, wxPrintPaperTypeList); +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wxPrintPaperTypeList) + +wxPrintPaperDatabase* wxThePrintPaperDatabase = (wxPrintPaperDatabase*) NULL; + +wxPrintPaperDatabase::wxPrintPaperDatabase() +{ + m_map = new wxStringToPrintPaperTypeHashMap; + m_list = new wxPrintPaperTypeList; +} + +wxPrintPaperDatabase::~wxPrintPaperDatabase() +{ + ClearDatabase(); +} + +void wxPrintPaperDatabase::CreateDatabase() +{ + WXADDPAPER(wxPAPER_LETTER, DMPAPER_LETTER, wxTRANSLATE("Letter, 8 1/2 x 11 in"), 2159, 2794); + WXADDPAPER(wxPAPER_LEGAL, DMPAPER_LEGAL, wxTRANSLATE("Legal, 8 1/2 x 14 in"), 2159, 3556); + WXADDPAPER(wxPAPER_A4, DMPAPER_A4, wxTRANSLATE("A4 sheet, 210 x 297 mm"), 2100, 2970); + WXADDPAPER(wxPAPER_CSHEET, DMPAPER_CSHEET, wxTRANSLATE("C sheet, 17 x 22 in"), 4318, 5588); + WXADDPAPER(wxPAPER_DSHEET, DMPAPER_DSHEET, wxTRANSLATE("D sheet, 22 x 34 in"), 5588, 8636); + WXADDPAPER(wxPAPER_ESHEET, DMPAPER_ESHEET, wxTRANSLATE("E sheet, 34 x 44 in"), 8636, 11176); + WXADDPAPER(wxPAPER_LETTERSMALL, DMPAPER_LETTERSMALL, wxTRANSLATE("Letter Small, 8 1/2 x 11 in"), 2159, 2794); + WXADDPAPER(wxPAPER_TABLOID, DMPAPER_TABLOID, wxTRANSLATE("Tabloid, 11 x 17 in"), 2794, 4318); + WXADDPAPER(wxPAPER_LEDGER, DMPAPER_LEDGER, wxTRANSLATE("Ledger, 17 x 11 in"), 4318, 2794); + WXADDPAPER(wxPAPER_STATEMENT, DMPAPER_STATEMENT, wxTRANSLATE("Statement, 5 1/2 x 8 1/2 in"), 1397, 2159); + WXADDPAPER(wxPAPER_EXECUTIVE, DMPAPER_EXECUTIVE, wxTRANSLATE("Executive, 7 1/4 x 10 1/2 in"), 1842, 2667); + WXADDPAPER(wxPAPER_A3, DMPAPER_A3, wxTRANSLATE("A3 sheet, 297 x 420 mm"), 2970, 4200); + WXADDPAPER(wxPAPER_A4SMALL, DMPAPER_A4SMALL, wxTRANSLATE("A4 small sheet, 210 x 297 mm"), 2100, 2970); + WXADDPAPER(wxPAPER_A5, DMPAPER_A5, wxTRANSLATE("A5 sheet, 148 x 210 mm"), 1480, 2100); + WXADDPAPER(wxPAPER_B4, DMPAPER_B4, wxTRANSLATE("B4 sheet, 250 x 354 mm"), 2500, 3540); + WXADDPAPER(wxPAPER_B5, DMPAPER_B5, wxTRANSLATE("B5 sheet, 182 x 257 millimeter"), 1820, 2570); + WXADDPAPER(wxPAPER_FOLIO, DMPAPER_FOLIO, wxTRANSLATE("Folio, 8 1/2 x 13 in"), 2159, 3302); + WXADDPAPER(wxPAPER_QUARTO, DMPAPER_QUARTO, wxTRANSLATE("Quarto, 215 x 275 mm"), 2150, 2750); + WXADDPAPER(wxPAPER_10X14, DMPAPER_10X14, wxTRANSLATE("10 x 14 in"), 2540, 3556); + WXADDPAPER(wxPAPER_11X17, DMPAPER_11X17, wxTRANSLATE("11 x 17 in"), 2794, 4318); + WXADDPAPER(wxPAPER_NOTE, DMPAPER_NOTE, wxTRANSLATE("Note, 8 1/2 x 11 in"), 2159, 2794); + WXADDPAPER(wxPAPER_ENV_9, DMPAPER_ENV_9, wxTRANSLATE("#9 Envelope, 3 7/8 x 8 7/8 in"), 984, 2254); + WXADDPAPER(wxPAPER_ENV_10, DMPAPER_ENV_10, wxTRANSLATE("#10 Envelope, 4 1/8 x 9 1/2 in"), 1048, 2413); + WXADDPAPER(wxPAPER_ENV_11, DMPAPER_ENV_11, wxTRANSLATE("#11 Envelope, 4 1/2 x 10 3/8 in"), 1143, 2635); + WXADDPAPER(wxPAPER_ENV_12, DMPAPER_ENV_12, wxTRANSLATE("#12 Envelope, 4 3/4 x 11 in"), 1206, 2794); + WXADDPAPER(wxPAPER_ENV_14, DMPAPER_ENV_14, wxTRANSLATE("#14 Envelope, 5 x 11 1/2 in"), 1270, 2921); + WXADDPAPER(wxPAPER_ENV_DL, DMPAPER_ENV_DL, wxTRANSLATE("DL Envelope, 110 x 220 mm"), 1100, 2200); + WXADDPAPER(wxPAPER_ENV_C5, DMPAPER_ENV_C5, wxTRANSLATE("C5 Envelope, 162 x 229 mm"), 1620, 2290); + WXADDPAPER(wxPAPER_ENV_C3, DMPAPER_ENV_C3, wxTRANSLATE("C3 Envelope, 324 x 458 mm"), 3240, 4580); + WXADDPAPER(wxPAPER_ENV_C4, DMPAPER_ENV_C4, wxTRANSLATE("C4 Envelope, 229 x 324 mm"), 2290, 3240); + WXADDPAPER(wxPAPER_ENV_C6, DMPAPER_ENV_C6, wxTRANSLATE("C6 Envelope, 114 x 162 mm"), 1140, 1620); + WXADDPAPER(wxPAPER_ENV_C65, DMPAPER_ENV_C65, wxTRANSLATE("C65 Envelope, 114 x 229 mm"), 1140, 2290); + WXADDPAPER(wxPAPER_ENV_B4, DMPAPER_ENV_B4, wxTRANSLATE("B4 Envelope, 250 x 353 mm"), 2500, 3530); + WXADDPAPER(wxPAPER_ENV_B5, DMPAPER_ENV_B5, wxTRANSLATE("B5 Envelope, 176 x 250 mm"), 1760, 2500); + WXADDPAPER(wxPAPER_ENV_B6, DMPAPER_ENV_B6, wxTRANSLATE("B6 Envelope, 176 x 125 mm"), 1760, 1250); + WXADDPAPER(wxPAPER_ENV_ITALY, DMPAPER_ENV_ITALY, wxTRANSLATE("Italy Envelope, 110 x 230 mm"), 1100, 2300); + WXADDPAPER(wxPAPER_ENV_MONARCH, DMPAPER_ENV_MONARCH, wxTRANSLATE("Monarch Envelope, 3 7/8 x 7 1/2 in"), 984, 1905); + WXADDPAPER(wxPAPER_ENV_PERSONAL, DMPAPER_ENV_PERSONAL, wxTRANSLATE("6 3/4 Envelope, 3 5/8 x 6 1/2 in"), 921, 1651); + WXADDPAPER(wxPAPER_FANFOLD_US, DMPAPER_FANFOLD_US, wxTRANSLATE("US Std Fanfold, 14 7/8 x 11 in"), 3778, 2794); + WXADDPAPER(wxPAPER_FANFOLD_STD_GERMAN, DMPAPER_FANFOLD_STD_GERMAN, wxTRANSLATE("German Std Fanfold, 8 1/2 x 12 in"), 2159, 3048); + WXADDPAPER(wxPAPER_FANFOLD_LGL_GERMAN, DMPAPER_FANFOLD_LGL_GERMAN, wxTRANSLATE("German Legal Fanfold, 8 1/2 x 13 in"), 2159, 3302); + + WXADDPAPER(wxPAPER_ISO_B4, DMPAPER_ISO_B4, wxTRANSLATE("B4 (ISO) 250 x 353 mm"), 2500, 2530); + WXADDPAPER(wxPAPER_JAPANESE_POSTCARD, DMPAPER_JAPANESE_POSTCARD, wxTRANSLATE("Japanese Postcard 100 x 148 mm"), 1000, 1480); + WXADDPAPER(wxPAPER_9X11, DMPAPER_9X11, wxTRANSLATE("9 x 11 in"), 2286, 2794); + WXADDPAPER(wxPAPER_10X11, DMPAPER_10X11, wxTRANSLATE("10 x 11 in"), 2540, 2794); + WXADDPAPER(wxPAPER_15X11, DMPAPER_15X11, wxTRANSLATE("15 x 11 in"), 3810, 2794); + WXADDPAPER(wxPAPER_ENV_INVITE, DMPAPER_ENV_INVITE, wxTRANSLATE("Envelope Invite 220 x 220 mm"), 2200, 2200); + WXADDPAPER(wxPAPER_LETTER_EXTRA, DMPAPER_LETTER_EXTRA, wxTRANSLATE("Letter Extra 9 1/2 x 12 in"), 2413, 3048); + WXADDPAPER(wxPAPER_LEGAL_EXTRA, DMPAPER_LEGAL_EXTRA, wxTRANSLATE("Legal Extra 9 1/2 x 15 in"), 2413, 3810); + WXADDPAPER(wxPAPER_TABLOID_EXTRA, DMPAPER_TABLOID_EXTRA, wxTRANSLATE("Tabloid Extra 11.69 x 18 in"), 2969, 4572); + WXADDPAPER(wxPAPER_A4_EXTRA, DMPAPER_A4_EXTRA, wxTRANSLATE("A4 Extra 9.27 x 12.69 in"), 2355, 3223); + WXADDPAPER(wxPAPER_LETTER_TRANSVERSE, DMPAPER_LETTER_TRANSVERSE, wxTRANSLATE("Letter Transverse 8 1/2 x 11 in"), 2159, 2794); + WXADDPAPER(wxPAPER_A4_TRANSVERSE, DMPAPER_A4_TRANSVERSE, wxTRANSLATE("A4 Transverse 210 x 297 mm"), 2100, 2970); + WXADDPAPER(wxPAPER_LETTER_EXTRA_TRANSVERSE, DMPAPER_LETTER_EXTRA_TRANSVERSE, wxTRANSLATE("Letter Extra Transverse 9.275 x 12 in"), 2355, 3048); + WXADDPAPER(wxPAPER_A_PLUS, DMPAPER_A_PLUS, wxTRANSLATE("SuperA/SuperA/A4 227 x 356 mm"), 2270, 3560); + WXADDPAPER(wxPAPER_B_PLUS, DMPAPER_B_PLUS, wxTRANSLATE("SuperB/SuperB/A3 305 x 487 mm"), 3050, 4870); + WXADDPAPER(wxPAPER_LETTER_PLUS, DMPAPER_LETTER_PLUS, wxTRANSLATE("Letter Plus 8 1/2 x 12.69 in"), 2159, 3223); + WXADDPAPER(wxPAPER_A4_PLUS, DMPAPER_A4_PLUS, wxTRANSLATE("A4 Plus 210 x 330 mm"), 2100, 3300); + WXADDPAPER(wxPAPER_A5_TRANSVERSE, DMPAPER_A5_TRANSVERSE, wxTRANSLATE("A5 Transverse 148 x 210 mm"), 1480, 2100); + WXADDPAPER(wxPAPER_B5_TRANSVERSE, DMPAPER_B5_TRANSVERSE, wxTRANSLATE("B5 (JIS) Transverse 182 x 257 mm"), 1820, 2570); + WXADDPAPER(wxPAPER_A3_EXTRA, DMPAPER_A3_EXTRA, wxTRANSLATE("A3 Extra 322 x 445 mm"), 3220, 4450); + WXADDPAPER(wxPAPER_A5_EXTRA, DMPAPER_A5_EXTRA, wxTRANSLATE("A5 Extra 174 x 235 mm"), 1740, 2350); + WXADDPAPER(wxPAPER_B5_EXTRA, DMPAPER_B5_EXTRA, wxTRANSLATE("B5 (ISO) Extra 201 x 276 mm"), 2010, 2760); + WXADDPAPER(wxPAPER_A2, DMPAPER_A2, wxTRANSLATE("A2 420 x 594 mm"), 4200, 5940); + WXADDPAPER(wxPAPER_A3_TRANSVERSE, DMPAPER_A3_TRANSVERSE, wxTRANSLATE("A3 Transverse 297 x 420 mm"), 2970, 4200); + WXADDPAPER(wxPAPER_A3_EXTRA_TRANSVERSE,DMPAPER_A3_EXTRA_TRANSVERSE,wxTRANSLATE("A3 Extra Transverse 322 x 445 mm"), 3220, 4450); + + WXADDPAPER(wxPAPER_DBL_JAPANESE_POSTCARD, 69, wxTRANSLATE("Japanese Double Postcard 200 x 148 mm"), 2000, 1480); + WXADDPAPER(wxPAPER_A6, 70, wxTRANSLATE("A6 105 x 148 mm"), 1050, 1480); + WXADDPAPER(wxPAPER_JENV_KAKU2, 71, wxTRANSLATE("Japanese Envelope Kaku #2"), 2400, 3320); + WXADDPAPER(wxPAPER_JENV_KAKU3, 72, wxTRANSLATE("Japanese Envelope Kaku #3"), 2160, 2770); + WXADDPAPER(wxPAPER_JENV_CHOU3, 73, wxTRANSLATE("Japanese Envelope Chou #3"), 1200, 2350); + WXADDPAPER(wxPAPER_JENV_CHOU4, 74, wxTRANSLATE("Japanese Envelope Chou #4"), 900, 2050); + WXADDPAPER(wxPAPER_LETTER_ROTATED, 75, wxTRANSLATE("Letter Rotated 11 x 8 1/2 in"), 2794, 2159); + WXADDPAPER(wxPAPER_A3_ROTATED, 76, wxTRANSLATE("A3 Rotated 420 x 297 mm"), 4200, 2970); + WXADDPAPER(wxPAPER_A4_ROTATED, 77, wxTRANSLATE("A4 Rotated 297 x 210 mm"), 2970, 2100); + WXADDPAPER(wxPAPER_A5_ROTATED, 78, wxTRANSLATE("A5 Rotated 210 x 148 mm"), 2100, 1480); + WXADDPAPER(wxPAPER_B4_JIS_ROTATED, 79, wxTRANSLATE("B4 (JIS) Rotated 364 x 257 mm"), 3640, 2570); + WXADDPAPER(wxPAPER_B5_JIS_ROTATED, 80, wxTRANSLATE("B5 (JIS) Rotated 257 x 182 mm"), 2570, 1820); + WXADDPAPER(wxPAPER_JAPANESE_POSTCARD_ROTATED, 81, wxTRANSLATE("Japanese Postcard Rotated 148 x 100 mm"), 1480, 1000); + WXADDPAPER(wxPAPER_DBL_JAPANESE_POSTCARD_ROTATED, 82, wxTRANSLATE("Double Japanese Postcard Rotated 148 x 200 mm"), 1480, 2000); + WXADDPAPER(wxPAPER_A6_ROTATED, 83, wxTRANSLATE("A6 Rotated 148 x 105 mm"), 1480, 1050); + WXADDPAPER(wxPAPER_JENV_KAKU2_ROTATED, 84, wxTRANSLATE("Japanese Envelope Kaku #2 Rotated"), 3320, 2400); + WXADDPAPER(wxPAPER_JENV_KAKU3_ROTATED, 85, wxTRANSLATE("Japanese Envelope Kaku #3 Rotated"), 2770, 2160); + WXADDPAPER(wxPAPER_JENV_CHOU3_ROTATED, 86, wxTRANSLATE("Japanese Envelope Chou #3 Rotated"), 2350, 1200); + WXADDPAPER(wxPAPER_JENV_CHOU4_ROTATED, 87, wxTRANSLATE("Japanese Envelope Chou #4 Rotated"), 2050, 900); + WXADDPAPER(wxPAPER_B6_JIS, 88, wxTRANSLATE("B6 (JIS) 128 x 182 mm"), 1280, 1820); + WXADDPAPER(wxPAPER_B6_JIS_ROTATED, 89, wxTRANSLATE("B6 (JIS) Rotated 182 x 128 mm"), 1920, 1280); + WXADDPAPER(wxPAPER_12X11, 90, wxTRANSLATE("12 x 11 in"), 3048, 2794); + WXADDPAPER(wxPAPER_JENV_YOU4, 91, wxTRANSLATE("Japanese Envelope You #4"), 2350, 1050); + WXADDPAPER(wxPAPER_JENV_YOU4_ROTATED, 92, wxTRANSLATE("Japanese Envelope You #4 Rotated"), 1050, 2350); + WXADDPAPER(wxPAPER_P16K, 93, wxTRANSLATE("PRC 16K 146 x 215 mm"), 1460, 2150); + WXADDPAPER(wxPAPER_P32K, 94, wxTRANSLATE("PRC 32K 97 x 151 mm"), 970, 1510); + WXADDPAPER(wxPAPER_P32KBIG, 95, wxTRANSLATE("PRC 32K(Big) 97 x 151 mm"), 970, 1510); + WXADDPAPER(wxPAPER_PENV_1, 96, wxTRANSLATE("PRC Envelope #1 102 x 165 mm"), 1020, 1650); + WXADDPAPER(wxPAPER_PENV_2, 97, wxTRANSLATE("PRC Envelope #2 102 x 176 mm"), 1020, 1760); + WXADDPAPER(wxPAPER_PENV_3, 98, wxTRANSLATE("PRC Envelope #3 125 x 176 mm"), 1250, 1760); + WXADDPAPER(wxPAPER_PENV_4, 99, wxTRANSLATE("PRC Envelope #4 110 x 208 mm"), 1100, 2080); + WXADDPAPER(wxPAPER_PENV_5, 100, wxTRANSLATE("PRC Envelope #5 110 x 220 mm"), 1100, 2200); + WXADDPAPER(wxPAPER_PENV_6, 101, wxTRANSLATE("PRC Envelope #6 120 x 230 mm"), 1200, 2300); + WXADDPAPER(wxPAPER_PENV_7, 102, wxTRANSLATE("PRC Envelope #7 160 x 230 mm"), 1600, 2300); + WXADDPAPER(wxPAPER_PENV_8, 103, wxTRANSLATE("PRC Envelope #8 120 x 309 mm"), 1200, 3090); + WXADDPAPER(wxPAPER_PENV_9, 104, wxTRANSLATE("PRC Envelope #9 229 x 324 mm"), 2290, 3240); + WXADDPAPER(wxPAPER_PENV_10, 105, wxTRANSLATE("PRC Envelope #10 324 x 458 mm"), 3240, 4580); + WXADDPAPER(wxPAPER_P16K_ROTATED, 106, wxTRANSLATE("PRC 16K Rotated"), 2150, 1460); + WXADDPAPER(wxPAPER_P32K_ROTATED, 107, wxTRANSLATE("PRC 32K Rotated"), 1510, 970); + WXADDPAPER(wxPAPER_P32KBIG_ROTATED, 108, wxTRANSLATE("PRC 32K(Big) Rotated"), 1510, 970); + WXADDPAPER(wxPAPER_PENV_1_ROTATED, 109, wxTRANSLATE("PRC Envelope #1 Rotated 165 x 102 mm"), 1650, 1020); + WXADDPAPER(wxPAPER_PENV_2_ROTATED, 110, wxTRANSLATE("PRC Envelope #2 Rotated 176 x 102 mm"), 1760, 1020); + WXADDPAPER(wxPAPER_PENV_3_ROTATED, 111, wxTRANSLATE("PRC Envelope #3 Rotated 176 x 125 mm"), 1760, 1250); + WXADDPAPER(wxPAPER_PENV_4_ROTATED, 112, wxTRANSLATE("PRC Envelope #4 Rotated 208 x 110 mm"), 2080, 1100); + WXADDPAPER(wxPAPER_PENV_5_ROTATED, 113, wxTRANSLATE("PRC Envelope #5 Rotated 220 x 110 mm"), 2200, 1100); + WXADDPAPER(wxPAPER_PENV_6_ROTATED, 114, wxTRANSLATE("PRC Envelope #6 Rotated 230 x 120 mm"), 2300, 1200); + WXADDPAPER(wxPAPER_PENV_7_ROTATED, 115, wxTRANSLATE("PRC Envelope #7 Rotated 230 x 160 mm"), 2300, 1600); + WXADDPAPER(wxPAPER_PENV_8_ROTATED, 116, wxTRANSLATE("PRC Envelope #8 Rotated 309 x 120 mm"), 3090, 1200); + WXADDPAPER(wxPAPER_PENV_9_ROTATED, 117, wxTRANSLATE("PRC Envelope #9 Rotated 324 x 229 mm"), 3240, 2290); + WXADDPAPER(wxPAPER_PENV_10_ROTATED, 118, wxTRANSLATE("PRC Envelope #10 Rotated 458 x 324 mm"), 4580, 3240); +} + +void wxPrintPaperDatabase::ClearDatabase() +{ + delete m_list; + WX_CLEAR_HASH_MAP(wxStringToPrintPaperTypeHashMap, *m_map); + delete m_map; +} + +void wxPrintPaperDatabase::AddPaperType(wxPaperSize paperId, const wxString& name, int w, int h) +{ + wxPrintPaperType* tmp = new wxPrintPaperType(paperId, 0, name, w, h); + (*m_map)[name] = tmp; + m_list->push_back(tmp); +} + +void wxPrintPaperDatabase::AddPaperType(wxPaperSize paperId, int platformId, const wxString& name, int w, int h) +{ + wxPrintPaperType* tmp = new wxPrintPaperType(paperId, platformId, name, w, h); + (*m_map)[name] = tmp; + m_list->push_back(tmp); +} + +wxPrintPaperType *wxPrintPaperDatabase::FindPaperType(const wxString& name) +{ + wxStringToPrintPaperTypeHashMap::iterator it = m_map->find(name); + if (it != m_map->end()) + return it->second; + else + return NULL; +} + +wxPrintPaperType *wxPrintPaperDatabase::FindPaperType(wxPaperSize id) +{ + typedef wxStringToPrintPaperTypeHashMap::iterator iterator; + + for (iterator it = m_map->begin(), en = m_map->end(); it != en; ++it) + { + wxPrintPaperType* paperType = it->second; + if (paperType->GetId() == id) + return paperType; + } + + return NULL; +} + +wxPrintPaperType *wxPrintPaperDatabase::FindPaperTypeByPlatformId(int id) +{ + typedef wxStringToPrintPaperTypeHashMap::iterator iterator; + + for (iterator it = m_map->begin(), en = m_map->end(); it != en; ++it) + { + wxPrintPaperType* paperType = it->second; + if (paperType->GetPlatformId() == id) + return paperType; + } + + return NULL; +} + +wxPrintPaperType *wxPrintPaperDatabase::FindPaperType(const wxSize& sz) +{ + // Take the item ordering into account so that the more common types + // are likely to be taken into account first. This fixes problems with, + // for example, Letter reverting to A4 in the page setup dialog because + // it was wrongly translated to Note. + size_t i; + for (i = 0; i < GetCount(); i++) + { + wxPrintPaperType* paperType = Item(i); + wxSize paperSize = paperType->GetSize() ; + if ( abs( paperSize.x - sz.x ) < 10 && abs( paperSize.y - sz.y ) < 10 ) + return paperType; + } + + return NULL; +} + +// Convert name to size id +wxPaperSize wxPrintPaperDatabase::ConvertNameToId(const wxString& name) +{ + wxPrintPaperType* type = FindPaperType(name); + if (type) + return type->GetId(); + else + return wxPAPER_NONE; +} + +// Convert size id to name +wxString wxPrintPaperDatabase::ConvertIdToName(wxPaperSize paperId) +{ + wxPrintPaperType* type = FindPaperType(paperId); + if (type) + return type->GetName(); + else + return wxEmptyString; +} + +// Get the paper size +wxSize wxPrintPaperDatabase::GetSize(wxPaperSize paperId) +{ + wxPrintPaperType* type = FindPaperType(paperId); + if (type) + return type->GetSize(); + else + return wxSize(0,0); +} + +// Get the paper size +wxPaperSize wxPrintPaperDatabase::GetSize(const wxSize& size) +{ + wxPrintPaperType* type = FindPaperType(size); + if (type) + return type->GetId(); + else + return wxPAPER_NONE; +} + +// QUICK and DIRTY +size_t wxPrintPaperDatabase::GetCount() const +{ + return m_list->GetCount(); +} + +wxPrintPaperType* wxPrintPaperDatabase::Item(size_t index) const +{ + return m_list->Item(index)->GetData(); +} + +// A module to allow initialization/cleanup of print paper +// things without calling these functions from app.cpp. + +class WXDLLEXPORT wxPrintPaperModule: public wxModule +{ +DECLARE_DYNAMIC_CLASS(wxPrintPaperModule) +public: + wxPrintPaperModule() {} + bool OnInit(); + void OnExit(); +}; + +IMPLEMENT_DYNAMIC_CLASS(wxPrintPaperModule, wxModule) + +/* + * Initialization/cleanup module + */ + +bool wxPrintPaperModule::OnInit() +{ + wxThePrintPaperDatabase = new wxPrintPaperDatabase; + wxThePrintPaperDatabase->CreateDatabase(); + + return true; +} + +void wxPrintPaperModule::OnExit() +{ + delete wxThePrintPaperDatabase; + wxThePrintPaperDatabase = NULL; +} + +#endif // wxUSE_PRINTING_ARCHITECTURE diff --git a/Source/3rd Party/wx/src/common/pickerbase.cpp b/Source/3rd Party/wx/src/common/pickerbase.cpp index 81c30782b..87c99066c 100644 --- a/Source/3rd Party/wx/src/common/pickerbase.cpp +++ b/Source/3rd Party/wx/src/common/pickerbase.cpp @@ -1,175 +1,175 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/pickerbase.cpp -// Purpose: wxPickerBase class implementation -// Author: Francesco Montorsi -// Modified by: -// Created: 15/04/2006 -// RCS-ID: $Id: pickerbase.cpp 58463 2009-01-27 17:39:50Z BP $ -// Copyright: (c) Francesco Montorsi -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_COLOURPICKERCTRL || \ - wxUSE_DIRPICKERCTRL || \ - wxUSE_FILEPICKERCTRL || \ - wxUSE_FONTPICKERCTRL - -#include "wx/pickerbase.h" -#include "wx/tooltip.h" - -#ifndef WX_PRECOMP - #include "wx/textctrl.h" -#endif - - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_ABSTRACT_CLASS(wxPickerBase, wxControl) - -BEGIN_EVENT_TABLE(wxPickerBase, wxControl) - EVT_SIZE(wxPickerBase::OnSize) - WX_EVENT_TABLE_CONTROL_CONTAINER(wxPickerBase) -END_EVENT_TABLE() -WX_DELEGATE_TO_CONTROL_CONTAINER(wxPickerBase, wxControl) - - -// ---------------------------------------------------------------------------- -// wxPickerBase -// ---------------------------------------------------------------------------- - -bool wxPickerBase::CreateBase(wxWindow *parent, - wxWindowID id, - const wxString &text, - const wxPoint& pos, - const wxSize& size, - long style, - const wxValidator& validator, - const wxString& name) -{ - // remove any border style from our style as wxPickerBase's window must be - // invisible (user styles must be set on the textctrl or the platform-dependent picker) - style &= ~wxBORDER_MASK; - if (!wxControl::Create(parent, id, pos, size, style | wxNO_BORDER | wxTAB_TRAVERSAL, - validator, name)) - return false; - - m_sizer = new wxBoxSizer(wxHORIZONTAL); - - if (HasFlag(wxPB_USE_TEXTCTRL)) - { - // NOTE: the style of this class (wxPickerBase) and the style of the - // attached text control are different: GetTextCtrlStyle() extracts - // the styles related to the textctrl from the styles passed here - m_text = new wxTextCtrl(this, wxID_ANY, wxEmptyString, - wxDefaultPosition, wxDefaultSize, - GetTextCtrlStyle(style)); - if (!m_text) - { - wxFAIL_MSG( wxT("wxPickerBase's textctrl creation failed") ); - return false; - } - - // set the maximum lenght allowed for this textctrl. - // This is very important since any change to it will trigger an update in - // the m_picker; for very long strings, this real-time synchronization could - // become a CPU-blocker and thus should be avoided. - // 32 characters will be more than enough for all common uses. - m_text->SetMaxLength(32); - - // set the initial contents of the textctrl - m_text->SetValue(text); - - m_text->Connect(m_text->GetId(), wxEVT_COMMAND_TEXT_UPDATED, - wxCommandEventHandler(wxPickerBase::OnTextCtrlUpdate), - NULL, this); - m_text->Connect(m_text->GetId(), wxEVT_KILL_FOCUS, - wxFocusEventHandler(wxPickerBase::OnTextCtrlKillFocus), - NULL, this); - - m_text->Connect(m_text->GetId(), wxEVT_DESTROY, - wxWindowDestroyEventHandler(wxPickerBase::OnTextCtrlDelete), - NULL, this); - - // the text control's proportion values defaults to 2 - m_sizer->Add(m_text, 2, GetDefaultTextCtrlFlag(), 5); - } - - return true; -} - -void wxPickerBase::PostCreation() -{ - // the picker's proportion value defaults to 1 when there's no text control - // associated with it - in that case it defaults to 0 - m_sizer->Add(m_picker, HasTextCtrl() ? 0 : 1, GetDefaultPickerCtrlFlag(), 5); - - SetSizer(m_sizer); - SetMinSize( m_sizer->GetMinSize() ); -} - -#if wxUSE_TOOLTIPS - -void wxPickerBase::DoSetToolTip(wxToolTip *tip) -{ - // don't set the tooltip on us but rather on our two child windows - // as otherwise it would appear only when the cursor is placed on the - // small area around the child windows which belong to wxPickerBase - m_picker->SetToolTip(tip); - - // do a copy as wxWindow will own the pointer we pass - if ( m_text ) - m_text->SetToolTip(tip ? new wxToolTip(tip->GetTip()) : NULL); -} - -#endif // wxUSE_TOOLTIPS - -// ---------------------------------------------------------------------------- -// wxPickerBase - event handlers -// ---------------------------------------------------------------------------- - -void wxPickerBase::OnTextCtrlKillFocus(wxFocusEvent& event) -{ - event.Skip(); - - // don't leave the textctrl empty - if (m_text && m_text->GetValue().empty()) - UpdateTextCtrlFromPicker(); -} - -void wxPickerBase::OnTextCtrlDelete(wxWindowDestroyEvent &) -{ - // the textctrl has been deleted; our pointer is invalid! - m_text = NULL; -} - -void wxPickerBase::OnTextCtrlUpdate(wxCommandEvent &) -{ - // for each text-change, update the picker - UpdatePickerFromTextCtrl(); -} - -void wxPickerBase::OnSize(wxSizeEvent &event) -{ - if (GetAutoLayout()) - Layout(); - event.Skip(); -} - -#endif // Any picker in use +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/pickerbase.cpp +// Purpose: wxPickerBase class implementation +// Author: Francesco Montorsi +// Modified by: +// Created: 15/04/2006 +// RCS-ID: $Id: pickerbase.cpp 58463 2009-01-27 17:39:50Z BP $ +// Copyright: (c) Francesco Montorsi +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_COLOURPICKERCTRL || \ + wxUSE_DIRPICKERCTRL || \ + wxUSE_FILEPICKERCTRL || \ + wxUSE_FONTPICKERCTRL + +#include "wx/pickerbase.h" +#include "wx/tooltip.h" + +#ifndef WX_PRECOMP + #include "wx/textctrl.h" +#endif + + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_ABSTRACT_CLASS(wxPickerBase, wxControl) + +BEGIN_EVENT_TABLE(wxPickerBase, wxControl) + EVT_SIZE(wxPickerBase::OnSize) + WX_EVENT_TABLE_CONTROL_CONTAINER(wxPickerBase) +END_EVENT_TABLE() +WX_DELEGATE_TO_CONTROL_CONTAINER(wxPickerBase, wxControl) + + +// ---------------------------------------------------------------------------- +// wxPickerBase +// ---------------------------------------------------------------------------- + +bool wxPickerBase::CreateBase(wxWindow *parent, + wxWindowID id, + const wxString &text, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + // remove any border style from our style as wxPickerBase's window must be + // invisible (user styles must be set on the textctrl or the platform-dependent picker) + style &= ~wxBORDER_MASK; + if (!wxControl::Create(parent, id, pos, size, style | wxNO_BORDER | wxTAB_TRAVERSAL, + validator, name)) + return false; + + m_sizer = new wxBoxSizer(wxHORIZONTAL); + + if (HasFlag(wxPB_USE_TEXTCTRL)) + { + // NOTE: the style of this class (wxPickerBase) and the style of the + // attached text control are different: GetTextCtrlStyle() extracts + // the styles related to the textctrl from the styles passed here + m_text = new wxTextCtrl(this, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + GetTextCtrlStyle(style)); + if (!m_text) + { + wxFAIL_MSG( wxT("wxPickerBase's textctrl creation failed") ); + return false; + } + + // set the maximum lenght allowed for this textctrl. + // This is very important since any change to it will trigger an update in + // the m_picker; for very long strings, this real-time synchronization could + // become a CPU-blocker and thus should be avoided. + // 32 characters will be more than enough for all common uses. + m_text->SetMaxLength(32); + + // set the initial contents of the textctrl + m_text->SetValue(text); + + m_text->Connect(m_text->GetId(), wxEVT_COMMAND_TEXT_UPDATED, + wxCommandEventHandler(wxPickerBase::OnTextCtrlUpdate), + NULL, this); + m_text->Connect(m_text->GetId(), wxEVT_KILL_FOCUS, + wxFocusEventHandler(wxPickerBase::OnTextCtrlKillFocus), + NULL, this); + + m_text->Connect(m_text->GetId(), wxEVT_DESTROY, + wxWindowDestroyEventHandler(wxPickerBase::OnTextCtrlDelete), + NULL, this); + + // the text control's proportion values defaults to 2 + m_sizer->Add(m_text, 2, GetDefaultTextCtrlFlag(), 5); + } + + return true; +} + +void wxPickerBase::PostCreation() +{ + // the picker's proportion value defaults to 1 when there's no text control + // associated with it - in that case it defaults to 0 + m_sizer->Add(m_picker, HasTextCtrl() ? 0 : 1, GetDefaultPickerCtrlFlag(), 5); + + SetSizer(m_sizer); + SetMinSize( m_sizer->GetMinSize() ); +} + +#if wxUSE_TOOLTIPS + +void wxPickerBase::DoSetToolTip(wxToolTip *tip) +{ + // don't set the tooltip on us but rather on our two child windows + // as otherwise it would appear only when the cursor is placed on the + // small area around the child windows which belong to wxPickerBase + m_picker->SetToolTip(tip); + + // do a copy as wxWindow will own the pointer we pass + if ( m_text ) + m_text->SetToolTip(tip ? new wxToolTip(tip->GetTip()) : NULL); +} + +#endif // wxUSE_TOOLTIPS + +// ---------------------------------------------------------------------------- +// wxPickerBase - event handlers +// ---------------------------------------------------------------------------- + +void wxPickerBase::OnTextCtrlKillFocus(wxFocusEvent& event) +{ + event.Skip(); + + // don't leave the textctrl empty + if (m_text && m_text->GetValue().empty()) + UpdateTextCtrlFromPicker(); +} + +void wxPickerBase::OnTextCtrlDelete(wxWindowDestroyEvent &) +{ + // the textctrl has been deleted; our pointer is invalid! + m_text = NULL; +} + +void wxPickerBase::OnTextCtrlUpdate(wxCommandEvent &) +{ + // for each text-change, update the picker + UpdatePickerFromTextCtrl(); +} + +void wxPickerBase::OnSize(wxSizeEvent &event) +{ + if (GetAutoLayout()) + Layout(); + event.Skip(); +} + +#endif // Any picker in use diff --git a/Source/3rd Party/wx/src/common/platinfo.cpp b/Source/3rd Party/wx/src/common/platinfo.cpp index c61fc393d..bf33db2e6 100644 --- a/Source/3rd Party/wx/src/common/platinfo.cpp +++ b/Source/3rd Party/wx/src/common/platinfo.cpp @@ -1,336 +1,336 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/platinfo.cpp -// Purpose: implements wxPlatformInfo class -// Author: Francesco Montorsi -// Modified by: -// Created: 07.07.2006 (based on wxToolkitInfo) -// RCS-ID: $Id: platinfo.cpp 44078 2006-12-30 21:46:22Z SN $ -// Copyright: (c) 2006 Francesco Montorsi -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/platinfo.h" - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/utils.h" -#endif //WX_PRECOMP - -#include "wx/apptrait.h" - -// global object -// VERY IMPORTANT: do not use the default constructor since it would -// try to init the wxPlatformInfo instance using -// gs_platInfo itself! -static wxPlatformInfo gs_platInfo(wxPORT_UNKNOWN); - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -static const wxChar* const wxOperatingSystemIdNames[] = -{ - _T("Apple Mac OS"), - _T("Apple Mac OS X"), - - _T("Microsoft Windows 9X"), - _T("Microsoft Windows NT"), - _T("Microsoft Windows Micro"), - _T("Microsoft Windows CE"), - - _T("Linux"), - _T("FreeBSD"), - _T("OpenBSD"), - _T("NetBSD"), - - _T("SunOS"), - _T("AIX"), - _T("HPUX"), - - _T("Other Unix"), - _T("Other Unix"), - - _T("DOS"), - _T("OS/2") -}; - -static const wxChar* const wxPortIdNames[] = -{ - _T("wxBase"), - _T("wxMSW"), - _T("wxMotif"), - _T("wxGTK"), - _T("wxMGL"), - _T("wxX11"), - _T("wxOS2"), - _T("wxMac"), - _T("wxCocoa"), - _T("wxWinCE"), - _T("wxPalmOS"), - _T("wxDFB") -}; - -static const wxChar* const wxArchitectureNames[] = -{ - _T("32 bit"), - _T("64 bit") -}; - -static const wxChar* const wxEndiannessNames[] = -{ - _T("Big endian"), - _T("Little endian"), - _T("PDP endian") -}; - -// ---------------------------------------------------------------------------- -// local functions -// ---------------------------------------------------------------------------- - -// returns log in base 2 of the value, this maps the enum values to the -// corresponding indices -static unsigned wxGetIndexFromEnumValue(int value) -{ - wxCHECK_MSG( value, (unsigned)-1, _T("invalid enum value") ); - - int n = 0; - while ( !(value & 1) ) - { - value >>= 1; - n++; - } - - wxASSERT_MSG( value == 1, _T("more than one bit set in enum value") ); - - return n; -} - -// ---------------------------------------------------------------------------- -// wxPlatformInfo -// ---------------------------------------------------------------------------- - -wxPlatformInfo::wxPlatformInfo() -{ - // just copy platform info for currently running platform - *this = Get(); -} - -wxPlatformInfo::wxPlatformInfo(wxPortId pid, int tkMajor, int tkMinor, - wxOperatingSystemId id, int osMajor, int osMinor, - wxArchitecture arch, - wxEndianness endian, - bool usingUniversal) -{ - m_tkVersionMajor = tkMajor; - m_tkVersionMinor = tkMinor; - m_port = pid; - m_usingUniversal = usingUniversal; - - m_os = id; - m_osVersionMajor = osMajor; - m_osVersionMinor = osMinor; - - m_endian = endian; - m_arch = arch; -} - -bool wxPlatformInfo::operator==(const wxPlatformInfo &t) const -{ - return m_tkVersionMajor == t.m_tkVersionMajor && - m_tkVersionMinor == t.m_tkVersionMinor && - m_osVersionMajor == t.m_osVersionMajor && - m_osVersionMinor == t.m_osVersionMinor && - m_os == t.m_os && - m_port == t.m_port && - m_usingUniversal == t.m_usingUniversal && - m_arch == t.m_arch && - m_endian == t.m_endian; -} - -void wxPlatformInfo::InitForCurrentPlatform() -{ - // autodetect all informations - const wxAppTraits * const traits = wxTheApp ? wxTheApp->GetTraits() : NULL; - if ( !traits ) - { - wxFAIL_MSG( _T("failed to initialize wxPlatformInfo") ); - - m_port = wxPORT_UNKNOWN; - m_usingUniversal = false; - m_tkVersionMajor = - m_tkVersionMinor = 0; - } - else - { - m_port = traits->GetToolkitVersion(&m_tkVersionMajor, &m_tkVersionMinor); - m_usingUniversal = traits->IsUsingUniversalWidgets(); - } - - m_os = wxGetOsVersion(&m_osVersionMajor, &m_osVersionMinor); - m_endian = wxIsPlatformLittleEndian() ? wxENDIAN_LITTLE : wxENDIAN_BIG; - m_arch = wxIsPlatform64Bit() ? wxARCH_64 : wxARCH_32; -} - -/* static */ -const wxPlatformInfo& wxPlatformInfo::Get() -{ - static bool initialized = false; - if ( !initialized ) - { - gs_platInfo.InitForCurrentPlatform(); - initialized = true; - } - - return gs_platInfo; -} - - - -// ---------------------------------------------------------------------------- -// wxPlatformInfo - enum -> string conversions -// ---------------------------------------------------------------------------- - -wxString wxPlatformInfo::GetOperatingSystemFamilyName(wxOperatingSystemId os) -{ - const wxChar* string = _T("Unknown"); - if ( os & wxOS_MAC ) - string = _T("Macintosh"); - else if ( os & wxOS_WINDOWS ) - string = _T("Windows"); - else if ( os & wxOS_UNIX ) - string = _T("Unix"); - else if ( os == wxOS_DOS ) - string = _T("DOS"); - else if ( os == wxOS_OS2 ) - string = _T("OS/2"); - - return string; -} - -wxString wxPlatformInfo::GetOperatingSystemIdName(wxOperatingSystemId os) -{ - const unsigned idx = wxGetIndexFromEnumValue(os); - - wxCHECK_MSG( idx < WXSIZEOF(wxOperatingSystemIdNames), wxEmptyString, - _T("invalid OS id") ); - - return wxOperatingSystemIdNames[idx]; -} - -wxString wxPlatformInfo::GetPortIdName(wxPortId port, bool usingUniversal) -{ - const unsigned idx = wxGetIndexFromEnumValue(port); - - wxCHECK_MSG( idx < WXSIZEOF(wxPortIdNames), wxEmptyString, - _T("invalid port id") ); - - wxString ret = wxPortIdNames[idx]; - - if ( usingUniversal ) - ret += wxT("/wxUniversal"); - - return ret; -} - -wxString wxPlatformInfo::GetPortIdShortName(wxPortId port, bool usingUniversal) -{ - const unsigned idx = wxGetIndexFromEnumValue(port); - - wxCHECK_MSG( idx < WXSIZEOF(wxPortIdNames), wxEmptyString, - _T("invalid port id") ); - - wxString ret = wxPortIdNames[idx]; - ret = ret.Mid(2).Lower(); // remove 'wx' prefix - - if ( usingUniversal ) - ret += wxT("univ"); - - return ret; -} - -wxString wxPlatformInfo::GetArchName(wxArchitecture arch) -{ - wxCOMPILE_TIME_ASSERT( WXSIZEOF(wxArchitectureNames) == wxARCH_MAX, - wxArchitectureNamesMismatch ); - - return wxArchitectureNames[arch]; -} - -wxString wxPlatformInfo::GetEndiannessName(wxEndianness end) -{ - wxCOMPILE_TIME_ASSERT( WXSIZEOF(wxEndiannessNames) == wxENDIAN_MAX, - wxEndiannessNamesMismatch ); - - return wxEndiannessNames[end]; -} - - -// ---------------------------------------------------------------------------- -// wxPlatformInfo - string -> enum conversions -// ---------------------------------------------------------------------------- - -wxOperatingSystemId wxPlatformInfo::GetOperatingSystemId(const wxString &str) -{ - for ( size_t i = 0; i < WXSIZEOF(wxOperatingSystemIdNames); i++ ) - { - if ( wxString(wxOperatingSystemIdNames[i]).CmpNoCase(str) == 0 ) - return (wxOperatingSystemId)(1 << i); - } - - return wxOS_UNKNOWN; -} - -wxPortId wxPlatformInfo::GetPortId(const wxString &str) -{ - // recognize both short and long port names - for ( size_t i = 0; i < WXSIZEOF(wxPortIdNames); i++ ) - { - wxPortId current = (wxPortId)(1 << i); - - if ( wxString(wxPortIdNames[i]).CmpNoCase(str) == 0 || - GetPortIdShortName(current, true).CmpNoCase(str) == 0 || - GetPortIdShortName(current, false).CmpNoCase(str) == 0 ) - return current; - } - - return wxPORT_UNKNOWN; -} - -wxArchitecture wxPlatformInfo::GetArch(const wxString &arch) -{ - if ( arch.Contains(wxT("32")) ) - return wxARCH_32; - - if ( arch.Contains(wxT("64")) ) - return wxARCH_64; - - return wxARCH_INVALID; -} - -wxEndianness wxPlatformInfo::GetEndianness(const wxString& end) -{ - wxString endl(end.Lower()); - if ( end.StartsWith(wxT("little")) ) - return wxENDIAN_LITTLE; - - if ( end.StartsWith(wxT("big")) ) - return wxENDIAN_BIG; - - return wxENDIAN_INVALID; -} - +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/platinfo.cpp +// Purpose: implements wxPlatformInfo class +// Author: Francesco Montorsi +// Modified by: +// Created: 07.07.2006 (based on wxToolkitInfo) +// RCS-ID: $Id: platinfo.cpp 44078 2006-12-30 21:46:22Z SN $ +// Copyright: (c) 2006 Francesco Montorsi +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/platinfo.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/utils.h" +#endif //WX_PRECOMP + +#include "wx/apptrait.h" + +// global object +// VERY IMPORTANT: do not use the default constructor since it would +// try to init the wxPlatformInfo instance using +// gs_platInfo itself! +static wxPlatformInfo gs_platInfo(wxPORT_UNKNOWN); + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +static const wxChar* const wxOperatingSystemIdNames[] = +{ + _T("Apple Mac OS"), + _T("Apple Mac OS X"), + + _T("Microsoft Windows 9X"), + _T("Microsoft Windows NT"), + _T("Microsoft Windows Micro"), + _T("Microsoft Windows CE"), + + _T("Linux"), + _T("FreeBSD"), + _T("OpenBSD"), + _T("NetBSD"), + + _T("SunOS"), + _T("AIX"), + _T("HPUX"), + + _T("Other Unix"), + _T("Other Unix"), + + _T("DOS"), + _T("OS/2") +}; + +static const wxChar* const wxPortIdNames[] = +{ + _T("wxBase"), + _T("wxMSW"), + _T("wxMotif"), + _T("wxGTK"), + _T("wxMGL"), + _T("wxX11"), + _T("wxOS2"), + _T("wxMac"), + _T("wxCocoa"), + _T("wxWinCE"), + _T("wxPalmOS"), + _T("wxDFB") +}; + +static const wxChar* const wxArchitectureNames[] = +{ + _T("32 bit"), + _T("64 bit") +}; + +static const wxChar* const wxEndiannessNames[] = +{ + _T("Big endian"), + _T("Little endian"), + _T("PDP endian") +}; + +// ---------------------------------------------------------------------------- +// local functions +// ---------------------------------------------------------------------------- + +// returns log in base 2 of the value, this maps the enum values to the +// corresponding indices +static unsigned wxGetIndexFromEnumValue(int value) +{ + wxCHECK_MSG( value, (unsigned)-1, _T("invalid enum value") ); + + int n = 0; + while ( !(value & 1) ) + { + value >>= 1; + n++; + } + + wxASSERT_MSG( value == 1, _T("more than one bit set in enum value") ); + + return n; +} + +// ---------------------------------------------------------------------------- +// wxPlatformInfo +// ---------------------------------------------------------------------------- + +wxPlatformInfo::wxPlatformInfo() +{ + // just copy platform info for currently running platform + *this = Get(); +} + +wxPlatformInfo::wxPlatformInfo(wxPortId pid, int tkMajor, int tkMinor, + wxOperatingSystemId id, int osMajor, int osMinor, + wxArchitecture arch, + wxEndianness endian, + bool usingUniversal) +{ + m_tkVersionMajor = tkMajor; + m_tkVersionMinor = tkMinor; + m_port = pid; + m_usingUniversal = usingUniversal; + + m_os = id; + m_osVersionMajor = osMajor; + m_osVersionMinor = osMinor; + + m_endian = endian; + m_arch = arch; +} + +bool wxPlatformInfo::operator==(const wxPlatformInfo &t) const +{ + return m_tkVersionMajor == t.m_tkVersionMajor && + m_tkVersionMinor == t.m_tkVersionMinor && + m_osVersionMajor == t.m_osVersionMajor && + m_osVersionMinor == t.m_osVersionMinor && + m_os == t.m_os && + m_port == t.m_port && + m_usingUniversal == t.m_usingUniversal && + m_arch == t.m_arch && + m_endian == t.m_endian; +} + +void wxPlatformInfo::InitForCurrentPlatform() +{ + // autodetect all informations + const wxAppTraits * const traits = wxTheApp ? wxTheApp->GetTraits() : NULL; + if ( !traits ) + { + wxFAIL_MSG( _T("failed to initialize wxPlatformInfo") ); + + m_port = wxPORT_UNKNOWN; + m_usingUniversal = false; + m_tkVersionMajor = + m_tkVersionMinor = 0; + } + else + { + m_port = traits->GetToolkitVersion(&m_tkVersionMajor, &m_tkVersionMinor); + m_usingUniversal = traits->IsUsingUniversalWidgets(); + } + + m_os = wxGetOsVersion(&m_osVersionMajor, &m_osVersionMinor); + m_endian = wxIsPlatformLittleEndian() ? wxENDIAN_LITTLE : wxENDIAN_BIG; + m_arch = wxIsPlatform64Bit() ? wxARCH_64 : wxARCH_32; +} + +/* static */ +const wxPlatformInfo& wxPlatformInfo::Get() +{ + static bool initialized = false; + if ( !initialized ) + { + gs_platInfo.InitForCurrentPlatform(); + initialized = true; + } + + return gs_platInfo; +} + + + +// ---------------------------------------------------------------------------- +// wxPlatformInfo - enum -> string conversions +// ---------------------------------------------------------------------------- + +wxString wxPlatformInfo::GetOperatingSystemFamilyName(wxOperatingSystemId os) +{ + const wxChar* string = _T("Unknown"); + if ( os & wxOS_MAC ) + string = _T("Macintosh"); + else if ( os & wxOS_WINDOWS ) + string = _T("Windows"); + else if ( os & wxOS_UNIX ) + string = _T("Unix"); + else if ( os == wxOS_DOS ) + string = _T("DOS"); + else if ( os == wxOS_OS2 ) + string = _T("OS/2"); + + return string; +} + +wxString wxPlatformInfo::GetOperatingSystemIdName(wxOperatingSystemId os) +{ + const unsigned idx = wxGetIndexFromEnumValue(os); + + wxCHECK_MSG( idx < WXSIZEOF(wxOperatingSystemIdNames), wxEmptyString, + _T("invalid OS id") ); + + return wxOperatingSystemIdNames[idx]; +} + +wxString wxPlatformInfo::GetPortIdName(wxPortId port, bool usingUniversal) +{ + const unsigned idx = wxGetIndexFromEnumValue(port); + + wxCHECK_MSG( idx < WXSIZEOF(wxPortIdNames), wxEmptyString, + _T("invalid port id") ); + + wxString ret = wxPortIdNames[idx]; + + if ( usingUniversal ) + ret += wxT("/wxUniversal"); + + return ret; +} + +wxString wxPlatformInfo::GetPortIdShortName(wxPortId port, bool usingUniversal) +{ + const unsigned idx = wxGetIndexFromEnumValue(port); + + wxCHECK_MSG( idx < WXSIZEOF(wxPortIdNames), wxEmptyString, + _T("invalid port id") ); + + wxString ret = wxPortIdNames[idx]; + ret = ret.Mid(2).Lower(); // remove 'wx' prefix + + if ( usingUniversal ) + ret += wxT("univ"); + + return ret; +} + +wxString wxPlatformInfo::GetArchName(wxArchitecture arch) +{ + wxCOMPILE_TIME_ASSERT( WXSIZEOF(wxArchitectureNames) == wxARCH_MAX, + wxArchitectureNamesMismatch ); + + return wxArchitectureNames[arch]; +} + +wxString wxPlatformInfo::GetEndiannessName(wxEndianness end) +{ + wxCOMPILE_TIME_ASSERT( WXSIZEOF(wxEndiannessNames) == wxENDIAN_MAX, + wxEndiannessNamesMismatch ); + + return wxEndiannessNames[end]; +} + + +// ---------------------------------------------------------------------------- +// wxPlatformInfo - string -> enum conversions +// ---------------------------------------------------------------------------- + +wxOperatingSystemId wxPlatformInfo::GetOperatingSystemId(const wxString &str) +{ + for ( size_t i = 0; i < WXSIZEOF(wxOperatingSystemIdNames); i++ ) + { + if ( wxString(wxOperatingSystemIdNames[i]).CmpNoCase(str) == 0 ) + return (wxOperatingSystemId)(1 << i); + } + + return wxOS_UNKNOWN; +} + +wxPortId wxPlatformInfo::GetPortId(const wxString &str) +{ + // recognize both short and long port names + for ( size_t i = 0; i < WXSIZEOF(wxPortIdNames); i++ ) + { + wxPortId current = (wxPortId)(1 << i); + + if ( wxString(wxPortIdNames[i]).CmpNoCase(str) == 0 || + GetPortIdShortName(current, true).CmpNoCase(str) == 0 || + GetPortIdShortName(current, false).CmpNoCase(str) == 0 ) + return current; + } + + return wxPORT_UNKNOWN; +} + +wxArchitecture wxPlatformInfo::GetArch(const wxString &arch) +{ + if ( arch.Contains(wxT("32")) ) + return wxARCH_32; + + if ( arch.Contains(wxT("64")) ) + return wxARCH_64; + + return wxARCH_INVALID; +} + +wxEndianness wxPlatformInfo::GetEndianness(const wxString& end) +{ + wxString endl(end.Lower()); + if ( end.StartsWith(wxT("little")) ) + return wxENDIAN_LITTLE; + + if ( end.StartsWith(wxT("big")) ) + return wxENDIAN_BIG; + + return wxENDIAN_INVALID; +} + diff --git a/Source/3rd Party/wx/src/common/popupcmn.cpp b/Source/3rd Party/wx/src/common/popupcmn.cpp index cbb7f0529..7582c313e 100644 --- a/Source/3rd Party/wx/src/common/popupcmn.cpp +++ b/Source/3rd Party/wx/src/common/popupcmn.cpp @@ -1,623 +1,623 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/popupcmn.cpp -// Purpose: implementation of wxPopupTransientWindow -// Author: Vadim Zeitlin -// Modified by: -// Created: 06.01.01 -// RCS-ID: $Id: popupcmn.cpp 61466 2009-07-19 16:45:08Z VZ $ -// Copyright: (c) 2001 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_POPUPWIN - -#include "wx/popupwin.h" - -#ifndef WX_PRECOMP - #include "wx/combobox.h" // wxComboCtrl - #include "wx/app.h" // wxPostEvent - #include "wx/log.h" -#endif //WX_PRECOMP - -#include "wx/display.h" -#include "wx/recguard.h" - -#ifdef __WXUNIVERSAL__ - #include "wx/univ/renderer.h" - #include "wx/scrolbar.h" -#endif // __WXUNIVERSAL__ - -#ifdef __WXGTK__ - #include -#elif defined(__WXMSW__) - #include "wx/msw/private.h" -#elif defined(__WXX11__) - #include "wx/x11/private.h" -#endif - -IMPLEMENT_DYNAMIC_CLASS(wxPopupWindow, wxWindow) -IMPLEMENT_DYNAMIC_CLASS(wxPopupTransientWindow, wxPopupWindow) - -#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__) - IMPLEMENT_DYNAMIC_CLASS(wxPopupComboWindow, wxPopupTransientWindow) -#endif - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -// event handlers which we use to intercept events which cause the popup to -// disappear -class wxPopupWindowHandler : public wxEvtHandler -{ -public: - wxPopupWindowHandler(wxPopupTransientWindow *popup) : m_popup(popup) {} - -protected: - // event handlers - void OnLeftDown(wxMouseEvent& event); - -private: - wxPopupTransientWindow *m_popup; - - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxPopupWindowHandler) -}; - -class wxPopupFocusHandler : public wxEvtHandler -{ -public: - wxPopupFocusHandler(wxPopupTransientWindow *popup) : m_popup(popup) {} - -protected: - void OnKillFocus(wxFocusEvent& event); - void OnKeyDown(wxKeyEvent& event); - -private: - wxPopupTransientWindow *m_popup; - - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxPopupFocusHandler) -}; - -// ---------------------------------------------------------------------------- -// event tables -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxPopupWindowHandler, wxEvtHandler) - EVT_LEFT_DOWN(wxPopupWindowHandler::OnLeftDown) -END_EVENT_TABLE() - -BEGIN_EVENT_TABLE(wxPopupFocusHandler, wxEvtHandler) - EVT_KILL_FOCUS(wxPopupFocusHandler::OnKillFocus) - EVT_KEY_DOWN(wxPopupFocusHandler::OnKeyDown) -END_EVENT_TABLE() - -BEGIN_EVENT_TABLE(wxPopupTransientWindow, wxPopupWindow) -#if defined( __WXMSW__ ) || defined( __WXMAC__ ) - EVT_IDLE(wxPopupTransientWindow::OnIdle) -#endif -END_EVENT_TABLE() - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxPopupWindowBase -// ---------------------------------------------------------------------------- - -wxPopupWindowBase::~wxPopupWindowBase() -{ - // this destructor is required for Darwin -} - -bool wxPopupWindowBase::Create(wxWindow* WXUNUSED(parent), int WXUNUSED(flags)) -{ - return true; -} - -void wxPopupWindowBase::Position(const wxPoint& ptOrigin, - const wxSize& size) -{ - // determine the position and size of the screen we clamp the popup to - wxPoint posScreen; - wxSize sizeScreen; - - const int displayNum = wxDisplay::GetFromPoint(ptOrigin); - if ( displayNum != wxNOT_FOUND ) - { - const wxRect rectScreen = wxDisplay(displayNum).GetGeometry(); - posScreen = rectScreen.GetPosition(); - sizeScreen = rectScreen.GetSize(); - } - else // outside of any display? - { - // just use the primary one then - posScreen = wxPoint(0, 0); - sizeScreen = wxGetDisplaySize(); - } - - - const wxSize sizeSelf = GetSize(); - - // is there enough space to put the popup below the window (where we put it - // by default)? - wxCoord y = ptOrigin.y + size.y; - if ( y + sizeSelf.y > posScreen.y + sizeScreen.y ) - { - // check if there is enough space above - if ( ptOrigin.y > sizeSelf.y ) - { - // do position the control above the window - y -= size.y + sizeSelf.y; - } - //else: not enough space below nor above, leave below - } - - // now check left/right too - wxCoord x = ptOrigin.x; - - if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ) - { - // shift the window to the left instead of the right. - x -= size.x; - x -= sizeSelf.x; // also shift it by window width. - } - else - x += size.x; - - - if ( x + sizeSelf.x > posScreen.x + sizeScreen.x ) - { - // check if there is enough space to the left - if ( ptOrigin.x > sizeSelf.x ) - { - // do position the control to the left - x -= size.x + sizeSelf.x; - } - //else: not enough space there neither, leave in default position - } - - Move(x, y, wxSIZE_NO_ADJUSTMENTS); -} - -// ---------------------------------------------------------------------------- -// wxPopupTransientWindow -// ---------------------------------------------------------------------------- - -void wxPopupTransientWindow::Init() -{ - m_child = - m_focus = (wxWindow *)NULL; - - m_handlerFocus = NULL; - m_handlerPopup = NULL; -} - -wxPopupTransientWindow::wxPopupTransientWindow(wxWindow *parent, int style) -{ - Init(); - - (void)Create(parent, style); -} - -wxPopupTransientWindow::~wxPopupTransientWindow() -{ - if (m_handlerPopup && m_handlerPopup->GetNextHandler()) - PopHandlers(); - - wxASSERT(!m_handlerFocus || !m_handlerFocus->GetNextHandler()); - wxASSERT(!m_handlerPopup || !m_handlerPopup->GetNextHandler()); - - delete m_handlerFocus; - delete m_handlerPopup; -} - -void wxPopupTransientWindow::PopHandlers() -{ - if ( m_child ) - { - if ( !m_child->RemoveEventHandler(m_handlerPopup) ) - { - // something is very wrong and someone else probably deleted our - // handler - so don't risk deleting it second time - m_handlerPopup = NULL; - } - if (m_child->HasCapture()) - { - m_child->ReleaseMouse(); - } - m_child = NULL; - } - - if ( m_focus ) - { - if ( !m_focus->RemoveEventHandler(m_handlerFocus) ) - { - // see above - m_handlerFocus = NULL; - } - } - m_focus = NULL; -} - -void wxPopupTransientWindow::Popup(wxWindow *winFocus) -{ - const wxWindowList& children = GetChildren(); - if ( children.GetCount() ) - { - m_child = children.GetFirst()->GetData(); - } - else - { - m_child = this; - } - - Show(); - - // There is is a problem if these are still in use - wxASSERT(!m_handlerFocus || !m_handlerFocus->GetNextHandler()); - wxASSERT(!m_handlerPopup || !m_handlerPopup->GetNextHandler()); - - if (!m_handlerPopup) - m_handlerPopup = new wxPopupWindowHandler(this); - - m_child->PushEventHandler(m_handlerPopup); - -#if defined(__WXMSW__) - // Focusing on child of popup window does not work on MSW unless WS_POPUP - // style is set. We do not even want to try to set the focus, as it may - // provoke errors on some Windows versions (Vista and later). - if ( ::GetWindowLong(GetHwnd(), GWL_STYLE) & WS_POPUP ) -#endif - { - m_focus = winFocus ? winFocus : this; - m_focus->SetFocus(); - } - -#if defined( __WXMSW__ ) || defined( __WXMAC__ ) - // MSW doesn't allow to set focus to the popup window, but we need to - // subclass the window which has the focus, and not winFocus passed in or - // otherwise everything else breaks down - m_focus = FindFocus(); -#elif defined(__WXGTK__) - // GTK+ catches the activate events from the popup - // window, not the focus events from the child window - m_focus = this; -#endif - - if ( m_focus ) - { - if (!m_handlerFocus) - m_handlerFocus = new wxPopupFocusHandler(this); - - m_focus->PushEventHandler(m_handlerFocus); - } -} - -bool wxPopupTransientWindow::Show( bool show ) -{ -#ifdef __WXGTK__ - if (!show) - { - gdk_pointer_ungrab( (guint32)GDK_CURRENT_TIME ); - - gtk_grab_remove( m_widget ); - } -#endif - -#ifdef __WXX11__ - if (!show) - { - XUngrabPointer( wxGlobalDisplay(), CurrentTime ); - } -#endif - -#if defined( __WXMSW__ ) || defined( __WMAC__ ) - if (!show && m_child && m_child->HasCapture()) - { - m_child->ReleaseMouse(); - } -#endif - - bool ret = wxPopupWindow::Show( show ); - -#ifdef __WXGTK__ - if (show) - { - gtk_grab_add( m_widget ); - - gdk_pointer_grab( m_widget->window, TRUE, - (GdkEventMask) - (GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | - GDK_POINTER_MOTION_HINT_MASK | - GDK_POINTER_MOTION_MASK), - (GdkWindow *) NULL, - (GdkCursor *) NULL, - (guint32)GDK_CURRENT_TIME ); - } -#endif - -#ifdef __WXX11__ - if (show) - { - Window xwindow = (Window) m_clientWindow; - - /* int res =*/ XGrabPointer(wxGlobalDisplay(), xwindow, - True, - ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask, - GrabModeAsync, - GrabModeAsync, - None, - None, - CurrentTime ); - } -#endif - -#if defined( __WXMSW__ ) || defined( __WMAC__ ) - if (show && m_child) - { - // Assume that the mouse is outside the popup to begin with - m_child->CaptureMouse(); - } -#endif - - return ret; -} - -void wxPopupTransientWindow::Dismiss() -{ - Hide(); - PopHandlers(); -} - -void wxPopupTransientWindow::DismissAndNotify() -{ - Dismiss(); - OnDismiss(); -} - -void wxPopupTransientWindow::OnDismiss() -{ - // nothing to do here - but it may be interesting for derived class -} - -bool wxPopupTransientWindow::ProcessLeftDown(wxMouseEvent& WXUNUSED(event)) -{ - // no special processing here - return false; -} - -#if defined( __WXMSW__ ) || defined( __WXMAC__ ) -void wxPopupTransientWindow::OnIdle(wxIdleEvent& event) -{ - event.Skip(); - - if (IsShown() && m_child) - { - wxPoint pos = ScreenToClient(wxGetMousePosition()); - wxRect rect(GetSize()); - - if ( rect.Contains(pos) ) - { - if ( m_child->HasCapture() ) - { - m_child->ReleaseMouse(); - } - } - else - { - if ( !m_child->HasCapture() ) - { - m_child->CaptureMouse(); - } - } - } -} -#endif // __WXMSW__ - - -#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__) - -// ---------------------------------------------------------------------------- -// wxPopupComboWindow -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxPopupComboWindow, wxPopupTransientWindow) - EVT_KEY_DOWN(wxPopupComboWindow::OnKeyDown) -END_EVENT_TABLE() - -wxPopupComboWindow::wxPopupComboWindow(wxComboCtrl *parent) - : wxPopupTransientWindow(parent) -{ - m_combo = parent; -} - -bool wxPopupComboWindow::Create(wxComboCtrl *parent) -{ - m_combo = parent; - - return wxPopupWindow::Create(parent); -} - -void wxPopupComboWindow::PositionNearCombo() -{ - // the origin point must be in screen coords - wxPoint ptOrigin = m_combo->ClientToScreen(wxPoint(0,0)); - -#if 0 //def __WXUNIVERSAL__ - // account for the fact that (0, 0) is not the top left corner of the - // window: there is also the border - wxRect rectBorders = m_combo->GetRenderer()-> - GetBorderDimensions(m_combo->GetBorder()); - ptOrigin.x -= rectBorders.x; - ptOrigin.y -= rectBorders.y; -#endif // __WXUNIVERSAL__ - - // position below or above the combobox: the width is 0 to put it exactly - // below us, not to the left or to the right - Position(ptOrigin, wxSize(0, m_combo->GetSize().y)); -} - -void wxPopupComboWindow::OnDismiss() -{ - m_combo->OnPopupDismiss(); -} - -void wxPopupComboWindow::OnKeyDown(wxKeyEvent& event) -{ - m_combo->ProcessEvent(event); -} - -#endif // wxUSE_COMBOBOX && defined(__WXUNIVERSAL__) - -// ---------------------------------------------------------------------------- -// wxPopupWindowHandler -// ---------------------------------------------------------------------------- - -void wxPopupWindowHandler::OnLeftDown(wxMouseEvent& event) -{ - // let the window have it first (we're the first event handler in the chain - // of handlers for this window) - if ( m_popup->ProcessLeftDown(event) ) - { - return; - } - - wxPoint pos = event.GetPosition(); - - // in non-Univ ports the system manages scrollbars for us -#if defined(__WXUNIVERSAL__) && wxUSE_SCROLLBAR - // scrollbar on which the click occurred - wxWindow *sbar = NULL; -#endif // __WXUNIVERSAL__ && wxUSE_SCROLLBAR - - wxWindow *win = (wxWindow *)event.GetEventObject(); - - switch ( win->HitTest(pos.x, pos.y) ) - { - case wxHT_WINDOW_OUTSIDE: - { - // do the coords translation now as after DismissAndNotify() - // m_popup may be destroyed - wxMouseEvent event2(event); - - m_popup->ClientToScreen(&event2.m_x, &event2.m_y); - - // clicking outside a popup dismisses it - m_popup->DismissAndNotify(); - - // dismissing a tooltip shouldn't waste a click, i.e. you - // should be able to dismiss it and press the button with the - // same click, so repost this event to the window beneath us - wxWindow *winUnder = wxFindWindowAtPoint(event2.GetPosition()); - if ( winUnder ) - { - // translate the event coords to the ones of the window - // which is going to get the event - winUnder->ScreenToClient(&event2.m_x, &event2.m_y); - - event2.SetEventObject(winUnder); - wxPostEvent(winUnder, event2); - } - } - break; - -#if defined(__WXUNIVERSAL__) && wxUSE_SCROLLBAR - case wxHT_WINDOW_HORZ_SCROLLBAR: - sbar = win->GetScrollbar(wxHORIZONTAL); - break; - - case wxHT_WINDOW_VERT_SCROLLBAR: - sbar = win->GetScrollbar(wxVERTICAL); - break; -#endif // __WXUNIVERSAL__ && wxUSE_SCROLLBAR - - default: - // forgot to update the switch after adding a new hit test code? - wxFAIL_MSG( _T("unexpected HitTest() return value") ); - // fall through - - case wxHT_WINDOW_CORNER: - // don't actually know if this one is good for anything, but let it - // pass just in case - - case wxHT_WINDOW_INSIDE: - // let the normal processing take place - event.Skip(); - break; - } - -#if defined(__WXUNIVERSAL__) && wxUSE_SCROLLBAR - if ( sbar ) - { - // translate the event coordinates to the scrollbar ones - pos = sbar->ScreenToClient(win->ClientToScreen(pos)); - - // and give the event to it - wxMouseEvent event2 = event; - event2.m_x = pos.x; - event2.m_y = pos.y; - - (void)sbar->GetEventHandler()->ProcessEvent(event2); - } -#endif // __WXUNIVERSAL__ && wxUSE_SCROLLBAR -} - -// ---------------------------------------------------------------------------- -// wxPopupFocusHandler -// ---------------------------------------------------------------------------- - -void wxPopupFocusHandler::OnKillFocus(wxFocusEvent& event) -{ - // when we lose focus we always disappear - unless it goes to the popup (in - // which case we don't really lose it) - wxWindow *win = event.GetWindow(); - while ( win ) - { - if ( win == m_popup ) - return; - win = win->GetParent(); - } - - m_popup->DismissAndNotify(); -} - -void wxPopupFocusHandler::OnKeyDown(wxKeyEvent& event) -{ - // we can be associated with the popup itself in which case we should avoid - // infinite recursion - static int s_inside; - wxRecursionGuard guard(s_inside); - if ( guard.IsInside() ) - { - event.Skip(); - return; - } - - // let the window have it first, it might process the keys - if ( !m_popup->GetEventHandler()->ProcessEvent(event) ) - { - // by default, dismiss the popup - m_popup->DismissAndNotify(); - } -} - -#endif // wxUSE_POPUPWIN +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/popupcmn.cpp +// Purpose: implementation of wxPopupTransientWindow +// Author: Vadim Zeitlin +// Modified by: +// Created: 06.01.01 +// RCS-ID: $Id: popupcmn.cpp 61466 2009-07-19 16:45:08Z VZ $ +// Copyright: (c) 2001 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_POPUPWIN + +#include "wx/popupwin.h" + +#ifndef WX_PRECOMP + #include "wx/combobox.h" // wxComboCtrl + #include "wx/app.h" // wxPostEvent + #include "wx/log.h" +#endif //WX_PRECOMP + +#include "wx/display.h" +#include "wx/recguard.h" + +#ifdef __WXUNIVERSAL__ + #include "wx/univ/renderer.h" + #include "wx/scrolbar.h" +#endif // __WXUNIVERSAL__ + +#ifdef __WXGTK__ + #include +#elif defined(__WXMSW__) + #include "wx/msw/private.h" +#elif defined(__WXX11__) + #include "wx/x11/private.h" +#endif + +IMPLEMENT_DYNAMIC_CLASS(wxPopupWindow, wxWindow) +IMPLEMENT_DYNAMIC_CLASS(wxPopupTransientWindow, wxPopupWindow) + +#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__) + IMPLEMENT_DYNAMIC_CLASS(wxPopupComboWindow, wxPopupTransientWindow) +#endif + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// event handlers which we use to intercept events which cause the popup to +// disappear +class wxPopupWindowHandler : public wxEvtHandler +{ +public: + wxPopupWindowHandler(wxPopupTransientWindow *popup) : m_popup(popup) {} + +protected: + // event handlers + void OnLeftDown(wxMouseEvent& event); + +private: + wxPopupTransientWindow *m_popup; + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxPopupWindowHandler) +}; + +class wxPopupFocusHandler : public wxEvtHandler +{ +public: + wxPopupFocusHandler(wxPopupTransientWindow *popup) : m_popup(popup) {} + +protected: + void OnKillFocus(wxFocusEvent& event); + void OnKeyDown(wxKeyEvent& event); + +private: + wxPopupTransientWindow *m_popup; + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxPopupFocusHandler) +}; + +// ---------------------------------------------------------------------------- +// event tables +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxPopupWindowHandler, wxEvtHandler) + EVT_LEFT_DOWN(wxPopupWindowHandler::OnLeftDown) +END_EVENT_TABLE() + +BEGIN_EVENT_TABLE(wxPopupFocusHandler, wxEvtHandler) + EVT_KILL_FOCUS(wxPopupFocusHandler::OnKillFocus) + EVT_KEY_DOWN(wxPopupFocusHandler::OnKeyDown) +END_EVENT_TABLE() + +BEGIN_EVENT_TABLE(wxPopupTransientWindow, wxPopupWindow) +#if defined( __WXMSW__ ) || defined( __WXMAC__ ) + EVT_IDLE(wxPopupTransientWindow::OnIdle) +#endif +END_EVENT_TABLE() + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxPopupWindowBase +// ---------------------------------------------------------------------------- + +wxPopupWindowBase::~wxPopupWindowBase() +{ + // this destructor is required for Darwin +} + +bool wxPopupWindowBase::Create(wxWindow* WXUNUSED(parent), int WXUNUSED(flags)) +{ + return true; +} + +void wxPopupWindowBase::Position(const wxPoint& ptOrigin, + const wxSize& size) +{ + // determine the position and size of the screen we clamp the popup to + wxPoint posScreen; + wxSize sizeScreen; + + const int displayNum = wxDisplay::GetFromPoint(ptOrigin); + if ( displayNum != wxNOT_FOUND ) + { + const wxRect rectScreen = wxDisplay(displayNum).GetGeometry(); + posScreen = rectScreen.GetPosition(); + sizeScreen = rectScreen.GetSize(); + } + else // outside of any display? + { + // just use the primary one then + posScreen = wxPoint(0, 0); + sizeScreen = wxGetDisplaySize(); + } + + + const wxSize sizeSelf = GetSize(); + + // is there enough space to put the popup below the window (where we put it + // by default)? + wxCoord y = ptOrigin.y + size.y; + if ( y + sizeSelf.y > posScreen.y + sizeScreen.y ) + { + // check if there is enough space above + if ( ptOrigin.y > sizeSelf.y ) + { + // do position the control above the window + y -= size.y + sizeSelf.y; + } + //else: not enough space below nor above, leave below + } + + // now check left/right too + wxCoord x = ptOrigin.x; + + if ( wxTheApp->GetLayoutDirection() == wxLayout_RightToLeft ) + { + // shift the window to the left instead of the right. + x -= size.x; + x -= sizeSelf.x; // also shift it by window width. + } + else + x += size.x; + + + if ( x + sizeSelf.x > posScreen.x + sizeScreen.x ) + { + // check if there is enough space to the left + if ( ptOrigin.x > sizeSelf.x ) + { + // do position the control to the left + x -= size.x + sizeSelf.x; + } + //else: not enough space there neither, leave in default position + } + + Move(x, y, wxSIZE_NO_ADJUSTMENTS); +} + +// ---------------------------------------------------------------------------- +// wxPopupTransientWindow +// ---------------------------------------------------------------------------- + +void wxPopupTransientWindow::Init() +{ + m_child = + m_focus = (wxWindow *)NULL; + + m_handlerFocus = NULL; + m_handlerPopup = NULL; +} + +wxPopupTransientWindow::wxPopupTransientWindow(wxWindow *parent, int style) +{ + Init(); + + (void)Create(parent, style); +} + +wxPopupTransientWindow::~wxPopupTransientWindow() +{ + if (m_handlerPopup && m_handlerPopup->GetNextHandler()) + PopHandlers(); + + wxASSERT(!m_handlerFocus || !m_handlerFocus->GetNextHandler()); + wxASSERT(!m_handlerPopup || !m_handlerPopup->GetNextHandler()); + + delete m_handlerFocus; + delete m_handlerPopup; +} + +void wxPopupTransientWindow::PopHandlers() +{ + if ( m_child ) + { + if ( !m_child->RemoveEventHandler(m_handlerPopup) ) + { + // something is very wrong and someone else probably deleted our + // handler - so don't risk deleting it second time + m_handlerPopup = NULL; + } + if (m_child->HasCapture()) + { + m_child->ReleaseMouse(); + } + m_child = NULL; + } + + if ( m_focus ) + { + if ( !m_focus->RemoveEventHandler(m_handlerFocus) ) + { + // see above + m_handlerFocus = NULL; + } + } + m_focus = NULL; +} + +void wxPopupTransientWindow::Popup(wxWindow *winFocus) +{ + const wxWindowList& children = GetChildren(); + if ( children.GetCount() ) + { + m_child = children.GetFirst()->GetData(); + } + else + { + m_child = this; + } + + Show(); + + // There is is a problem if these are still in use + wxASSERT(!m_handlerFocus || !m_handlerFocus->GetNextHandler()); + wxASSERT(!m_handlerPopup || !m_handlerPopup->GetNextHandler()); + + if (!m_handlerPopup) + m_handlerPopup = new wxPopupWindowHandler(this); + + m_child->PushEventHandler(m_handlerPopup); + +#if defined(__WXMSW__) + // Focusing on child of popup window does not work on MSW unless WS_POPUP + // style is set. We do not even want to try to set the focus, as it may + // provoke errors on some Windows versions (Vista and later). + if ( ::GetWindowLong(GetHwnd(), GWL_STYLE) & WS_POPUP ) +#endif + { + m_focus = winFocus ? winFocus : this; + m_focus->SetFocus(); + } + +#if defined( __WXMSW__ ) || defined( __WXMAC__ ) + // MSW doesn't allow to set focus to the popup window, but we need to + // subclass the window which has the focus, and not winFocus passed in or + // otherwise everything else breaks down + m_focus = FindFocus(); +#elif defined(__WXGTK__) + // GTK+ catches the activate events from the popup + // window, not the focus events from the child window + m_focus = this; +#endif + + if ( m_focus ) + { + if (!m_handlerFocus) + m_handlerFocus = new wxPopupFocusHandler(this); + + m_focus->PushEventHandler(m_handlerFocus); + } +} + +bool wxPopupTransientWindow::Show( bool show ) +{ +#ifdef __WXGTK__ + if (!show) + { + gdk_pointer_ungrab( (guint32)GDK_CURRENT_TIME ); + + gtk_grab_remove( m_widget ); + } +#endif + +#ifdef __WXX11__ + if (!show) + { + XUngrabPointer( wxGlobalDisplay(), CurrentTime ); + } +#endif + +#if defined( __WXMSW__ ) || defined( __WMAC__ ) + if (!show && m_child && m_child->HasCapture()) + { + m_child->ReleaseMouse(); + } +#endif + + bool ret = wxPopupWindow::Show( show ); + +#ifdef __WXGTK__ + if (show) + { + gtk_grab_add( m_widget ); + + gdk_pointer_grab( m_widget->window, TRUE, + (GdkEventMask) + (GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_POINTER_MOTION_HINT_MASK | + GDK_POINTER_MOTION_MASK), + (GdkWindow *) NULL, + (GdkCursor *) NULL, + (guint32)GDK_CURRENT_TIME ); + } +#endif + +#ifdef __WXX11__ + if (show) + { + Window xwindow = (Window) m_clientWindow; + + /* int res =*/ XGrabPointer(wxGlobalDisplay(), xwindow, + True, + ButtonPressMask | ButtonReleaseMask | ButtonMotionMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask, + GrabModeAsync, + GrabModeAsync, + None, + None, + CurrentTime ); + } +#endif + +#if defined( __WXMSW__ ) || defined( __WMAC__ ) + if (show && m_child) + { + // Assume that the mouse is outside the popup to begin with + m_child->CaptureMouse(); + } +#endif + + return ret; +} + +void wxPopupTransientWindow::Dismiss() +{ + Hide(); + PopHandlers(); +} + +void wxPopupTransientWindow::DismissAndNotify() +{ + Dismiss(); + OnDismiss(); +} + +void wxPopupTransientWindow::OnDismiss() +{ + // nothing to do here - but it may be interesting for derived class +} + +bool wxPopupTransientWindow::ProcessLeftDown(wxMouseEvent& WXUNUSED(event)) +{ + // no special processing here + return false; +} + +#if defined( __WXMSW__ ) || defined( __WXMAC__ ) +void wxPopupTransientWindow::OnIdle(wxIdleEvent& event) +{ + event.Skip(); + + if (IsShown() && m_child) + { + wxPoint pos = ScreenToClient(wxGetMousePosition()); + wxRect rect(GetSize()); + + if ( rect.Contains(pos) ) + { + if ( m_child->HasCapture() ) + { + m_child->ReleaseMouse(); + } + } + else + { + if ( !m_child->HasCapture() ) + { + m_child->CaptureMouse(); + } + } + } +} +#endif // __WXMSW__ + + +#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__) + +// ---------------------------------------------------------------------------- +// wxPopupComboWindow +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxPopupComboWindow, wxPopupTransientWindow) + EVT_KEY_DOWN(wxPopupComboWindow::OnKeyDown) +END_EVENT_TABLE() + +wxPopupComboWindow::wxPopupComboWindow(wxComboCtrl *parent) + : wxPopupTransientWindow(parent) +{ + m_combo = parent; +} + +bool wxPopupComboWindow::Create(wxComboCtrl *parent) +{ + m_combo = parent; + + return wxPopupWindow::Create(parent); +} + +void wxPopupComboWindow::PositionNearCombo() +{ + // the origin point must be in screen coords + wxPoint ptOrigin = m_combo->ClientToScreen(wxPoint(0,0)); + +#if 0 //def __WXUNIVERSAL__ + // account for the fact that (0, 0) is not the top left corner of the + // window: there is also the border + wxRect rectBorders = m_combo->GetRenderer()-> + GetBorderDimensions(m_combo->GetBorder()); + ptOrigin.x -= rectBorders.x; + ptOrigin.y -= rectBorders.y; +#endif // __WXUNIVERSAL__ + + // position below or above the combobox: the width is 0 to put it exactly + // below us, not to the left or to the right + Position(ptOrigin, wxSize(0, m_combo->GetSize().y)); +} + +void wxPopupComboWindow::OnDismiss() +{ + m_combo->OnPopupDismiss(); +} + +void wxPopupComboWindow::OnKeyDown(wxKeyEvent& event) +{ + m_combo->ProcessEvent(event); +} + +#endif // wxUSE_COMBOBOX && defined(__WXUNIVERSAL__) + +// ---------------------------------------------------------------------------- +// wxPopupWindowHandler +// ---------------------------------------------------------------------------- + +void wxPopupWindowHandler::OnLeftDown(wxMouseEvent& event) +{ + // let the window have it first (we're the first event handler in the chain + // of handlers for this window) + if ( m_popup->ProcessLeftDown(event) ) + { + return; + } + + wxPoint pos = event.GetPosition(); + + // in non-Univ ports the system manages scrollbars for us +#if defined(__WXUNIVERSAL__) && wxUSE_SCROLLBAR + // scrollbar on which the click occurred + wxWindow *sbar = NULL; +#endif // __WXUNIVERSAL__ && wxUSE_SCROLLBAR + + wxWindow *win = (wxWindow *)event.GetEventObject(); + + switch ( win->HitTest(pos.x, pos.y) ) + { + case wxHT_WINDOW_OUTSIDE: + { + // do the coords translation now as after DismissAndNotify() + // m_popup may be destroyed + wxMouseEvent event2(event); + + m_popup->ClientToScreen(&event2.m_x, &event2.m_y); + + // clicking outside a popup dismisses it + m_popup->DismissAndNotify(); + + // dismissing a tooltip shouldn't waste a click, i.e. you + // should be able to dismiss it and press the button with the + // same click, so repost this event to the window beneath us + wxWindow *winUnder = wxFindWindowAtPoint(event2.GetPosition()); + if ( winUnder ) + { + // translate the event coords to the ones of the window + // which is going to get the event + winUnder->ScreenToClient(&event2.m_x, &event2.m_y); + + event2.SetEventObject(winUnder); + wxPostEvent(winUnder, event2); + } + } + break; + +#if defined(__WXUNIVERSAL__) && wxUSE_SCROLLBAR + case wxHT_WINDOW_HORZ_SCROLLBAR: + sbar = win->GetScrollbar(wxHORIZONTAL); + break; + + case wxHT_WINDOW_VERT_SCROLLBAR: + sbar = win->GetScrollbar(wxVERTICAL); + break; +#endif // __WXUNIVERSAL__ && wxUSE_SCROLLBAR + + default: + // forgot to update the switch after adding a new hit test code? + wxFAIL_MSG( _T("unexpected HitTest() return value") ); + // fall through + + case wxHT_WINDOW_CORNER: + // don't actually know if this one is good for anything, but let it + // pass just in case + + case wxHT_WINDOW_INSIDE: + // let the normal processing take place + event.Skip(); + break; + } + +#if defined(__WXUNIVERSAL__) && wxUSE_SCROLLBAR + if ( sbar ) + { + // translate the event coordinates to the scrollbar ones + pos = sbar->ScreenToClient(win->ClientToScreen(pos)); + + // and give the event to it + wxMouseEvent event2 = event; + event2.m_x = pos.x; + event2.m_y = pos.y; + + (void)sbar->GetEventHandler()->ProcessEvent(event2); + } +#endif // __WXUNIVERSAL__ && wxUSE_SCROLLBAR +} + +// ---------------------------------------------------------------------------- +// wxPopupFocusHandler +// ---------------------------------------------------------------------------- + +void wxPopupFocusHandler::OnKillFocus(wxFocusEvent& event) +{ + // when we lose focus we always disappear - unless it goes to the popup (in + // which case we don't really lose it) + wxWindow *win = event.GetWindow(); + while ( win ) + { + if ( win == m_popup ) + return; + win = win->GetParent(); + } + + m_popup->DismissAndNotify(); +} + +void wxPopupFocusHandler::OnKeyDown(wxKeyEvent& event) +{ + // we can be associated with the popup itself in which case we should avoid + // infinite recursion + static int s_inside; + wxRecursionGuard guard(s_inside); + if ( guard.IsInside() ) + { + event.Skip(); + return; + } + + // let the window have it first, it might process the keys + if ( !m_popup->GetEventHandler()->ProcessEvent(event) ) + { + // by default, dismiss the popup + m_popup->DismissAndNotify(); + } +} + +#endif // wxUSE_POPUPWIN diff --git a/Source/3rd Party/wx/src/common/powercmn.cpp b/Source/3rd Party/wx/src/common/powercmn.cpp index 82f28c416..cf2086ff8 100644 --- a/Source/3rd Party/wx/src/common/powercmn.cpp +++ b/Source/3rd Party/wx/src/common/powercmn.cpp @@ -1,59 +1,59 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/powercmn.cpp -// Purpose: power event types and stubs for power functions -// Author: Vadim Zeitlin -// Modified by: -// Created: 2006-05-27 -// RCS-ID: $Id: powercmn.cpp 48811 2007-09-19 23:11:28Z RD $ -// Copyright: (c) 2006 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP -#endif //WX_PRECOMP - -#include "wx/power.h" - -// ============================================================================ -// implementation -// ============================================================================ - -#ifdef wxHAS_POWER_EVENTS - DEFINE_EVENT_TYPE(wxEVT_POWER_SUSPENDING) - DEFINE_EVENT_TYPE(wxEVT_POWER_SUSPENDED) - DEFINE_EVENT_TYPE(wxEVT_POWER_SUSPEND_CANCEL) - DEFINE_EVENT_TYPE(wxEVT_POWER_RESUME) - - IMPLEMENT_ABSTRACT_CLASS(wxPowerEvent, wxEvent) -#endif - -// provide stubs for the systems not implementing these functions -#if !defined(__WXPALMOS__) && !defined(__WXMSW__) - -wxPowerType wxGetPowerType() -{ - return wxPOWER_UNKNOWN; -} - -wxBatteryState wxGetBatteryState() -{ - return wxBATTERY_UNKNOWN_STATE; -} - -#endif // systems without power management functions - +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/powercmn.cpp +// Purpose: power event types and stubs for power functions +// Author: Vadim Zeitlin +// Modified by: +// Created: 2006-05-27 +// RCS-ID: $Id: powercmn.cpp 48811 2007-09-19 23:11:28Z RD $ +// Copyright: (c) 2006 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP +#endif //WX_PRECOMP + +#include "wx/power.h" + +// ============================================================================ +// implementation +// ============================================================================ + +#ifdef wxHAS_POWER_EVENTS + DEFINE_EVENT_TYPE(wxEVT_POWER_SUSPENDING) + DEFINE_EVENT_TYPE(wxEVT_POWER_SUSPENDED) + DEFINE_EVENT_TYPE(wxEVT_POWER_SUSPEND_CANCEL) + DEFINE_EVENT_TYPE(wxEVT_POWER_RESUME) + + IMPLEMENT_ABSTRACT_CLASS(wxPowerEvent, wxEvent) +#endif + +// provide stubs for the systems not implementing these functions +#if !defined(__WXPALMOS__) && !defined(__WXMSW__) + +wxPowerType wxGetPowerType() +{ + return wxPOWER_UNKNOWN; +} + +wxBatteryState wxGetBatteryState() +{ + return wxBATTERY_UNKNOWN_STATE; +} + +#endif // systems without power management functions + diff --git a/Source/3rd Party/wx/src/common/prntbase.cpp b/Source/3rd Party/wx/src/common/prntbase.cpp index 9b6399671..b45b319b8 100644 --- a/Source/3rd Party/wx/src/common/prntbase.cpp +++ b/Source/3rd Party/wx/src/common/prntbase.cpp @@ -1,1869 +1,1869 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/prntbase.cpp -// Purpose: Printing framework base class implementation -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: prntbase.cpp 60850 2009-06-01 10:16:13Z JS $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_PRINTING_ARCHITECTURE - -// change this to 1 to use experimental high-quality printing on Windows -// (NB: this can't be in msw/printwin.cpp because of binary compatibility) -#define wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW 0 - -#if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW - #if !defined(__WXMSW__) || !wxUSE_IMAGE || !wxUSE_WXDIB - #undef wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW - #define wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW 0 - #endif -#endif - -#if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW -#include "wx/msw/enhmeta.h" -#endif - -#if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW && !wxUSE_ENH_METAFILE_FROM_DC -#error Please set wxUSE_ENH_METAFILE_FROM_DC to 1 in include/wx/msw/enhmeta.h. -#endif - -#include "wx/dcprint.h" - -#ifndef WX_PRECOMP - #if defined(__WXMSW__) - #include "wx/msw/wrapcdlg.h" - #endif // MSW - #include "wx/utils.h" - #include "wx/dc.h" - #include "wx/app.h" - #include "wx/math.h" - #include "wx/msgdlg.h" - #include "wx/layout.h" - #include "wx/choice.h" - #include "wx/button.h" - #include "wx/settings.h" - #include "wx/dcmemory.h" - #include "wx/stattext.h" - #include "wx/intl.h" - #include "wx/textdlg.h" - #include "wx/sizer.h" - #include "wx/module.h" -#endif // !WX_PRECOMP - -#include "wx/prntbase.h" -#include "wx/printdlg.h" -#include "wx/print.h" -#include "wx/dcprint.h" - -#include -#include - -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) -#include "wx/msw/printdlg.h" -#elif defined(__WXMAC__) -#include "wx/mac/printdlg.h" -#include "wx/mac/private/print.h" -#else -#include "wx/generic/prntdlgg.h" -#include "wx/dcps.h" -#endif - -#ifdef __WXMSW__ - #ifndef __WIN32__ - #include - #endif -#endif // __WXMSW__ - -#if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW - -#include "wx/msw/dib.h" -#include "wx/image.h" - -typedef bool (wxPrintPreviewBase::*RenderPageIntoDCFunc)(wxDC&, int); -static bool RenderPageIntoBitmapHQ(wxPrintPreviewBase *preview, - RenderPageIntoDCFunc RenderPageIntoDC, - wxBitmap& bmp, int pageNum); -#endif // wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW - -//---------------------------------------------------------------------------- -// wxPrintFactory -//---------------------------------------------------------------------------- - -wxPrintFactory *wxPrintFactory::m_factory = NULL; - -void wxPrintFactory::SetPrintFactory( wxPrintFactory *factory ) -{ - if (wxPrintFactory::m_factory) - delete wxPrintFactory::m_factory; - - wxPrintFactory::m_factory = factory; -} - -wxPrintFactory *wxPrintFactory::GetFactory() -{ - if (!wxPrintFactory::m_factory) - wxPrintFactory::m_factory = new wxNativePrintFactory; - - return wxPrintFactory::m_factory; -} - -//---------------------------------------------------------------------------- -// wxNativePrintFactory -//---------------------------------------------------------------------------- - -wxPrinterBase *wxNativePrintFactory::CreatePrinter( wxPrintDialogData *data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxWindowsPrinter( data ); -#elif defined(__WXMAC__) - return new wxMacPrinter( data ); -#elif defined(__WXPM__) - return new wxOS2Printer( data ); -#else - return new wxPostScriptPrinter( data ); -#endif -} - -wxPrintPreviewBase *wxNativePrintFactory::CreatePrintPreview( wxPrintout *preview, - wxPrintout *printout, wxPrintDialogData *data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxWindowsPrintPreview( preview, printout, data ); -#elif defined(__WXMAC__) - return new wxMacPrintPreview( preview, printout, data ); -#elif defined(__WXPM__) - return new wxOS2PrintPreview( preview, printout, data ); -#else - return new wxPostScriptPrintPreview( preview, printout, data ); -#endif -} - -wxPrintPreviewBase *wxNativePrintFactory::CreatePrintPreview( wxPrintout *preview, - wxPrintout *printout, wxPrintData *data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxWindowsPrintPreview( preview, printout, data ); -#elif defined(__WXMAC__) - return new wxMacPrintPreview( preview, printout, data ); -#elif defined(__WXPM__) - return new wxOS2PrintPreview( preview, printout, data ); -#else - return new wxPostScriptPrintPreview( preview, printout, data ); -#endif -} - -wxPrintDialogBase *wxNativePrintFactory::CreatePrintDialog( wxWindow *parent, - wxPrintDialogData *data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxWindowsPrintDialog( parent, data ); -#elif defined(__WXMAC__) - return new wxMacPrintDialog( parent, data ); -#else - return new wxGenericPrintDialog( parent, data ); -#endif -} - -wxPrintDialogBase *wxNativePrintFactory::CreatePrintDialog( wxWindow *parent, - wxPrintData *data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxWindowsPrintDialog( parent, data ); -#elif defined(__WXMAC__) - return new wxMacPrintDialog( parent, data ); -#else - return new wxGenericPrintDialog( parent, data ); -#endif -} - -wxPageSetupDialogBase *wxNativePrintFactory::CreatePageSetupDialog( wxWindow *parent, - wxPageSetupDialogData *data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxWindowsPageSetupDialog( parent, data ); -#elif defined(__WXMAC__) - return new wxMacPageSetupDialog( parent, data ); -#else - return new wxGenericPageSetupDialog( parent, data ); -#endif -} - -bool wxNativePrintFactory::HasPrintSetupDialog() -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return false; -#elif defined(__WXMAC__) - return false; -#else - // Only here do we need to provide the print setup - // dialog ourselves, the other platforms either have - // none, don't make it accessible or let you configure - // the printer from the wxPrintDialog anyway. - return true; -#endif - -} - -wxDialog *wxNativePrintFactory::CreatePrintSetupDialog( wxWindow *parent, - wxPrintData *data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - wxUnusedVar(parent); - wxUnusedVar(data); - return NULL; -#elif defined(__WXMAC__) - wxUnusedVar(parent); - wxUnusedVar(data); - return NULL; -#else - // Only here do we need to provide the print setup - // dialog ourselves, the other platforms either have - // none, don't make it accessible or let you configure - // the printer from the wxPrintDialog anyway. - return new wxGenericPrintSetupDialog( parent, data ); -#endif -} - -wxDC* wxNativePrintFactory::CreatePrinterDC( const wxPrintData& data ) -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxPrinterDC(data); -#elif defined(__WXMAC__) - return new wxPrinterDC(data); -#else - return new wxPostScriptDC(data); -#endif -} - -bool wxNativePrintFactory::HasOwnPrintToFile() -{ - // Only relevant for PostScript and here the - // setup dialog provides no "print to file" - // option. In the GNOME setup dialog, the - // setup dialog has its own print to file. - return false; -} - -bool wxNativePrintFactory::HasPrinterLine() -{ - // Only relevant for PostScript for now - return true; -} - -wxString wxNativePrintFactory::CreatePrinterLine() -{ - // Only relevant for PostScript for now - - // We should query "lpstat -d" here - return _("Generic PostScript"); -} - -bool wxNativePrintFactory::HasStatusLine() -{ - // Only relevant for PostScript for now - return true; -} - -wxString wxNativePrintFactory::CreateStatusLine() -{ - // Only relevant for PostScript for now - - // We should query "lpstat -r" or "lpstat -p" here - return _("Ready"); -} - -wxPrintNativeDataBase *wxNativePrintFactory::CreatePrintNativeData() -{ -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - return new wxWindowsPrintNativeData; -#elif defined(__WXMAC__) - return new wxMacCarbonPrintData; -#else - return new wxPostScriptPrintNativeData; -#endif -} - -//---------------------------------------------------------------------------- -// wxPrintNativeDataBase -//---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxPrintNativeDataBase, wxObject) - -wxPrintNativeDataBase::wxPrintNativeDataBase() -{ - m_ref = 1; -} - -//---------------------------------------------------------------------------- -// wxPrintFactoryModule -//---------------------------------------------------------------------------- - -class wxPrintFactoryModule: public wxModule -{ -public: - wxPrintFactoryModule() {} - bool OnInit() { return true; } - void OnExit() { wxPrintFactory::SetPrintFactory( NULL ); } - -private: - DECLARE_DYNAMIC_CLASS(wxPrintFactoryModule) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxPrintFactoryModule, wxModule) - -//---------------------------------------------------------------------------- -// wxPrinterBase -//---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPrinterBase, wxObject) - -wxPrinterBase::wxPrinterBase(wxPrintDialogData *data) -{ - m_currentPrintout = (wxPrintout *) NULL; - sm_abortWindow = (wxWindow *) NULL; - sm_abortIt = false; - if (data) - m_printDialogData = (*data); - sm_lastError = wxPRINTER_NO_ERROR; -} - -wxWindow *wxPrinterBase::sm_abortWindow = (wxWindow *) NULL; -bool wxPrinterBase::sm_abortIt = false; -wxPrinterError wxPrinterBase::sm_lastError = wxPRINTER_NO_ERROR; - -wxPrinterBase::~wxPrinterBase() -{ -} - -wxWindow *wxPrinterBase::CreateAbortWindow(wxWindow *parent, wxPrintout * printout) -{ - wxPrintAbortDialog *dialog = new wxPrintAbortDialog(parent, _("Printing ") , wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE); - - wxBoxSizer *button_sizer = new wxBoxSizer( wxVERTICAL ); - button_sizer->Add( new wxStaticText(dialog, wxID_ANY, _("Please wait while printing\n") + printout->GetTitle() ), 0, wxALL, 10 ); - button_sizer->Add( new wxButton( dialog, wxID_CANCEL, wxT("Cancel") ), 0, wxALL | wxALIGN_CENTER, 10 ); - - dialog->SetAutoLayout( true ); - dialog->SetSizer( button_sizer ); - - button_sizer->Fit(dialog); - button_sizer->SetSizeHints (dialog) ; - - return dialog; -} - -void wxPrinterBase::ReportError(wxWindow *parent, wxPrintout *WXUNUSED(printout), const wxString& message) -{ - wxMessageBox(message, _("Printing Error"), wxOK, parent); -} - -wxPrintDialogData& wxPrinterBase::GetPrintDialogData() const -{ - return (wxPrintDialogData&) m_printDialogData; -} - -//---------------------------------------------------------------------------- -// wxPrinter -//---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPrinter, wxPrinterBase) - -wxPrinter::wxPrinter(wxPrintDialogData *data) -{ - m_pimpl = wxPrintFactory::GetFactory()->CreatePrinter( data ); -} - -wxPrinter::~wxPrinter() -{ - delete m_pimpl; -} - -wxWindow *wxPrinter::CreateAbortWindow(wxWindow *parent, wxPrintout *printout) -{ - return m_pimpl->CreateAbortWindow( parent, printout ); -} - -void wxPrinter::ReportError(wxWindow *parent, wxPrintout *printout, const wxString& message) -{ - m_pimpl->ReportError( parent, printout, message ); -} - -bool wxPrinter::Setup(wxWindow *parent) -{ - return m_pimpl->Setup( parent ); -} - -bool wxPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt) -{ - return m_pimpl->Print( parent, printout, prompt ); -} - -wxDC* wxPrinter::PrintDialog(wxWindow *parent) -{ - return m_pimpl->PrintDialog( parent ); -} - -wxPrintDialogData& wxPrinter::GetPrintDialogData() const -{ - return m_pimpl->GetPrintDialogData(); -} - -// --------------------------------------------------------------------------- -// wxPrintDialogBase: the dialog for printing. -// --------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxPrintDialogBase, wxDialog) - -wxPrintDialogBase::wxPrintDialogBase(wxWindow *parent, - wxWindowID id, - const wxString &title, - const wxPoint &pos, - const wxSize &size, - long style) - : wxDialog( parent, id, title.empty() ? wxString(_("Print")) : title, - pos, size, style ) -{ -} - -// --------------------------------------------------------------------------- -// wxPrintDialog: the dialog for printing -// --------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPrintDialog, wxObject) - -wxPrintDialog::wxPrintDialog(wxWindow *parent, wxPrintDialogData* data) -{ - m_pimpl = wxPrintFactory::GetFactory()->CreatePrintDialog( parent, data ); -} - -wxPrintDialog::wxPrintDialog(wxWindow *parent, wxPrintData* data) -{ - m_pimpl = wxPrintFactory::GetFactory()->CreatePrintDialog( parent, data ); -} - -wxPrintDialog::~wxPrintDialog() -{ - delete m_pimpl; -} - -int wxPrintDialog::ShowModal() -{ - return m_pimpl->ShowModal(); -} - -wxPrintDialogData& wxPrintDialog::GetPrintDialogData() -{ - return m_pimpl->GetPrintDialogData(); -} - -wxPrintData& wxPrintDialog::GetPrintData() -{ - return m_pimpl->GetPrintData(); -} - -wxDC *wxPrintDialog::GetPrintDC() -{ - return m_pimpl->GetPrintDC(); -} - -// --------------------------------------------------------------------------- -// wxPageSetupDialogBase: the page setup dialog -// --------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxPageSetupDialogBase, wxDialog) - -wxPageSetupDialogBase::wxPageSetupDialogBase(wxWindow *parent, - wxWindowID id, - const wxString &title, - const wxPoint &pos, - const wxSize &size, - long style) - : wxDialog( parent, id, title.empty() ? wxString(_("Page setup")) : title, - pos, size, style ) -{ -} - -// --------------------------------------------------------------------------- -// wxPageSetupDialog: the page setup dialog -// --------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPageSetupDialog, wxObject) - -wxPageSetupDialog::wxPageSetupDialog(wxWindow *parent, wxPageSetupDialogData *data ) -{ - m_pimpl = wxPrintFactory::GetFactory()->CreatePageSetupDialog( parent, data ); -} - -wxPageSetupDialog::~wxPageSetupDialog() -{ - delete m_pimpl; -} - -int wxPageSetupDialog::ShowModal() -{ - return m_pimpl->ShowModal(); -} - -wxPageSetupDialogData& wxPageSetupDialog::GetPageSetupDialogData() -{ - return m_pimpl->GetPageSetupDialogData(); -} - -// old name -wxPageSetupDialogData& wxPageSetupDialog::GetPageSetupData() -{ - return m_pimpl->GetPageSetupDialogData(); -} - -//---------------------------------------------------------------------------- -// wxPrintAbortDialog -//---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxPrintAbortDialog, wxDialog) - EVT_BUTTON(wxID_CANCEL, wxPrintAbortDialog::OnCancel) -END_EVENT_TABLE() - -void wxPrintAbortDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) -{ - wxPrinterBase::sm_abortIt = true; - wxPrinterBase::sm_abortWindow->Show(false); - wxPrinterBase::sm_abortWindow->Close(true); - wxPrinterBase::sm_abortWindow->Destroy(); - wxPrinterBase::sm_abortWindow = (wxWindow *) NULL; -} - -//---------------------------------------------------------------------------- -// wxPrintout -//---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxPrintout, wxObject) - -wxPrintout::wxPrintout(const wxString& title) -{ - m_printoutTitle = title ; - m_printoutDC = (wxDC *) NULL; - m_pageWidthMM = 0; - m_pageHeightMM = 0; - m_pageWidthPixels = 0; - m_pageHeightPixels = 0; - m_PPIScreenX = 0; - m_PPIScreenY = 0; - m_PPIPrinterX = 0; - m_PPIPrinterY = 0; - m_isPreview = false; -} - -wxPrintout::~wxPrintout() -{ -} - -bool wxPrintout::OnBeginDocument(int WXUNUSED(startPage), int WXUNUSED(endPage)) -{ - return GetDC()->StartDoc(_("Printing ") + m_printoutTitle); -} - -void wxPrintout::OnEndDocument() -{ - GetDC()->EndDoc(); -} - -void wxPrintout::OnBeginPrinting() -{ -} - -void wxPrintout::OnEndPrinting() -{ -} - -bool wxPrintout::HasPage(int page) -{ - return (page == 1); -} - -void wxPrintout::GetPageInfo(int *minPage, int *maxPage, int *fromPage, int *toPage) -{ - *minPage = 1; - *maxPage = 32000; - *fromPage = 1; - *toPage = 1; -} - -void wxPrintout::FitThisSizeToPaper(const wxSize& imageSize) -{ - // Set the DC scale and origin so that the given image size fits within the - // entire page and the origin is at the top left corner of the page. Note - // that with most printers, portions of the page will be non-printable. Use - // this if you're managing your own page margins. - if (!m_printoutDC) return; - wxRect paperRect = GetPaperRectPixels(); - wxCoord pw, ph; - GetPageSizePixels(&pw, &ph); - wxCoord w, h; - m_printoutDC->GetSize(&w, &h); - float scaleX = ((float(paperRect.width) * w) / (float(pw) * imageSize.x)); - float scaleY = ((float(paperRect.height) * h) / (float(ph) * imageSize.y)); - float actualScale = wxMin(scaleX, scaleY); - m_printoutDC->SetUserScale(actualScale, actualScale); - m_printoutDC->SetDeviceOrigin(0, 0); - wxRect logicalPaperRect = GetLogicalPaperRect(); - SetLogicalOrigin(logicalPaperRect.x, logicalPaperRect.y); -} - -void wxPrintout::FitThisSizeToPage(const wxSize& imageSize) -{ - // Set the DC scale and origin so that the given image size fits within the - // printable area of the page and the origin is at the top left corner of - // the printable area. - if (!m_printoutDC) return; - int w, h; - m_printoutDC->GetSize(&w, &h); - float scaleX = float(w) / imageSize.x; - float scaleY = float(h) / imageSize.y; - float actualScale = wxMin(scaleX, scaleY); - m_printoutDC->SetUserScale(actualScale, actualScale); - m_printoutDC->SetDeviceOrigin(0, 0); -} - -void wxPrintout::FitThisSizeToPageMargins(const wxSize& imageSize, const wxPageSetupDialogData& pageSetupData) -{ - // Set the DC scale and origin so that the given image size fits within the - // page margins defined in the given wxPageSetupDialogData object and the - // origin is at the top left corner of the page margins. - if (!m_printoutDC) return; - wxRect paperRect = GetPaperRectPixels(); - wxCoord pw, ph; - GetPageSizePixels(&pw, &ph); - wxPoint topLeft = pageSetupData.GetMarginTopLeft(); - wxPoint bottomRight = pageSetupData.GetMarginBottomRight(); - wxCoord mw, mh; - GetPageSizeMM(&mw, &mh); - float mmToDeviceX = float(pw) / mw; - float mmToDeviceY = float(ph) / mh; - wxRect pageMarginsRect(paperRect.x + wxRound(mmToDeviceX * topLeft.x), - paperRect.y + wxRound(mmToDeviceY * topLeft.y), - paperRect.width - wxRound(mmToDeviceX * (topLeft.x + bottomRight.x)), - paperRect.height - wxRound(mmToDeviceY * (topLeft.y + bottomRight.y))); - wxCoord w, h; - m_printoutDC->GetSize(&w, &h); - float scaleX = (float(pageMarginsRect.width) * w) / (float(pw) * imageSize.x); - float scaleY = (float(pageMarginsRect.height) * h) / (float(ph) * imageSize.y); - float actualScale = wxMin(scaleX, scaleY); - m_printoutDC->SetUserScale(actualScale, actualScale); - m_printoutDC->SetDeviceOrigin(0, 0); - wxRect logicalPageMarginsRect = GetLogicalPageMarginsRect(pageSetupData); - SetLogicalOrigin(logicalPageMarginsRect.x, logicalPageMarginsRect.y); -} - -void wxPrintout::MapScreenSizeToPaper() -{ - // Set the DC scale so that an image on the screen is the same size on the - // paper and the origin is at the top left of the paper. Note that with most - // printers, portions of the page will be cut off. Use this if you're - // managing your own page margins. - if (!m_printoutDC) return; - MapScreenSizeToPage(); - wxRect logicalPaperRect = GetLogicalPaperRect(); - SetLogicalOrigin(logicalPaperRect.x, logicalPaperRect.y); -} - -void wxPrintout::MapScreenSizeToPage() -{ - // Set the DC scale and origin so that an image on the screen is the same - // size on the paper and the origin is at the top left of the printable area. - if (!m_printoutDC) return; - int ppiScreenX, ppiScreenY; - GetPPIScreen(&ppiScreenX, &ppiScreenY); - int ppiPrinterX, ppiPrinterY; - GetPPIPrinter(&ppiPrinterX, &ppiPrinterY); - int w, h; - m_printoutDC->GetSize(&w, &h); - int pageSizePixelsX, pageSizePixelsY; - GetPageSizePixels(&pageSizePixelsX, &pageSizePixelsY); - float userScaleX = (float(ppiPrinterX) * w) / (float(ppiScreenX) * pageSizePixelsX); - float userScaleY = (float(ppiPrinterY) * h) / (float(ppiScreenY) * pageSizePixelsY); - m_printoutDC->SetUserScale(userScaleX, userScaleY); - m_printoutDC->SetDeviceOrigin(0, 0); -} - -void wxPrintout::MapScreenSizeToPageMargins(const wxPageSetupDialogData& pageSetupData) -{ - // Set the DC scale so that an image on the screen is the same size on the - // paper and the origin is at the top left of the page margins defined by - // the given wxPageSetupDialogData object. - if (!m_printoutDC) return; - MapScreenSizeToPage(); - wxRect logicalPageMarginsRect = GetLogicalPageMarginsRect(pageSetupData); - SetLogicalOrigin(logicalPageMarginsRect.x, logicalPageMarginsRect.y); -} - -void wxPrintout::MapScreenSizeToDevice() -{ - // Set the DC scale so that a screen pixel is the same size as a device - // pixel and the origin is at the top left of the printable area. - if (!m_printoutDC) return; - int w, h; - m_printoutDC->GetSize(&w, &h); - int pageSizePixelsX, pageSizePixelsY; - GetPageSizePixels(&pageSizePixelsX, &pageSizePixelsY); - float userScaleX = float(w) / pageSizePixelsX; - float userScaleY = float(h) / pageSizePixelsY; - m_printoutDC->SetUserScale(userScaleX, userScaleY); - m_printoutDC->SetDeviceOrigin(0, 0); -} - -wxRect wxPrintout::GetLogicalPaperRect() const -{ - // Return the rectangle in logical units that corresponds to the paper - // rectangle. - wxRect paperRect = GetPaperRectPixels(); - wxCoord pw, ph; - GetPageSizePixels(&pw, &ph); - wxCoord w, h; - m_printoutDC->GetSize(&w, &h); - if (w == pw && h == ph) { - // this DC matches the printed page, so no scaling - return wxRect(m_printoutDC->DeviceToLogicalX(paperRect.x), - m_printoutDC->DeviceToLogicalY(paperRect.y), - m_printoutDC->DeviceToLogicalXRel(paperRect.width), - m_printoutDC->DeviceToLogicalYRel(paperRect.height)); - } - // This DC doesn't match the printed page, so we have to scale. - float scaleX = float(w) / pw; - float scaleY = float(h) / ph; - return wxRect(m_printoutDC->DeviceToLogicalX(wxRound(paperRect.x * scaleX)), - m_printoutDC->DeviceToLogicalY(wxRound(paperRect.y * scaleY)), - m_printoutDC->DeviceToLogicalXRel(wxRound(paperRect.width * scaleX)), - m_printoutDC->DeviceToLogicalYRel(wxRound(paperRect.height * scaleY))); -} - -wxRect wxPrintout::GetLogicalPageRect() const -{ - // Return the rectangle in logical units that corresponds to the printable - // area. - int w, h; - m_printoutDC->GetSize(&w, &h); - return wxRect(m_printoutDC->DeviceToLogicalX(0), - m_printoutDC->DeviceToLogicalY(0), - m_printoutDC->DeviceToLogicalXRel(w), - m_printoutDC->DeviceToLogicalYRel(h)); -} - -wxRect wxPrintout::GetLogicalPageMarginsRect(const wxPageSetupDialogData& pageSetupData) const -{ - // Return the rectangle in logical units that corresponds to the region - // within the page margins as specified by the given wxPageSetupDialogData - // object. - wxRect paperRect = GetPaperRectPixels(); - wxCoord pw, ph; - GetPageSizePixels(&pw, &ph); - wxPoint topLeft = pageSetupData.GetMarginTopLeft(); - wxPoint bottomRight = pageSetupData.GetMarginBottomRight(); - wxCoord mw, mh; - GetPageSizeMM(&mw, &mh); - float mmToDeviceX = float(pw) / mw; - float mmToDeviceY = float(ph) / mh; - wxRect pageMarginsRect(paperRect.x + wxRound(mmToDeviceX * topLeft.x), - paperRect.y + wxRound(mmToDeviceY * topLeft.y), - paperRect.width - wxRound(mmToDeviceX * (topLeft.x + bottomRight.x)), - paperRect.height - wxRound(mmToDeviceY * (topLeft.y + bottomRight.y))); - wxCoord w, h; - m_printoutDC->GetSize(&w, &h); - if (w == pw && h == ph) { - // this DC matches the printed page, so no scaling - return wxRect(m_printoutDC->DeviceToLogicalX(pageMarginsRect.x), - m_printoutDC->DeviceToLogicalY(pageMarginsRect.y), - m_printoutDC->DeviceToLogicalXRel(pageMarginsRect.width), - m_printoutDC->DeviceToLogicalYRel(pageMarginsRect.height)); - } - // This DC doesn't match the printed page, so we have to scale. - float scaleX = float(w) / pw; - float scaleY = float(h) / ph; - return wxRect(m_printoutDC->DeviceToLogicalX(wxRound(pageMarginsRect.x * scaleX)), - m_printoutDC->DeviceToLogicalY(wxRound(pageMarginsRect.y * scaleY)), - m_printoutDC->DeviceToLogicalXRel(wxRound(pageMarginsRect.width * scaleX)), - m_printoutDC->DeviceToLogicalYRel(wxRound(pageMarginsRect.height * scaleY))); -} - -void wxPrintout::SetLogicalOrigin(wxCoord x, wxCoord y) -{ - // Set the device origin by specifying a point in logical coordinates. - m_printoutDC->SetDeviceOrigin(m_printoutDC->LogicalToDeviceX(x), - m_printoutDC->LogicalToDeviceY(y)); -} - -void wxPrintout::OffsetLogicalOrigin(wxCoord xoff, wxCoord yoff) -{ - // Offset the device origin by a specified distance in device coordinates. - wxCoord x = m_printoutDC->LogicalToDeviceX(0); - wxCoord y = m_printoutDC->LogicalToDeviceY(0); - m_printoutDC->SetDeviceOrigin(x + m_printoutDC->LogicalToDeviceXRel(xoff), - y + m_printoutDC->LogicalToDeviceYRel(yoff)); -} - - -//---------------------------------------------------------------------------- -// wxPreviewCanvas -//---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPreviewCanvas, wxWindow) - -BEGIN_EVENT_TABLE(wxPreviewCanvas, wxScrolledWindow) - EVT_PAINT(wxPreviewCanvas::OnPaint) - EVT_CHAR(wxPreviewCanvas::OnChar) - EVT_SYS_COLOUR_CHANGED(wxPreviewCanvas::OnSysColourChanged) -#if wxUSE_MOUSEWHEEL - EVT_MOUSEWHEEL(wxPreviewCanvas::OnMouseWheel) -#endif -END_EVENT_TABLE() - -// VZ: the current code doesn't refresh properly without -// wxFULL_REPAINT_ON_RESIZE, this must be fixed as otherwise we have -// really horrible flicker when resizing the preview frame, but without -// this style it simply doesn't work correctly at all... -wxPreviewCanvas::wxPreviewCanvas(wxPrintPreviewBase *preview, wxWindow *parent, - const wxPoint& pos, const wxSize& size, long style, const wxString& name): -wxScrolledWindow(parent, wxID_ANY, pos, size, style | wxFULL_REPAINT_ON_RESIZE, name) -{ - m_printPreview = preview; -#ifdef __WXMAC__ - // The app workspace colour is always white, but we should have - // a contrast with the page. - wxSystemColour colourIndex = wxSYS_COLOUR_3DDKSHADOW; -#elif defined(__WXGTK__) - wxSystemColour colourIndex = wxSYS_COLOUR_BTNFACE; -#else - wxSystemColour colourIndex = wxSYS_COLOUR_APPWORKSPACE; -#endif - SetBackgroundColour(wxSystemSettings::GetColour(colourIndex)); - - SetScrollbars(10, 10, 100, 100); -} - -wxPreviewCanvas::~wxPreviewCanvas() -{ -} - -void wxPreviewCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) -{ - wxPaintDC dc(this); - PrepareDC( dc ); - -/* -#ifdef __WXGTK__ - if (!GetUpdateRegion().IsEmpty()) - dc.SetClippingRegion( GetUpdateRegion() ); -#endif -*/ - - if (m_printPreview) - { - m_printPreview->PaintPage(this, dc); - } -} - -// Responds to colour changes, and passes event on to children. -void wxPreviewCanvas::OnSysColourChanged(wxSysColourChangedEvent& event) -{ -#ifdef __WXMAC__ - // The app workspace colour is always white, but we should have - // a contrast with the page. - wxSystemColour colourIndex = wxSYS_COLOUR_3DDKSHADOW; -#elif defined(__WXGTK__) - wxSystemColour colourIndex = wxSYS_COLOUR_BTNFACE; -#else - wxSystemColour colourIndex = wxSYS_COLOUR_APPWORKSPACE; -#endif - SetBackgroundColour(wxSystemSettings::GetColour(colourIndex)); - Refresh(); - - // Propagate the event to the non-top-level children - wxWindow::OnSysColourChanged(event); -} - -void wxPreviewCanvas::OnChar(wxKeyEvent &event) -{ - wxPreviewControlBar* controlBar = ((wxPreviewFrame*) GetParent())->GetControlBar(); - if (event.GetKeyCode() == WXK_ESCAPE) - { - ((wxPreviewFrame*) GetParent())->Close(true); - return; - } - else if (event.GetKeyCode() == WXK_TAB) - { - controlBar->OnGoto(); - return; - } - else if (event.GetKeyCode() == WXK_RETURN) - { - controlBar->OnPrint(); - return; - } - - if (!event.ControlDown()) - { - event.Skip(); - return; - } - - switch(event.GetKeyCode()) - { - case WXK_PAGEDOWN: - controlBar->OnNext(); break; - case WXK_PAGEUP: - controlBar->OnPrevious(); break; - case WXK_HOME: - controlBar->OnFirst(); break; - case WXK_END: - controlBar->OnLast(); break; - default: - event.Skip(); - } -} - -#if wxUSE_MOUSEWHEEL - -void wxPreviewCanvas::OnMouseWheel(wxMouseEvent& event) -{ - wxPreviewControlBar * - controlBar = wxStaticCast(GetParent(), wxPreviewFrame)->GetControlBar(); - - if ( controlBar ) - { - if ( event.ControlDown() && event.GetWheelRotation() != 0 ) - { - int currentZoom = controlBar->GetZoomControl(); - - int delta; - if ( currentZoom < 100 ) - delta = 5; - else if ( currentZoom <= 120 ) - delta = 10; - else - delta = 50; - - if ( event.GetWheelRotation() > 0 ) - delta = -delta; - - int newZoom = currentZoom + delta; - if ( newZoom < 10 ) - newZoom = 10; - if ( newZoom > 200 ) - newZoom = 200; - if ( newZoom != currentZoom ) - { - controlBar->SetZoomControl(newZoom); - m_printPreview->SetZoom(newZoom); - Refresh(); - } - return; - } - } - - event.Skip(); -} - -#endif // wxUSE_MOUSEWHEEL - -//---------------------------------------------------------------------------- -// wxPreviewControlBar -//---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPreviewControlBar, wxWindow) - -BEGIN_EVENT_TABLE(wxPreviewControlBar, wxPanel) - EVT_BUTTON(wxID_PREVIEW_CLOSE, wxPreviewControlBar::OnWindowClose) - EVT_BUTTON(wxID_PREVIEW_PRINT, wxPreviewControlBar::OnPrintButton) - EVT_BUTTON(wxID_PREVIEW_PREVIOUS, wxPreviewControlBar::OnPreviousButton) - EVT_BUTTON(wxID_PREVIEW_NEXT, wxPreviewControlBar::OnNextButton) - EVT_BUTTON(wxID_PREVIEW_FIRST, wxPreviewControlBar::OnFirstButton) - EVT_BUTTON(wxID_PREVIEW_LAST, wxPreviewControlBar::OnLastButton) - EVT_BUTTON(wxID_PREVIEW_GOTO, wxPreviewControlBar::OnGotoButton) - EVT_CHOICE(wxID_PREVIEW_ZOOM, wxPreviewControlBar::OnZoom) - EVT_PAINT(wxPreviewControlBar::OnPaint) -END_EVENT_TABLE() - -wxPreviewControlBar::wxPreviewControlBar(wxPrintPreviewBase *preview, long buttons, - wxWindow *parent, const wxPoint& pos, const wxSize& size, - long style, const wxString& name): -wxPanel(parent, wxID_ANY, pos, size, style, name) -{ - m_printPreview = preview; - m_closeButton = (wxButton *) NULL; - m_nextPageButton = (wxButton *) NULL; - m_previousPageButton = (wxButton *) NULL; - m_printButton = (wxButton *) NULL; - m_zoomControl = (wxChoice *) NULL; - m_buttonFlags = buttons; -} - -wxPreviewControlBar::~wxPreviewControlBar() -{ -} - -void wxPreviewControlBar::OnPaint(wxPaintEvent& WXUNUSED(event)) -{ - wxPaintDC dc(this); - - int w, h; - GetSize(&w, &h); - dc.SetPen(*wxBLACK_PEN); - dc.SetBrush(*wxTRANSPARENT_BRUSH); - dc.DrawLine( 0, h-1, w, h-1 ); -} - -void wxPreviewControlBar::OnWindowClose(wxCommandEvent& WXUNUSED(event)) -{ - wxPreviewFrame *frame = (wxPreviewFrame *)GetParent(); - frame->Close(true); -} - -void wxPreviewControlBar::OnPrint(void) -{ - wxPrintPreviewBase *preview = GetPrintPreview(); - preview->Print(true); -} - -void wxPreviewControlBar::OnNext(void) -{ - wxPrintPreviewBase *preview = GetPrintPreview(); - if (preview) - { - int currentPage = preview->GetCurrentPage(); - if ((preview->GetMaxPage() > 0) && - (currentPage < preview->GetMaxPage()) && - preview->GetPrintout()->HasPage(currentPage + 1)) - { - preview->SetCurrentPage(currentPage + 1); - } - } -} - -void wxPreviewControlBar::OnPrevious(void) -{ - wxPrintPreviewBase *preview = GetPrintPreview(); - if (preview) - { - int currentPage = preview->GetCurrentPage(); - if ((preview->GetMinPage() > 0) && - (currentPage > preview->GetMinPage()) && - preview->GetPrintout()->HasPage(currentPage - 1)) - { - preview->SetCurrentPage(currentPage - 1); - } - } -} - -void wxPreviewControlBar::OnFirst(void) -{ - wxPrintPreviewBase *preview = GetPrintPreview(); - if (preview) - { - int currentPage = preview->GetMinPage(); - if (preview->GetPrintout()->HasPage(currentPage)) - { - preview->SetCurrentPage(currentPage); - } - } -} - -void wxPreviewControlBar::OnLast(void) -{ - wxPrintPreviewBase *preview = GetPrintPreview(); - if (preview) - { - int currentPage = preview->GetMaxPage(); - if (preview->GetPrintout()->HasPage(currentPage)) - { - preview->SetCurrentPage(currentPage); - } - } -} - -void wxPreviewControlBar::OnGoto(void) -{ - wxPrintPreviewBase *preview = GetPrintPreview(); - if (preview) - { - long currentPage; - - if (preview->GetMinPage() > 0) - { - wxString strPrompt; - wxString strPage; - - strPrompt.Printf( _("Enter a page number between %d and %d:"), - preview->GetMinPage(), preview->GetMaxPage()); - strPage.Printf( wxT("%d"), preview->GetCurrentPage() ); - - strPage = - wxGetTextFromUser( strPrompt, _("Goto Page"), strPage, GetParent()); - - if ( strPage.ToLong( ¤tPage ) ) - if (preview->GetPrintout()->HasPage(currentPage)) - { - preview->SetCurrentPage(currentPage); - } - } - } -} - -void wxPreviewControlBar::OnZoom(wxCommandEvent& WXUNUSED(event)) -{ - int zoom = GetZoomControl(); - if (GetPrintPreview()) - GetPrintPreview()->SetZoom(zoom); -} - -void wxPreviewControlBar::CreateButtons() -{ - SetSize(0, 0, 400, 40); - - wxBoxSizer *item0 = new wxBoxSizer( wxHORIZONTAL ); - - m_closeButton = new wxButton( this, wxID_PREVIEW_CLOSE, _("&Close"), wxDefaultPosition, wxDefaultSize, 0 ); - item0->Add( m_closeButton, 0, wxALIGN_CENTRE|wxALL, 5 ); - - if (m_buttonFlags & wxPREVIEW_PRINT) - { - m_printButton = new wxButton( this, wxID_PREVIEW_PRINT, _("&Print..."), wxDefaultPosition, wxDefaultSize, 0 ); - item0->Add( m_printButton, 0, wxALIGN_CENTRE|wxALL, 5 ); - } - - // Exact-fit buttons are too tiny on wxUniversal - int navButtonStyle; - wxSize navButtonSize; -#ifdef __WXUNIVERSAL__ - navButtonStyle = 0; - navButtonSize = wxSize(40, m_closeButton->GetSize().y); -#else - navButtonStyle = wxBU_EXACTFIT; - navButtonSize = wxDefaultSize; -#endif - - if (m_buttonFlags & wxPREVIEW_FIRST) - { - m_firstPageButton = new wxButton( this, wxID_PREVIEW_FIRST, _("|<<"), wxDefaultPosition, navButtonSize, navButtonStyle ); - item0->Add( m_firstPageButton, 0, wxALIGN_CENTRE|wxALL, 5 ); - } - - if (m_buttonFlags & wxPREVIEW_PREVIOUS) - { - m_previousPageButton = new wxButton( this, wxID_PREVIEW_PREVIOUS, _("<<"), wxDefaultPosition, navButtonSize, navButtonStyle ); - item0->Add( m_previousPageButton, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 ); - } - - if (m_buttonFlags & wxPREVIEW_NEXT) - { - m_nextPageButton = new wxButton( this, wxID_PREVIEW_NEXT, _(">>"), wxDefaultPosition, navButtonSize, navButtonStyle ); - item0->Add( m_nextPageButton, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 ); - } - - if (m_buttonFlags & wxPREVIEW_LAST) - { - m_lastPageButton = new wxButton( this, wxID_PREVIEW_LAST, _(">>|"), wxDefaultPosition, navButtonSize, navButtonStyle ); - item0->Add( m_lastPageButton, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 ); - } - - if (m_buttonFlags & wxPREVIEW_GOTO) - { - m_gotoPageButton = new wxButton( this, wxID_PREVIEW_GOTO, _("&Goto..."), wxDefaultPosition, wxDefaultSize, 0 ); - item0->Add( m_gotoPageButton, 0, wxALIGN_CENTRE|wxALL, 5 ); - } - - if (m_buttonFlags & wxPREVIEW_ZOOM) - { - wxString choices[] = - { - wxT("10%"), wxT("15%"), wxT("20%"), wxT("25%"), wxT("30%"), wxT("35%"), wxT("40%"), wxT("45%"), wxT("50%"), wxT("55%"), - wxT("60%"), wxT("65%"), wxT("70%"), wxT("75%"), wxT("80%"), wxT("85%"), wxT("90%"), wxT("95%"), wxT("100%"), wxT("110%"), - wxT("120%"), wxT("150%"), wxT("200%") - }; - int n = WXSIZEOF(choices); - - m_zoomControl = new wxChoice( this, wxID_PREVIEW_ZOOM, wxDefaultPosition, wxSize(70,wxDefaultCoord), n, choices, 0 ); - item0->Add( m_zoomControl, 0, wxALIGN_CENTRE|wxALL, 5 ); - SetZoomControl(m_printPreview->GetZoom()); - } - - SetSizer(item0); - item0->Fit(this); -} - -void wxPreviewControlBar::SetZoomControl(int zoom) -{ - if (m_zoomControl) - { - int n, count = m_zoomControl->GetCount(); - long val; - for (n=0; nGetString(n).BeforeFirst(wxT('%')).ToLong(&val) && - (val >= long(zoom))) - { - m_zoomControl->SetSelection(n); - return; - } - } - - m_zoomControl->SetSelection(count-1); - } -} - -int wxPreviewControlBar::GetZoomControl() -{ - if (m_zoomControl && (m_zoomControl->GetStringSelection() != wxEmptyString)) - { - long val; - if (m_zoomControl->GetStringSelection().BeforeFirst(wxT('%')).ToLong(&val)) - return int(val); - } - - return 0; -} - - -/* -* Preview frame -*/ - -IMPLEMENT_CLASS(wxPreviewFrame, wxFrame) - -BEGIN_EVENT_TABLE(wxPreviewFrame, wxFrame) - EVT_CLOSE(wxPreviewFrame::OnCloseWindow) -END_EVENT_TABLE() - -wxPreviewFrame::wxPreviewFrame(wxPrintPreviewBase *preview, wxWindow *parent, const wxString& title, - const wxPoint& pos, const wxSize& size, long style, const wxString& name): -wxFrame(parent, wxID_ANY, title, pos, size, style, name) -{ - m_printPreview = preview; - m_controlBar = NULL; - m_previewCanvas = NULL; - m_windowDisabler = NULL; - - // Give the application icon -#ifdef __WXMSW__ - wxFrame* topFrame = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame); - if (topFrame) - SetIcon(topFrame->GetIcon()); -#endif -} - -wxPreviewFrame::~wxPreviewFrame() -{ -} - -void wxPreviewFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) -{ - if (m_windowDisabler) - delete m_windowDisabler; - - // Need to delete the printout and the print preview - wxPrintout *printout = m_printPreview->GetPrintout(); - if (printout) - { - delete printout; - m_printPreview->SetPrintout(NULL); - m_printPreview->SetCanvas(NULL); - m_printPreview->SetFrame(NULL); - } - delete m_printPreview; - - Destroy(); -} - -void wxPreviewFrame::Initialize() -{ -#if wxUSE_STATUSBAR - CreateStatusBar(); -#endif - CreateCanvas(); - CreateControlBar(); - - m_printPreview->SetCanvas(m_previewCanvas); - m_printPreview->SetFrame(this); - - wxBoxSizer *item0 = new wxBoxSizer( wxVERTICAL ); - - item0->Add( m_controlBar, 0, wxGROW|wxALIGN_CENTER_VERTICAL, 5 ); - item0->Add( m_previewCanvas, 1, wxGROW|wxALIGN_CENTER_VERTICAL, 5 ); - - SetAutoLayout( true ); - SetSizer( item0 ); - - m_windowDisabler = new wxWindowDisabler(this); - - Layout(); - - m_printPreview->AdjustScrollbars(m_previewCanvas); - m_previewCanvas->SetFocus(); - m_controlBar->SetFocus(); -} - -void wxPreviewFrame::CreateCanvas() -{ - m_previewCanvas = new wxPreviewCanvas(m_printPreview, this); -} - -void wxPreviewFrame::CreateControlBar() -{ - long buttons = wxPREVIEW_DEFAULT; - if (m_printPreview->GetPrintoutForPrinting()) - buttons |= wxPREVIEW_PRINT; - - m_controlBar = new wxPreviewControlBar(m_printPreview, buttons, this, wxPoint(0,0), wxSize(400, 40)); - m_controlBar->CreateButtons(); -} - -/* -* Print preview -*/ - -IMPLEMENT_CLASS(wxPrintPreviewBase, wxObject) - -wxPrintPreviewBase::wxPrintPreviewBase(wxPrintout *printout, - wxPrintout *printoutForPrinting, - wxPrintData *data) -{ - if (data) - m_printDialogData = (*data); - - Init(printout, printoutForPrinting); -} - -wxPrintPreviewBase::wxPrintPreviewBase(wxPrintout *printout, - wxPrintout *printoutForPrinting, - wxPrintDialogData *data) -{ - if (data) - m_printDialogData = (*data); - - Init(printout, printoutForPrinting); -} - -void wxPrintPreviewBase::Init(wxPrintout *printout, - wxPrintout *printoutForPrinting) -{ - m_isOk = true; - m_previewPrintout = printout; - if (m_previewPrintout) - m_previewPrintout->SetIsPreview(true); - - m_printPrintout = printoutForPrinting; - - m_previewCanvas = NULL; - m_previewFrame = NULL; - m_previewBitmap = NULL; - m_currentPage = 1; - m_currentZoom = 70; - m_topMargin = 40; - m_leftMargin = 40; - m_pageWidth = 0; - m_pageHeight = 0; - m_printingPrepared = false; - m_minPage = 1; - m_maxPage = 1; -} - -wxPrintPreviewBase::~wxPrintPreviewBase() -{ - if (m_previewPrintout) - delete m_previewPrintout; - if (m_previewBitmap) - delete m_previewBitmap; - if (m_printPrintout) - delete m_printPrintout; -} - -bool wxPrintPreviewBase::SetCurrentPage(int pageNum) -{ - if (m_currentPage == pageNum) - return true; - - m_currentPage = pageNum; - if (m_previewBitmap) - { - delete m_previewBitmap; - m_previewBitmap = NULL; - } - - if (m_previewCanvas) - { - AdjustScrollbars(m_previewCanvas); - - if (!RenderPage(pageNum)) - return false; - m_previewCanvas->Refresh(); - m_previewCanvas->SetFocus(); - } - return true; -} - -int wxPrintPreviewBase::GetCurrentPage() const - { return m_currentPage; } -void wxPrintPreviewBase::SetPrintout(wxPrintout *printout) - { m_previewPrintout = printout; } -wxPrintout *wxPrintPreviewBase::GetPrintout() const - { return m_previewPrintout; } -wxPrintout *wxPrintPreviewBase::GetPrintoutForPrinting() const - { return m_printPrintout; } -void wxPrintPreviewBase::SetFrame(wxFrame *frame) - { m_previewFrame = frame; } -void wxPrintPreviewBase::SetCanvas(wxPreviewCanvas *canvas) - { m_previewCanvas = canvas; } -wxFrame *wxPrintPreviewBase::GetFrame() const - { return m_previewFrame; } -wxPreviewCanvas *wxPrintPreviewBase::GetCanvas() const - { return m_previewCanvas; } - -void wxPrintPreviewBase::CalcRects(wxPreviewCanvas *canvas, wxRect& pageRect, wxRect& paperRect) -{ - // Calculate the rectangles for the printable area of the page and the - // entire paper as they appear on the canvas on-screen. - int canvasWidth, canvasHeight; - canvas->GetSize(&canvasWidth, &canvasHeight); - - float zoomScale = float(m_currentZoom) / 100; - float screenPrintableWidth = zoomScale * m_pageWidth * m_previewScaleX; - float screenPrintableHeight = zoomScale * m_pageHeight * m_previewScaleY; - - wxRect devicePaperRect = m_previewPrintout->GetPaperRectPixels(); - wxCoord devicePrintableWidth, devicePrintableHeight; - m_previewPrintout->GetPageSizePixels(&devicePrintableWidth, &devicePrintableHeight); - float scaleX = screenPrintableWidth / devicePrintableWidth; - float scaleY = screenPrintableHeight / devicePrintableHeight; - paperRect.width = wxCoord(scaleX * devicePaperRect.width); - paperRect.height = wxCoord(scaleY * devicePaperRect.height); - - paperRect.x = wxCoord((canvasWidth - paperRect.width)/ 2.0); - if (paperRect.x < m_leftMargin) - paperRect.x = m_leftMargin; - paperRect.y = wxCoord((canvasHeight - paperRect.height)/ 2.0); - if (paperRect.y < m_topMargin) - paperRect.y = m_topMargin; - - pageRect.x = paperRect.x - wxCoord(scaleX * devicePaperRect.x); - pageRect.y = paperRect.y - wxCoord(scaleY * devicePaperRect.y); - pageRect.width = wxCoord(screenPrintableWidth); - pageRect.height = wxCoord(screenPrintableHeight); -} - - -bool wxPrintPreviewBase::PaintPage(wxPreviewCanvas *canvas, wxDC& dc) -{ - DrawBlankPage(canvas, dc); - - if (!m_previewBitmap) - if (!RenderPage(m_currentPage)) - return false; - if (!m_previewBitmap) - return false; - if (!canvas) - return false; - - wxRect pageRect, paperRect; - CalcRects(canvas, pageRect, paperRect); - wxMemoryDC temp_dc; - temp_dc.SelectObject(*m_previewBitmap); - - dc.Blit(pageRect.x, pageRect.y, - m_previewBitmap->GetWidth(), m_previewBitmap->GetHeight(), &temp_dc, 0, 0); - - temp_dc.SelectObject(wxNullBitmap); - return true; -} - -// Adjusts the scrollbars for the current scale -void wxPrintPreviewBase::AdjustScrollbars(wxPreviewCanvas *canvas) -{ - if (!canvas) - return ; - - wxRect pageRect, paperRect; - CalcRects(canvas, pageRect, paperRect); - int totalWidth = paperRect.width + 2 * m_leftMargin; - int totalHeight = paperRect.height + 2 * m_topMargin; - int scrollUnitsX = totalWidth / 10; - int scrollUnitsY = totalHeight / 10; - wxSize virtualSize = canvas->GetVirtualSize(); - if (virtualSize.GetWidth() != totalWidth || virtualSize.GetHeight() != totalHeight) - canvas->SetScrollbars(10, 10, scrollUnitsX, scrollUnitsY, 0, 0, true); -} - -bool wxPrintPreviewBase::RenderPageIntoDC(wxDC& dc, int pageNum) -{ - m_previewPrintout->SetDC(&dc); - m_previewPrintout->SetPageSizePixels(m_pageWidth, m_pageHeight); - - // Need to delay OnPreparePrinting() until here, so we have enough - // information. - if (!m_printingPrepared) - { - m_previewPrintout->OnPreparePrinting(); - int selFrom, selTo; - m_previewPrintout->GetPageInfo(&m_minPage, &m_maxPage, &selFrom, &selTo); - m_printingPrepared = true; - } - - m_previewPrintout->OnBeginPrinting(); - - if (!m_previewPrintout->OnBeginDocument(m_printDialogData.GetFromPage(), m_printDialogData.GetToPage())) - { - wxMessageBox(_("Could not start document preview."), _("Print Preview Failure"), wxOK); - return false; - } - - m_previewPrintout->OnPrintPage(pageNum); - m_previewPrintout->OnEndDocument(); - m_previewPrintout->OnEndPrinting(); - - m_previewPrintout->SetDC(NULL); - - return true; -} - -bool wxPrintPreviewBase::RenderPageIntoBitmap(wxBitmap& bmp, int pageNum) -{ -#if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW - { - if ( RenderPageIntoBitmapHQ(this, - &wxPrintPreviewBase::RenderPageIntoDC, - bmp, pageNum) ) - { - return true; - } - } -#endif // wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW - - wxMemoryDC memoryDC; - memoryDC.SelectObject(bmp); - memoryDC.Clear(); - - return RenderPageIntoDC(memoryDC, pageNum); -} - -bool wxPrintPreviewBase::RenderPage(int pageNum) -{ - wxBusyCursor busy; - - if (!m_previewCanvas) - { - wxFAIL_MSG(_T("wxPrintPreviewBase::RenderPage: must use wxPrintPreviewBase::SetCanvas to let me know about the canvas!")); - return false; - } - - wxRect pageRect, paperRect; - CalcRects(m_previewCanvas, pageRect, paperRect); - - if (!m_previewBitmap) - { - m_previewBitmap = new wxBitmap(pageRect.width, pageRect.height); - - if (!m_previewBitmap || !m_previewBitmap->Ok()) - { - if (m_previewBitmap) { - delete m_previewBitmap; - m_previewBitmap = NULL; - } - wxMessageBox(_("Sorry, not enough memory to create a preview."), _("Print Preview Failure"), wxOK); - return false; - } - } - - if ( !RenderPageIntoBitmap(*m_previewBitmap, pageNum) ) - { - wxMessageBox(_("Could not start document preview."), _("Print Preview Failure"), wxOK); - - delete m_previewBitmap; - m_previewBitmap = NULL; - return false; - } - -#if wxUSE_STATUSBAR - wxString status; - if (m_maxPage != 0) - status = wxString::Format(_("Page %d of %d"), pageNum, m_maxPage); - else - status = wxString::Format(_("Page %d"), pageNum); - - if (m_previewFrame) - m_previewFrame->SetStatusText(status); -#endif - - return true; -} - -bool wxPrintPreviewBase::DrawBlankPage(wxPreviewCanvas *canvas, wxDC& dc) -{ - wxRect pageRect, paperRect; - - CalcRects(canvas, pageRect, paperRect); - - // Draw shadow, allowing for 1-pixel border AROUND the actual paper - wxCoord shadowOffset = 4; - - dc.SetPen(*wxBLACK_PEN); - dc.SetBrush(*wxBLACK_BRUSH); - dc.DrawRectangle(paperRect.x + shadowOffset, paperRect.y + paperRect.height + 1, - paperRect.width, shadowOffset); - - dc.DrawRectangle(paperRect.x + paperRect.width, paperRect.y + shadowOffset, - shadowOffset, paperRect.height); - - // Draw blank page allowing for 1-pixel border AROUND the actual paper - dc.SetPen(*wxBLACK_PEN); - dc.SetBrush(*wxWHITE_BRUSH); - dc.DrawRectangle(paperRect.x - 2, paperRect.y - 1, - paperRect.width + 3, paperRect.height + 2); - - return true; -} - -void wxPrintPreviewBase::SetZoom(int percent) -{ - if (m_currentZoom == percent) - return; - - m_currentZoom = percent; - if (m_previewBitmap) - { - delete m_previewBitmap; - m_previewBitmap = NULL; - } - - if (m_previewCanvas) - { - AdjustScrollbars(m_previewCanvas); - RenderPage(m_currentPage); - ((wxScrolledWindow *) m_previewCanvas)->Scroll(0, 0); - m_previewCanvas->ClearBackground(); - m_previewCanvas->Refresh(); - m_previewCanvas->SetFocus(); - } -} - -wxPrintDialogData& wxPrintPreviewBase::GetPrintDialogData() -{ - return m_printDialogData; -} - -int wxPrintPreviewBase::GetZoom() const -{ return m_currentZoom; } -int wxPrintPreviewBase::GetMaxPage() const -{ return m_maxPage; } -int wxPrintPreviewBase::GetMinPage() const -{ return m_minPage; } -bool wxPrintPreviewBase::IsOk() const -{ return m_isOk; } -void wxPrintPreviewBase::SetOk(bool ok) -{ m_isOk = ok; } - -//---------------------------------------------------------------------------- -// wxPrintPreview -//---------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxPrintPreview, wxPrintPreviewBase) - -wxPrintPreview::wxPrintPreview(wxPrintout *printout, - wxPrintout *printoutForPrinting, - wxPrintDialogData *data) : - wxPrintPreviewBase( printout, printoutForPrinting, data ) -{ - m_pimpl = wxPrintFactory::GetFactory()-> - CreatePrintPreview( printout, printoutForPrinting, data ); -} - -wxPrintPreview::wxPrintPreview(wxPrintout *printout, - wxPrintout *printoutForPrinting, - wxPrintData *data ) : - wxPrintPreviewBase( printout, printoutForPrinting, data ) -{ - m_pimpl = wxPrintFactory::GetFactory()-> - CreatePrintPreview( printout, printoutForPrinting, data ); -} - -wxPrintPreview::~wxPrintPreview() -{ - delete m_pimpl; - - // don't delete twice - m_printPrintout = NULL; - m_previewPrintout = NULL; - m_previewBitmap = NULL; -} - -bool wxPrintPreview::SetCurrentPage(int pageNum) -{ - return m_pimpl->SetCurrentPage( pageNum ); -} - -int wxPrintPreview::GetCurrentPage() const -{ - return m_pimpl->GetCurrentPage(); -} - -void wxPrintPreview::SetPrintout(wxPrintout *printout) -{ - m_pimpl->SetPrintout( printout ); -} - -wxPrintout *wxPrintPreview::GetPrintout() const -{ - return m_pimpl->GetPrintout(); -} - -wxPrintout *wxPrintPreview::GetPrintoutForPrinting() const -{ - return m_pimpl->GetPrintoutForPrinting(); -} - -void wxPrintPreview::SetFrame(wxFrame *frame) -{ - m_pimpl->SetFrame( frame ); -} - -void wxPrintPreview::SetCanvas(wxPreviewCanvas *canvas) -{ - m_pimpl->SetCanvas( canvas ); -} - -wxFrame *wxPrintPreview::GetFrame() const -{ - return m_pimpl->GetFrame(); -} - -wxPreviewCanvas *wxPrintPreview::GetCanvas() const -{ - return m_pimpl->GetCanvas(); -} - -bool wxPrintPreview::PaintPage(wxPreviewCanvas *canvas, wxDC& dc) -{ - return m_pimpl->PaintPage( canvas, dc ); -} - -bool wxPrintPreview::DrawBlankPage(wxPreviewCanvas *canvas, wxDC& dc) -{ - return m_pimpl->DrawBlankPage( canvas, dc ); -} - -void wxPrintPreview::AdjustScrollbars(wxPreviewCanvas *canvas) -{ - m_pimpl->AdjustScrollbars( canvas ); -} - -bool wxPrintPreview::RenderPage(int pageNum) -{ - return m_pimpl->RenderPage( pageNum ); -} - -void wxPrintPreview::SetZoom(int percent) -{ - m_pimpl->SetZoom( percent ); -} - -int wxPrintPreview::GetZoom() const -{ - return m_pimpl->GetZoom(); -} - -wxPrintDialogData& wxPrintPreview::GetPrintDialogData() -{ - return m_pimpl->GetPrintDialogData(); -} - -int wxPrintPreview::GetMaxPage() const -{ - return m_pimpl->GetMaxPage(); -} - -int wxPrintPreview::GetMinPage() const -{ - return m_pimpl->GetMinPage(); -} - -bool wxPrintPreview::IsOk() const -{ - return m_pimpl->Ok(); -} - -void wxPrintPreview::SetOk(bool ok) -{ - m_pimpl->SetOk( ok ); -} - -bool wxPrintPreview::Print(bool interactive) -{ - return m_pimpl->Print( interactive ); -} - -void wxPrintPreview::DetermineScaling() -{ - m_pimpl->DetermineScaling(); -} - -//---------------------------------------------------------------------------- -// experimental backport of high-quality preview on Windows -//---------------------------------------------------------------------------- - -#if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW -static bool RenderPageIntoBitmapHQ(wxPrintPreviewBase *preview, - RenderPageIntoDCFunc RenderPageIntoDC, - wxBitmap& bmp, int pageNum) -{ - // The preview, as implemented in wxPrintPreviewBase (and as used prior to - // wx3) is inexact: it uses screen DC, which has much lower resolution and - // has other properties different from printer DC, so the preview is not - // quite right. - // - // To make matters worse, if the application depends heavily on - // GetTextExtent() or does text layout itself, the output in preview and on - // paper can be very different. In particular, wxHtmlEasyPrinting is - // affected and the preview can be easily off by several pages. - // - // To fix this, we render the preview into high-resolution enhanced - // metafile with properties identical to the printer DC. This guarantees - // metrics correctness while still being fast. - - - // print the preview into a metafile: - wxPrinterDC printerDC(preview->GetPrintDialogData().GetPrintData()); - wxEnhMetaFileDC metaDC(printerDC, - wxEmptyString, - printerDC.GetSize().x, printerDC.GetSize().y); - - if ( !(preview->*RenderPageIntoDC)(metaDC, pageNum) ) - return false; - - wxEnhMetaFile *metafile = metaDC.Close(); - if ( !metafile ) - return false; - - // now render the metafile: - wxMemoryDC bmpDC; - bmpDC.SelectObject(bmp); - bmpDC.Clear(); - - wxRect outRect(0, 0, bmp.GetWidth(), bmp.GetHeight()); - metafile->Play(&bmpDC, &outRect); - - - delete metafile; - - // TODO: we should keep the metafile and reuse it when changing zoom level - - return true; -} -#endif // wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW - -#endif // wxUSE_PRINTING_ARCHITECTURE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/prntbase.cpp +// Purpose: Printing framework base class implementation +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: prntbase.cpp 60850 2009-06-01 10:16:13Z JS $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_PRINTING_ARCHITECTURE + +// change this to 1 to use experimental high-quality printing on Windows +// (NB: this can't be in msw/printwin.cpp because of binary compatibility) +#define wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW 0 + +#if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW + #if !defined(__WXMSW__) || !wxUSE_IMAGE || !wxUSE_WXDIB + #undef wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW + #define wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW 0 + #endif +#endif + +#if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW +#include "wx/msw/enhmeta.h" +#endif + +#if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW && !wxUSE_ENH_METAFILE_FROM_DC +#error Please set wxUSE_ENH_METAFILE_FROM_DC to 1 in include/wx/msw/enhmeta.h. +#endif + +#include "wx/dcprint.h" + +#ifndef WX_PRECOMP + #if defined(__WXMSW__) + #include "wx/msw/wrapcdlg.h" + #endif // MSW + #include "wx/utils.h" + #include "wx/dc.h" + #include "wx/app.h" + #include "wx/math.h" + #include "wx/msgdlg.h" + #include "wx/layout.h" + #include "wx/choice.h" + #include "wx/button.h" + #include "wx/settings.h" + #include "wx/dcmemory.h" + #include "wx/stattext.h" + #include "wx/intl.h" + #include "wx/textdlg.h" + #include "wx/sizer.h" + #include "wx/module.h" +#endif // !WX_PRECOMP + +#include "wx/prntbase.h" +#include "wx/printdlg.h" +#include "wx/print.h" +#include "wx/dcprint.h" + +#include +#include + +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) +#include "wx/msw/printdlg.h" +#elif defined(__WXMAC__) +#include "wx/mac/printdlg.h" +#include "wx/mac/private/print.h" +#else +#include "wx/generic/prntdlgg.h" +#include "wx/dcps.h" +#endif + +#ifdef __WXMSW__ + #ifndef __WIN32__ + #include + #endif +#endif // __WXMSW__ + +#if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW + +#include "wx/msw/dib.h" +#include "wx/image.h" + +typedef bool (wxPrintPreviewBase::*RenderPageIntoDCFunc)(wxDC&, int); +static bool RenderPageIntoBitmapHQ(wxPrintPreviewBase *preview, + RenderPageIntoDCFunc RenderPageIntoDC, + wxBitmap& bmp, int pageNum); +#endif // wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW + +//---------------------------------------------------------------------------- +// wxPrintFactory +//---------------------------------------------------------------------------- + +wxPrintFactory *wxPrintFactory::m_factory = NULL; + +void wxPrintFactory::SetPrintFactory( wxPrintFactory *factory ) +{ + if (wxPrintFactory::m_factory) + delete wxPrintFactory::m_factory; + + wxPrintFactory::m_factory = factory; +} + +wxPrintFactory *wxPrintFactory::GetFactory() +{ + if (!wxPrintFactory::m_factory) + wxPrintFactory::m_factory = new wxNativePrintFactory; + + return wxPrintFactory::m_factory; +} + +//---------------------------------------------------------------------------- +// wxNativePrintFactory +//---------------------------------------------------------------------------- + +wxPrinterBase *wxNativePrintFactory::CreatePrinter( wxPrintDialogData *data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxWindowsPrinter( data ); +#elif defined(__WXMAC__) + return new wxMacPrinter( data ); +#elif defined(__WXPM__) + return new wxOS2Printer( data ); +#else + return new wxPostScriptPrinter( data ); +#endif +} + +wxPrintPreviewBase *wxNativePrintFactory::CreatePrintPreview( wxPrintout *preview, + wxPrintout *printout, wxPrintDialogData *data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxWindowsPrintPreview( preview, printout, data ); +#elif defined(__WXMAC__) + return new wxMacPrintPreview( preview, printout, data ); +#elif defined(__WXPM__) + return new wxOS2PrintPreview( preview, printout, data ); +#else + return new wxPostScriptPrintPreview( preview, printout, data ); +#endif +} + +wxPrintPreviewBase *wxNativePrintFactory::CreatePrintPreview( wxPrintout *preview, + wxPrintout *printout, wxPrintData *data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxWindowsPrintPreview( preview, printout, data ); +#elif defined(__WXMAC__) + return new wxMacPrintPreview( preview, printout, data ); +#elif defined(__WXPM__) + return new wxOS2PrintPreview( preview, printout, data ); +#else + return new wxPostScriptPrintPreview( preview, printout, data ); +#endif +} + +wxPrintDialogBase *wxNativePrintFactory::CreatePrintDialog( wxWindow *parent, + wxPrintDialogData *data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxWindowsPrintDialog( parent, data ); +#elif defined(__WXMAC__) + return new wxMacPrintDialog( parent, data ); +#else + return new wxGenericPrintDialog( parent, data ); +#endif +} + +wxPrintDialogBase *wxNativePrintFactory::CreatePrintDialog( wxWindow *parent, + wxPrintData *data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxWindowsPrintDialog( parent, data ); +#elif defined(__WXMAC__) + return new wxMacPrintDialog( parent, data ); +#else + return new wxGenericPrintDialog( parent, data ); +#endif +} + +wxPageSetupDialogBase *wxNativePrintFactory::CreatePageSetupDialog( wxWindow *parent, + wxPageSetupDialogData *data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxWindowsPageSetupDialog( parent, data ); +#elif defined(__WXMAC__) + return new wxMacPageSetupDialog( parent, data ); +#else + return new wxGenericPageSetupDialog( parent, data ); +#endif +} + +bool wxNativePrintFactory::HasPrintSetupDialog() +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return false; +#elif defined(__WXMAC__) + return false; +#else + // Only here do we need to provide the print setup + // dialog ourselves, the other platforms either have + // none, don't make it accessible or let you configure + // the printer from the wxPrintDialog anyway. + return true; +#endif + +} + +wxDialog *wxNativePrintFactory::CreatePrintSetupDialog( wxWindow *parent, + wxPrintData *data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + wxUnusedVar(parent); + wxUnusedVar(data); + return NULL; +#elif defined(__WXMAC__) + wxUnusedVar(parent); + wxUnusedVar(data); + return NULL; +#else + // Only here do we need to provide the print setup + // dialog ourselves, the other platforms either have + // none, don't make it accessible or let you configure + // the printer from the wxPrintDialog anyway. + return new wxGenericPrintSetupDialog( parent, data ); +#endif +} + +wxDC* wxNativePrintFactory::CreatePrinterDC( const wxPrintData& data ) +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxPrinterDC(data); +#elif defined(__WXMAC__) + return new wxPrinterDC(data); +#else + return new wxPostScriptDC(data); +#endif +} + +bool wxNativePrintFactory::HasOwnPrintToFile() +{ + // Only relevant for PostScript and here the + // setup dialog provides no "print to file" + // option. In the GNOME setup dialog, the + // setup dialog has its own print to file. + return false; +} + +bool wxNativePrintFactory::HasPrinterLine() +{ + // Only relevant for PostScript for now + return true; +} + +wxString wxNativePrintFactory::CreatePrinterLine() +{ + // Only relevant for PostScript for now + + // We should query "lpstat -d" here + return _("Generic PostScript"); +} + +bool wxNativePrintFactory::HasStatusLine() +{ + // Only relevant for PostScript for now + return true; +} + +wxString wxNativePrintFactory::CreateStatusLine() +{ + // Only relevant for PostScript for now + + // We should query "lpstat -r" or "lpstat -p" here + return _("Ready"); +} + +wxPrintNativeDataBase *wxNativePrintFactory::CreatePrintNativeData() +{ +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + return new wxWindowsPrintNativeData; +#elif defined(__WXMAC__) + return new wxMacCarbonPrintData; +#else + return new wxPostScriptPrintNativeData; +#endif +} + +//---------------------------------------------------------------------------- +// wxPrintNativeDataBase +//---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxPrintNativeDataBase, wxObject) + +wxPrintNativeDataBase::wxPrintNativeDataBase() +{ + m_ref = 1; +} + +//---------------------------------------------------------------------------- +// wxPrintFactoryModule +//---------------------------------------------------------------------------- + +class wxPrintFactoryModule: public wxModule +{ +public: + wxPrintFactoryModule() {} + bool OnInit() { return true; } + void OnExit() { wxPrintFactory::SetPrintFactory( NULL ); } + +private: + DECLARE_DYNAMIC_CLASS(wxPrintFactoryModule) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxPrintFactoryModule, wxModule) + +//---------------------------------------------------------------------------- +// wxPrinterBase +//---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPrinterBase, wxObject) + +wxPrinterBase::wxPrinterBase(wxPrintDialogData *data) +{ + m_currentPrintout = (wxPrintout *) NULL; + sm_abortWindow = (wxWindow *) NULL; + sm_abortIt = false; + if (data) + m_printDialogData = (*data); + sm_lastError = wxPRINTER_NO_ERROR; +} + +wxWindow *wxPrinterBase::sm_abortWindow = (wxWindow *) NULL; +bool wxPrinterBase::sm_abortIt = false; +wxPrinterError wxPrinterBase::sm_lastError = wxPRINTER_NO_ERROR; + +wxPrinterBase::~wxPrinterBase() +{ +} + +wxWindow *wxPrinterBase::CreateAbortWindow(wxWindow *parent, wxPrintout * printout) +{ + wxPrintAbortDialog *dialog = new wxPrintAbortDialog(parent, _("Printing ") , wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE); + + wxBoxSizer *button_sizer = new wxBoxSizer( wxVERTICAL ); + button_sizer->Add( new wxStaticText(dialog, wxID_ANY, _("Please wait while printing\n") + printout->GetTitle() ), 0, wxALL, 10 ); + button_sizer->Add( new wxButton( dialog, wxID_CANCEL, wxT("Cancel") ), 0, wxALL | wxALIGN_CENTER, 10 ); + + dialog->SetAutoLayout( true ); + dialog->SetSizer( button_sizer ); + + button_sizer->Fit(dialog); + button_sizer->SetSizeHints (dialog) ; + + return dialog; +} + +void wxPrinterBase::ReportError(wxWindow *parent, wxPrintout *WXUNUSED(printout), const wxString& message) +{ + wxMessageBox(message, _("Printing Error"), wxOK, parent); +} + +wxPrintDialogData& wxPrinterBase::GetPrintDialogData() const +{ + return (wxPrintDialogData&) m_printDialogData; +} + +//---------------------------------------------------------------------------- +// wxPrinter +//---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPrinter, wxPrinterBase) + +wxPrinter::wxPrinter(wxPrintDialogData *data) +{ + m_pimpl = wxPrintFactory::GetFactory()->CreatePrinter( data ); +} + +wxPrinter::~wxPrinter() +{ + delete m_pimpl; +} + +wxWindow *wxPrinter::CreateAbortWindow(wxWindow *parent, wxPrintout *printout) +{ + return m_pimpl->CreateAbortWindow( parent, printout ); +} + +void wxPrinter::ReportError(wxWindow *parent, wxPrintout *printout, const wxString& message) +{ + m_pimpl->ReportError( parent, printout, message ); +} + +bool wxPrinter::Setup(wxWindow *parent) +{ + return m_pimpl->Setup( parent ); +} + +bool wxPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt) +{ + return m_pimpl->Print( parent, printout, prompt ); +} + +wxDC* wxPrinter::PrintDialog(wxWindow *parent) +{ + return m_pimpl->PrintDialog( parent ); +} + +wxPrintDialogData& wxPrinter::GetPrintDialogData() const +{ + return m_pimpl->GetPrintDialogData(); +} + +// --------------------------------------------------------------------------- +// wxPrintDialogBase: the dialog for printing. +// --------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxPrintDialogBase, wxDialog) + +wxPrintDialogBase::wxPrintDialogBase(wxWindow *parent, + wxWindowID id, + const wxString &title, + const wxPoint &pos, + const wxSize &size, + long style) + : wxDialog( parent, id, title.empty() ? wxString(_("Print")) : title, + pos, size, style ) +{ +} + +// --------------------------------------------------------------------------- +// wxPrintDialog: the dialog for printing +// --------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPrintDialog, wxObject) + +wxPrintDialog::wxPrintDialog(wxWindow *parent, wxPrintDialogData* data) +{ + m_pimpl = wxPrintFactory::GetFactory()->CreatePrintDialog( parent, data ); +} + +wxPrintDialog::wxPrintDialog(wxWindow *parent, wxPrintData* data) +{ + m_pimpl = wxPrintFactory::GetFactory()->CreatePrintDialog( parent, data ); +} + +wxPrintDialog::~wxPrintDialog() +{ + delete m_pimpl; +} + +int wxPrintDialog::ShowModal() +{ + return m_pimpl->ShowModal(); +} + +wxPrintDialogData& wxPrintDialog::GetPrintDialogData() +{ + return m_pimpl->GetPrintDialogData(); +} + +wxPrintData& wxPrintDialog::GetPrintData() +{ + return m_pimpl->GetPrintData(); +} + +wxDC *wxPrintDialog::GetPrintDC() +{ + return m_pimpl->GetPrintDC(); +} + +// --------------------------------------------------------------------------- +// wxPageSetupDialogBase: the page setup dialog +// --------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxPageSetupDialogBase, wxDialog) + +wxPageSetupDialogBase::wxPageSetupDialogBase(wxWindow *parent, + wxWindowID id, + const wxString &title, + const wxPoint &pos, + const wxSize &size, + long style) + : wxDialog( parent, id, title.empty() ? wxString(_("Page setup")) : title, + pos, size, style ) +{ +} + +// --------------------------------------------------------------------------- +// wxPageSetupDialog: the page setup dialog +// --------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPageSetupDialog, wxObject) + +wxPageSetupDialog::wxPageSetupDialog(wxWindow *parent, wxPageSetupDialogData *data ) +{ + m_pimpl = wxPrintFactory::GetFactory()->CreatePageSetupDialog( parent, data ); +} + +wxPageSetupDialog::~wxPageSetupDialog() +{ + delete m_pimpl; +} + +int wxPageSetupDialog::ShowModal() +{ + return m_pimpl->ShowModal(); +} + +wxPageSetupDialogData& wxPageSetupDialog::GetPageSetupDialogData() +{ + return m_pimpl->GetPageSetupDialogData(); +} + +// old name +wxPageSetupDialogData& wxPageSetupDialog::GetPageSetupData() +{ + return m_pimpl->GetPageSetupDialogData(); +} + +//---------------------------------------------------------------------------- +// wxPrintAbortDialog +//---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxPrintAbortDialog, wxDialog) + EVT_BUTTON(wxID_CANCEL, wxPrintAbortDialog::OnCancel) +END_EVENT_TABLE() + +void wxPrintAbortDialog::OnCancel(wxCommandEvent& WXUNUSED(event)) +{ + wxPrinterBase::sm_abortIt = true; + wxPrinterBase::sm_abortWindow->Show(false); + wxPrinterBase::sm_abortWindow->Close(true); + wxPrinterBase::sm_abortWindow->Destroy(); + wxPrinterBase::sm_abortWindow = (wxWindow *) NULL; +} + +//---------------------------------------------------------------------------- +// wxPrintout +//---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxPrintout, wxObject) + +wxPrintout::wxPrintout(const wxString& title) +{ + m_printoutTitle = title ; + m_printoutDC = (wxDC *) NULL; + m_pageWidthMM = 0; + m_pageHeightMM = 0; + m_pageWidthPixels = 0; + m_pageHeightPixels = 0; + m_PPIScreenX = 0; + m_PPIScreenY = 0; + m_PPIPrinterX = 0; + m_PPIPrinterY = 0; + m_isPreview = false; +} + +wxPrintout::~wxPrintout() +{ +} + +bool wxPrintout::OnBeginDocument(int WXUNUSED(startPage), int WXUNUSED(endPage)) +{ + return GetDC()->StartDoc(_("Printing ") + m_printoutTitle); +} + +void wxPrintout::OnEndDocument() +{ + GetDC()->EndDoc(); +} + +void wxPrintout::OnBeginPrinting() +{ +} + +void wxPrintout::OnEndPrinting() +{ +} + +bool wxPrintout::HasPage(int page) +{ + return (page == 1); +} + +void wxPrintout::GetPageInfo(int *minPage, int *maxPage, int *fromPage, int *toPage) +{ + *minPage = 1; + *maxPage = 32000; + *fromPage = 1; + *toPage = 1; +} + +void wxPrintout::FitThisSizeToPaper(const wxSize& imageSize) +{ + // Set the DC scale and origin so that the given image size fits within the + // entire page and the origin is at the top left corner of the page. Note + // that with most printers, portions of the page will be non-printable. Use + // this if you're managing your own page margins. + if (!m_printoutDC) return; + wxRect paperRect = GetPaperRectPixels(); + wxCoord pw, ph; + GetPageSizePixels(&pw, &ph); + wxCoord w, h; + m_printoutDC->GetSize(&w, &h); + float scaleX = ((float(paperRect.width) * w) / (float(pw) * imageSize.x)); + float scaleY = ((float(paperRect.height) * h) / (float(ph) * imageSize.y)); + float actualScale = wxMin(scaleX, scaleY); + m_printoutDC->SetUserScale(actualScale, actualScale); + m_printoutDC->SetDeviceOrigin(0, 0); + wxRect logicalPaperRect = GetLogicalPaperRect(); + SetLogicalOrigin(logicalPaperRect.x, logicalPaperRect.y); +} + +void wxPrintout::FitThisSizeToPage(const wxSize& imageSize) +{ + // Set the DC scale and origin so that the given image size fits within the + // printable area of the page and the origin is at the top left corner of + // the printable area. + if (!m_printoutDC) return; + int w, h; + m_printoutDC->GetSize(&w, &h); + float scaleX = float(w) / imageSize.x; + float scaleY = float(h) / imageSize.y; + float actualScale = wxMin(scaleX, scaleY); + m_printoutDC->SetUserScale(actualScale, actualScale); + m_printoutDC->SetDeviceOrigin(0, 0); +} + +void wxPrintout::FitThisSizeToPageMargins(const wxSize& imageSize, const wxPageSetupDialogData& pageSetupData) +{ + // Set the DC scale and origin so that the given image size fits within the + // page margins defined in the given wxPageSetupDialogData object and the + // origin is at the top left corner of the page margins. + if (!m_printoutDC) return; + wxRect paperRect = GetPaperRectPixels(); + wxCoord pw, ph; + GetPageSizePixels(&pw, &ph); + wxPoint topLeft = pageSetupData.GetMarginTopLeft(); + wxPoint bottomRight = pageSetupData.GetMarginBottomRight(); + wxCoord mw, mh; + GetPageSizeMM(&mw, &mh); + float mmToDeviceX = float(pw) / mw; + float mmToDeviceY = float(ph) / mh; + wxRect pageMarginsRect(paperRect.x + wxRound(mmToDeviceX * topLeft.x), + paperRect.y + wxRound(mmToDeviceY * topLeft.y), + paperRect.width - wxRound(mmToDeviceX * (topLeft.x + bottomRight.x)), + paperRect.height - wxRound(mmToDeviceY * (topLeft.y + bottomRight.y))); + wxCoord w, h; + m_printoutDC->GetSize(&w, &h); + float scaleX = (float(pageMarginsRect.width) * w) / (float(pw) * imageSize.x); + float scaleY = (float(pageMarginsRect.height) * h) / (float(ph) * imageSize.y); + float actualScale = wxMin(scaleX, scaleY); + m_printoutDC->SetUserScale(actualScale, actualScale); + m_printoutDC->SetDeviceOrigin(0, 0); + wxRect logicalPageMarginsRect = GetLogicalPageMarginsRect(pageSetupData); + SetLogicalOrigin(logicalPageMarginsRect.x, logicalPageMarginsRect.y); +} + +void wxPrintout::MapScreenSizeToPaper() +{ + // Set the DC scale so that an image on the screen is the same size on the + // paper and the origin is at the top left of the paper. Note that with most + // printers, portions of the page will be cut off. Use this if you're + // managing your own page margins. + if (!m_printoutDC) return; + MapScreenSizeToPage(); + wxRect logicalPaperRect = GetLogicalPaperRect(); + SetLogicalOrigin(logicalPaperRect.x, logicalPaperRect.y); +} + +void wxPrintout::MapScreenSizeToPage() +{ + // Set the DC scale and origin so that an image on the screen is the same + // size on the paper and the origin is at the top left of the printable area. + if (!m_printoutDC) return; + int ppiScreenX, ppiScreenY; + GetPPIScreen(&ppiScreenX, &ppiScreenY); + int ppiPrinterX, ppiPrinterY; + GetPPIPrinter(&ppiPrinterX, &ppiPrinterY); + int w, h; + m_printoutDC->GetSize(&w, &h); + int pageSizePixelsX, pageSizePixelsY; + GetPageSizePixels(&pageSizePixelsX, &pageSizePixelsY); + float userScaleX = (float(ppiPrinterX) * w) / (float(ppiScreenX) * pageSizePixelsX); + float userScaleY = (float(ppiPrinterY) * h) / (float(ppiScreenY) * pageSizePixelsY); + m_printoutDC->SetUserScale(userScaleX, userScaleY); + m_printoutDC->SetDeviceOrigin(0, 0); +} + +void wxPrintout::MapScreenSizeToPageMargins(const wxPageSetupDialogData& pageSetupData) +{ + // Set the DC scale so that an image on the screen is the same size on the + // paper and the origin is at the top left of the page margins defined by + // the given wxPageSetupDialogData object. + if (!m_printoutDC) return; + MapScreenSizeToPage(); + wxRect logicalPageMarginsRect = GetLogicalPageMarginsRect(pageSetupData); + SetLogicalOrigin(logicalPageMarginsRect.x, logicalPageMarginsRect.y); +} + +void wxPrintout::MapScreenSizeToDevice() +{ + // Set the DC scale so that a screen pixel is the same size as a device + // pixel and the origin is at the top left of the printable area. + if (!m_printoutDC) return; + int w, h; + m_printoutDC->GetSize(&w, &h); + int pageSizePixelsX, pageSizePixelsY; + GetPageSizePixels(&pageSizePixelsX, &pageSizePixelsY); + float userScaleX = float(w) / pageSizePixelsX; + float userScaleY = float(h) / pageSizePixelsY; + m_printoutDC->SetUserScale(userScaleX, userScaleY); + m_printoutDC->SetDeviceOrigin(0, 0); +} + +wxRect wxPrintout::GetLogicalPaperRect() const +{ + // Return the rectangle in logical units that corresponds to the paper + // rectangle. + wxRect paperRect = GetPaperRectPixels(); + wxCoord pw, ph; + GetPageSizePixels(&pw, &ph); + wxCoord w, h; + m_printoutDC->GetSize(&w, &h); + if (w == pw && h == ph) { + // this DC matches the printed page, so no scaling + return wxRect(m_printoutDC->DeviceToLogicalX(paperRect.x), + m_printoutDC->DeviceToLogicalY(paperRect.y), + m_printoutDC->DeviceToLogicalXRel(paperRect.width), + m_printoutDC->DeviceToLogicalYRel(paperRect.height)); + } + // This DC doesn't match the printed page, so we have to scale. + float scaleX = float(w) / pw; + float scaleY = float(h) / ph; + return wxRect(m_printoutDC->DeviceToLogicalX(wxRound(paperRect.x * scaleX)), + m_printoutDC->DeviceToLogicalY(wxRound(paperRect.y * scaleY)), + m_printoutDC->DeviceToLogicalXRel(wxRound(paperRect.width * scaleX)), + m_printoutDC->DeviceToLogicalYRel(wxRound(paperRect.height * scaleY))); +} + +wxRect wxPrintout::GetLogicalPageRect() const +{ + // Return the rectangle in logical units that corresponds to the printable + // area. + int w, h; + m_printoutDC->GetSize(&w, &h); + return wxRect(m_printoutDC->DeviceToLogicalX(0), + m_printoutDC->DeviceToLogicalY(0), + m_printoutDC->DeviceToLogicalXRel(w), + m_printoutDC->DeviceToLogicalYRel(h)); +} + +wxRect wxPrintout::GetLogicalPageMarginsRect(const wxPageSetupDialogData& pageSetupData) const +{ + // Return the rectangle in logical units that corresponds to the region + // within the page margins as specified by the given wxPageSetupDialogData + // object. + wxRect paperRect = GetPaperRectPixels(); + wxCoord pw, ph; + GetPageSizePixels(&pw, &ph); + wxPoint topLeft = pageSetupData.GetMarginTopLeft(); + wxPoint bottomRight = pageSetupData.GetMarginBottomRight(); + wxCoord mw, mh; + GetPageSizeMM(&mw, &mh); + float mmToDeviceX = float(pw) / mw; + float mmToDeviceY = float(ph) / mh; + wxRect pageMarginsRect(paperRect.x + wxRound(mmToDeviceX * topLeft.x), + paperRect.y + wxRound(mmToDeviceY * topLeft.y), + paperRect.width - wxRound(mmToDeviceX * (topLeft.x + bottomRight.x)), + paperRect.height - wxRound(mmToDeviceY * (topLeft.y + bottomRight.y))); + wxCoord w, h; + m_printoutDC->GetSize(&w, &h); + if (w == pw && h == ph) { + // this DC matches the printed page, so no scaling + return wxRect(m_printoutDC->DeviceToLogicalX(pageMarginsRect.x), + m_printoutDC->DeviceToLogicalY(pageMarginsRect.y), + m_printoutDC->DeviceToLogicalXRel(pageMarginsRect.width), + m_printoutDC->DeviceToLogicalYRel(pageMarginsRect.height)); + } + // This DC doesn't match the printed page, so we have to scale. + float scaleX = float(w) / pw; + float scaleY = float(h) / ph; + return wxRect(m_printoutDC->DeviceToLogicalX(wxRound(pageMarginsRect.x * scaleX)), + m_printoutDC->DeviceToLogicalY(wxRound(pageMarginsRect.y * scaleY)), + m_printoutDC->DeviceToLogicalXRel(wxRound(pageMarginsRect.width * scaleX)), + m_printoutDC->DeviceToLogicalYRel(wxRound(pageMarginsRect.height * scaleY))); +} + +void wxPrintout::SetLogicalOrigin(wxCoord x, wxCoord y) +{ + // Set the device origin by specifying a point in logical coordinates. + m_printoutDC->SetDeviceOrigin(m_printoutDC->LogicalToDeviceX(x), + m_printoutDC->LogicalToDeviceY(y)); +} + +void wxPrintout::OffsetLogicalOrigin(wxCoord xoff, wxCoord yoff) +{ + // Offset the device origin by a specified distance in device coordinates. + wxCoord x = m_printoutDC->LogicalToDeviceX(0); + wxCoord y = m_printoutDC->LogicalToDeviceY(0); + m_printoutDC->SetDeviceOrigin(x + m_printoutDC->LogicalToDeviceXRel(xoff), + y + m_printoutDC->LogicalToDeviceYRel(yoff)); +} + + +//---------------------------------------------------------------------------- +// wxPreviewCanvas +//---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPreviewCanvas, wxWindow) + +BEGIN_EVENT_TABLE(wxPreviewCanvas, wxScrolledWindow) + EVT_PAINT(wxPreviewCanvas::OnPaint) + EVT_CHAR(wxPreviewCanvas::OnChar) + EVT_SYS_COLOUR_CHANGED(wxPreviewCanvas::OnSysColourChanged) +#if wxUSE_MOUSEWHEEL + EVT_MOUSEWHEEL(wxPreviewCanvas::OnMouseWheel) +#endif +END_EVENT_TABLE() + +// VZ: the current code doesn't refresh properly without +// wxFULL_REPAINT_ON_RESIZE, this must be fixed as otherwise we have +// really horrible flicker when resizing the preview frame, but without +// this style it simply doesn't work correctly at all... +wxPreviewCanvas::wxPreviewCanvas(wxPrintPreviewBase *preview, wxWindow *parent, + const wxPoint& pos, const wxSize& size, long style, const wxString& name): +wxScrolledWindow(parent, wxID_ANY, pos, size, style | wxFULL_REPAINT_ON_RESIZE, name) +{ + m_printPreview = preview; +#ifdef __WXMAC__ + // The app workspace colour is always white, but we should have + // a contrast with the page. + wxSystemColour colourIndex = wxSYS_COLOUR_3DDKSHADOW; +#elif defined(__WXGTK__) + wxSystemColour colourIndex = wxSYS_COLOUR_BTNFACE; +#else + wxSystemColour colourIndex = wxSYS_COLOUR_APPWORKSPACE; +#endif + SetBackgroundColour(wxSystemSettings::GetColour(colourIndex)); + + SetScrollbars(10, 10, 100, 100); +} + +wxPreviewCanvas::~wxPreviewCanvas() +{ +} + +void wxPreviewCanvas::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + wxPaintDC dc(this); + PrepareDC( dc ); + +/* +#ifdef __WXGTK__ + if (!GetUpdateRegion().IsEmpty()) + dc.SetClippingRegion( GetUpdateRegion() ); +#endif +*/ + + if (m_printPreview) + { + m_printPreview->PaintPage(this, dc); + } +} + +// Responds to colour changes, and passes event on to children. +void wxPreviewCanvas::OnSysColourChanged(wxSysColourChangedEvent& event) +{ +#ifdef __WXMAC__ + // The app workspace colour is always white, but we should have + // a contrast with the page. + wxSystemColour colourIndex = wxSYS_COLOUR_3DDKSHADOW; +#elif defined(__WXGTK__) + wxSystemColour colourIndex = wxSYS_COLOUR_BTNFACE; +#else + wxSystemColour colourIndex = wxSYS_COLOUR_APPWORKSPACE; +#endif + SetBackgroundColour(wxSystemSettings::GetColour(colourIndex)); + Refresh(); + + // Propagate the event to the non-top-level children + wxWindow::OnSysColourChanged(event); +} + +void wxPreviewCanvas::OnChar(wxKeyEvent &event) +{ + wxPreviewControlBar* controlBar = ((wxPreviewFrame*) GetParent())->GetControlBar(); + if (event.GetKeyCode() == WXK_ESCAPE) + { + ((wxPreviewFrame*) GetParent())->Close(true); + return; + } + else if (event.GetKeyCode() == WXK_TAB) + { + controlBar->OnGoto(); + return; + } + else if (event.GetKeyCode() == WXK_RETURN) + { + controlBar->OnPrint(); + return; + } + + if (!event.ControlDown()) + { + event.Skip(); + return; + } + + switch(event.GetKeyCode()) + { + case WXK_PAGEDOWN: + controlBar->OnNext(); break; + case WXK_PAGEUP: + controlBar->OnPrevious(); break; + case WXK_HOME: + controlBar->OnFirst(); break; + case WXK_END: + controlBar->OnLast(); break; + default: + event.Skip(); + } +} + +#if wxUSE_MOUSEWHEEL + +void wxPreviewCanvas::OnMouseWheel(wxMouseEvent& event) +{ + wxPreviewControlBar * + controlBar = wxStaticCast(GetParent(), wxPreviewFrame)->GetControlBar(); + + if ( controlBar ) + { + if ( event.ControlDown() && event.GetWheelRotation() != 0 ) + { + int currentZoom = controlBar->GetZoomControl(); + + int delta; + if ( currentZoom < 100 ) + delta = 5; + else if ( currentZoom <= 120 ) + delta = 10; + else + delta = 50; + + if ( event.GetWheelRotation() > 0 ) + delta = -delta; + + int newZoom = currentZoom + delta; + if ( newZoom < 10 ) + newZoom = 10; + if ( newZoom > 200 ) + newZoom = 200; + if ( newZoom != currentZoom ) + { + controlBar->SetZoomControl(newZoom); + m_printPreview->SetZoom(newZoom); + Refresh(); + } + return; + } + } + + event.Skip(); +} + +#endif // wxUSE_MOUSEWHEEL + +//---------------------------------------------------------------------------- +// wxPreviewControlBar +//---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPreviewControlBar, wxWindow) + +BEGIN_EVENT_TABLE(wxPreviewControlBar, wxPanel) + EVT_BUTTON(wxID_PREVIEW_CLOSE, wxPreviewControlBar::OnWindowClose) + EVT_BUTTON(wxID_PREVIEW_PRINT, wxPreviewControlBar::OnPrintButton) + EVT_BUTTON(wxID_PREVIEW_PREVIOUS, wxPreviewControlBar::OnPreviousButton) + EVT_BUTTON(wxID_PREVIEW_NEXT, wxPreviewControlBar::OnNextButton) + EVT_BUTTON(wxID_PREVIEW_FIRST, wxPreviewControlBar::OnFirstButton) + EVT_BUTTON(wxID_PREVIEW_LAST, wxPreviewControlBar::OnLastButton) + EVT_BUTTON(wxID_PREVIEW_GOTO, wxPreviewControlBar::OnGotoButton) + EVT_CHOICE(wxID_PREVIEW_ZOOM, wxPreviewControlBar::OnZoom) + EVT_PAINT(wxPreviewControlBar::OnPaint) +END_EVENT_TABLE() + +wxPreviewControlBar::wxPreviewControlBar(wxPrintPreviewBase *preview, long buttons, + wxWindow *parent, const wxPoint& pos, const wxSize& size, + long style, const wxString& name): +wxPanel(parent, wxID_ANY, pos, size, style, name) +{ + m_printPreview = preview; + m_closeButton = (wxButton *) NULL; + m_nextPageButton = (wxButton *) NULL; + m_previousPageButton = (wxButton *) NULL; + m_printButton = (wxButton *) NULL; + m_zoomControl = (wxChoice *) NULL; + m_buttonFlags = buttons; +} + +wxPreviewControlBar::~wxPreviewControlBar() +{ +} + +void wxPreviewControlBar::OnPaint(wxPaintEvent& WXUNUSED(event)) +{ + wxPaintDC dc(this); + + int w, h; + GetSize(&w, &h); + dc.SetPen(*wxBLACK_PEN); + dc.SetBrush(*wxTRANSPARENT_BRUSH); + dc.DrawLine( 0, h-1, w, h-1 ); +} + +void wxPreviewControlBar::OnWindowClose(wxCommandEvent& WXUNUSED(event)) +{ + wxPreviewFrame *frame = (wxPreviewFrame *)GetParent(); + frame->Close(true); +} + +void wxPreviewControlBar::OnPrint(void) +{ + wxPrintPreviewBase *preview = GetPrintPreview(); + preview->Print(true); +} + +void wxPreviewControlBar::OnNext(void) +{ + wxPrintPreviewBase *preview = GetPrintPreview(); + if (preview) + { + int currentPage = preview->GetCurrentPage(); + if ((preview->GetMaxPage() > 0) && + (currentPage < preview->GetMaxPage()) && + preview->GetPrintout()->HasPage(currentPage + 1)) + { + preview->SetCurrentPage(currentPage + 1); + } + } +} + +void wxPreviewControlBar::OnPrevious(void) +{ + wxPrintPreviewBase *preview = GetPrintPreview(); + if (preview) + { + int currentPage = preview->GetCurrentPage(); + if ((preview->GetMinPage() > 0) && + (currentPage > preview->GetMinPage()) && + preview->GetPrintout()->HasPage(currentPage - 1)) + { + preview->SetCurrentPage(currentPage - 1); + } + } +} + +void wxPreviewControlBar::OnFirst(void) +{ + wxPrintPreviewBase *preview = GetPrintPreview(); + if (preview) + { + int currentPage = preview->GetMinPage(); + if (preview->GetPrintout()->HasPage(currentPage)) + { + preview->SetCurrentPage(currentPage); + } + } +} + +void wxPreviewControlBar::OnLast(void) +{ + wxPrintPreviewBase *preview = GetPrintPreview(); + if (preview) + { + int currentPage = preview->GetMaxPage(); + if (preview->GetPrintout()->HasPage(currentPage)) + { + preview->SetCurrentPage(currentPage); + } + } +} + +void wxPreviewControlBar::OnGoto(void) +{ + wxPrintPreviewBase *preview = GetPrintPreview(); + if (preview) + { + long currentPage; + + if (preview->GetMinPage() > 0) + { + wxString strPrompt; + wxString strPage; + + strPrompt.Printf( _("Enter a page number between %d and %d:"), + preview->GetMinPage(), preview->GetMaxPage()); + strPage.Printf( wxT("%d"), preview->GetCurrentPage() ); + + strPage = + wxGetTextFromUser( strPrompt, _("Goto Page"), strPage, GetParent()); + + if ( strPage.ToLong( ¤tPage ) ) + if (preview->GetPrintout()->HasPage(currentPage)) + { + preview->SetCurrentPage(currentPage); + } + } + } +} + +void wxPreviewControlBar::OnZoom(wxCommandEvent& WXUNUSED(event)) +{ + int zoom = GetZoomControl(); + if (GetPrintPreview()) + GetPrintPreview()->SetZoom(zoom); +} + +void wxPreviewControlBar::CreateButtons() +{ + SetSize(0, 0, 400, 40); + + wxBoxSizer *item0 = new wxBoxSizer( wxHORIZONTAL ); + + m_closeButton = new wxButton( this, wxID_PREVIEW_CLOSE, _("&Close"), wxDefaultPosition, wxDefaultSize, 0 ); + item0->Add( m_closeButton, 0, wxALIGN_CENTRE|wxALL, 5 ); + + if (m_buttonFlags & wxPREVIEW_PRINT) + { + m_printButton = new wxButton( this, wxID_PREVIEW_PRINT, _("&Print..."), wxDefaultPosition, wxDefaultSize, 0 ); + item0->Add( m_printButton, 0, wxALIGN_CENTRE|wxALL, 5 ); + } + + // Exact-fit buttons are too tiny on wxUniversal + int navButtonStyle; + wxSize navButtonSize; +#ifdef __WXUNIVERSAL__ + navButtonStyle = 0; + navButtonSize = wxSize(40, m_closeButton->GetSize().y); +#else + navButtonStyle = wxBU_EXACTFIT; + navButtonSize = wxDefaultSize; +#endif + + if (m_buttonFlags & wxPREVIEW_FIRST) + { + m_firstPageButton = new wxButton( this, wxID_PREVIEW_FIRST, _("|<<"), wxDefaultPosition, navButtonSize, navButtonStyle ); + item0->Add( m_firstPageButton, 0, wxALIGN_CENTRE|wxALL, 5 ); + } + + if (m_buttonFlags & wxPREVIEW_PREVIOUS) + { + m_previousPageButton = new wxButton( this, wxID_PREVIEW_PREVIOUS, _("<<"), wxDefaultPosition, navButtonSize, navButtonStyle ); + item0->Add( m_previousPageButton, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 ); + } + + if (m_buttonFlags & wxPREVIEW_NEXT) + { + m_nextPageButton = new wxButton( this, wxID_PREVIEW_NEXT, _(">>"), wxDefaultPosition, navButtonSize, navButtonStyle ); + item0->Add( m_nextPageButton, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 ); + } + + if (m_buttonFlags & wxPREVIEW_LAST) + { + m_lastPageButton = new wxButton( this, wxID_PREVIEW_LAST, _(">>|"), wxDefaultPosition, navButtonSize, navButtonStyle ); + item0->Add( m_lastPageButton, 0, wxALIGN_CENTRE|wxRIGHT|wxTOP|wxBOTTOM, 5 ); + } + + if (m_buttonFlags & wxPREVIEW_GOTO) + { + m_gotoPageButton = new wxButton( this, wxID_PREVIEW_GOTO, _("&Goto..."), wxDefaultPosition, wxDefaultSize, 0 ); + item0->Add( m_gotoPageButton, 0, wxALIGN_CENTRE|wxALL, 5 ); + } + + if (m_buttonFlags & wxPREVIEW_ZOOM) + { + wxString choices[] = + { + wxT("10%"), wxT("15%"), wxT("20%"), wxT("25%"), wxT("30%"), wxT("35%"), wxT("40%"), wxT("45%"), wxT("50%"), wxT("55%"), + wxT("60%"), wxT("65%"), wxT("70%"), wxT("75%"), wxT("80%"), wxT("85%"), wxT("90%"), wxT("95%"), wxT("100%"), wxT("110%"), + wxT("120%"), wxT("150%"), wxT("200%") + }; + int n = WXSIZEOF(choices); + + m_zoomControl = new wxChoice( this, wxID_PREVIEW_ZOOM, wxDefaultPosition, wxSize(70,wxDefaultCoord), n, choices, 0 ); + item0->Add( m_zoomControl, 0, wxALIGN_CENTRE|wxALL, 5 ); + SetZoomControl(m_printPreview->GetZoom()); + } + + SetSizer(item0); + item0->Fit(this); +} + +void wxPreviewControlBar::SetZoomControl(int zoom) +{ + if (m_zoomControl) + { + int n, count = m_zoomControl->GetCount(); + long val; + for (n=0; nGetString(n).BeforeFirst(wxT('%')).ToLong(&val) && + (val >= long(zoom))) + { + m_zoomControl->SetSelection(n); + return; + } + } + + m_zoomControl->SetSelection(count-1); + } +} + +int wxPreviewControlBar::GetZoomControl() +{ + if (m_zoomControl && (m_zoomControl->GetStringSelection() != wxEmptyString)) + { + long val; + if (m_zoomControl->GetStringSelection().BeforeFirst(wxT('%')).ToLong(&val)) + return int(val); + } + + return 0; +} + + +/* +* Preview frame +*/ + +IMPLEMENT_CLASS(wxPreviewFrame, wxFrame) + +BEGIN_EVENT_TABLE(wxPreviewFrame, wxFrame) + EVT_CLOSE(wxPreviewFrame::OnCloseWindow) +END_EVENT_TABLE() + +wxPreviewFrame::wxPreviewFrame(wxPrintPreviewBase *preview, wxWindow *parent, const wxString& title, + const wxPoint& pos, const wxSize& size, long style, const wxString& name): +wxFrame(parent, wxID_ANY, title, pos, size, style, name) +{ + m_printPreview = preview; + m_controlBar = NULL; + m_previewCanvas = NULL; + m_windowDisabler = NULL; + + // Give the application icon +#ifdef __WXMSW__ + wxFrame* topFrame = wxDynamicCast(wxTheApp->GetTopWindow(), wxFrame); + if (topFrame) + SetIcon(topFrame->GetIcon()); +#endif +} + +wxPreviewFrame::~wxPreviewFrame() +{ +} + +void wxPreviewFrame::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) +{ + if (m_windowDisabler) + delete m_windowDisabler; + + // Need to delete the printout and the print preview + wxPrintout *printout = m_printPreview->GetPrintout(); + if (printout) + { + delete printout; + m_printPreview->SetPrintout(NULL); + m_printPreview->SetCanvas(NULL); + m_printPreview->SetFrame(NULL); + } + delete m_printPreview; + + Destroy(); +} + +void wxPreviewFrame::Initialize() +{ +#if wxUSE_STATUSBAR + CreateStatusBar(); +#endif + CreateCanvas(); + CreateControlBar(); + + m_printPreview->SetCanvas(m_previewCanvas); + m_printPreview->SetFrame(this); + + wxBoxSizer *item0 = new wxBoxSizer( wxVERTICAL ); + + item0->Add( m_controlBar, 0, wxGROW|wxALIGN_CENTER_VERTICAL, 5 ); + item0->Add( m_previewCanvas, 1, wxGROW|wxALIGN_CENTER_VERTICAL, 5 ); + + SetAutoLayout( true ); + SetSizer( item0 ); + + m_windowDisabler = new wxWindowDisabler(this); + + Layout(); + + m_printPreview->AdjustScrollbars(m_previewCanvas); + m_previewCanvas->SetFocus(); + m_controlBar->SetFocus(); +} + +void wxPreviewFrame::CreateCanvas() +{ + m_previewCanvas = new wxPreviewCanvas(m_printPreview, this); +} + +void wxPreviewFrame::CreateControlBar() +{ + long buttons = wxPREVIEW_DEFAULT; + if (m_printPreview->GetPrintoutForPrinting()) + buttons |= wxPREVIEW_PRINT; + + m_controlBar = new wxPreviewControlBar(m_printPreview, buttons, this, wxPoint(0,0), wxSize(400, 40)); + m_controlBar->CreateButtons(); +} + +/* +* Print preview +*/ + +IMPLEMENT_CLASS(wxPrintPreviewBase, wxObject) + +wxPrintPreviewBase::wxPrintPreviewBase(wxPrintout *printout, + wxPrintout *printoutForPrinting, + wxPrintData *data) +{ + if (data) + m_printDialogData = (*data); + + Init(printout, printoutForPrinting); +} + +wxPrintPreviewBase::wxPrintPreviewBase(wxPrintout *printout, + wxPrintout *printoutForPrinting, + wxPrintDialogData *data) +{ + if (data) + m_printDialogData = (*data); + + Init(printout, printoutForPrinting); +} + +void wxPrintPreviewBase::Init(wxPrintout *printout, + wxPrintout *printoutForPrinting) +{ + m_isOk = true; + m_previewPrintout = printout; + if (m_previewPrintout) + m_previewPrintout->SetIsPreview(true); + + m_printPrintout = printoutForPrinting; + + m_previewCanvas = NULL; + m_previewFrame = NULL; + m_previewBitmap = NULL; + m_currentPage = 1; + m_currentZoom = 70; + m_topMargin = 40; + m_leftMargin = 40; + m_pageWidth = 0; + m_pageHeight = 0; + m_printingPrepared = false; + m_minPage = 1; + m_maxPage = 1; +} + +wxPrintPreviewBase::~wxPrintPreviewBase() +{ + if (m_previewPrintout) + delete m_previewPrintout; + if (m_previewBitmap) + delete m_previewBitmap; + if (m_printPrintout) + delete m_printPrintout; +} + +bool wxPrintPreviewBase::SetCurrentPage(int pageNum) +{ + if (m_currentPage == pageNum) + return true; + + m_currentPage = pageNum; + if (m_previewBitmap) + { + delete m_previewBitmap; + m_previewBitmap = NULL; + } + + if (m_previewCanvas) + { + AdjustScrollbars(m_previewCanvas); + + if (!RenderPage(pageNum)) + return false; + m_previewCanvas->Refresh(); + m_previewCanvas->SetFocus(); + } + return true; +} + +int wxPrintPreviewBase::GetCurrentPage() const + { return m_currentPage; } +void wxPrintPreviewBase::SetPrintout(wxPrintout *printout) + { m_previewPrintout = printout; } +wxPrintout *wxPrintPreviewBase::GetPrintout() const + { return m_previewPrintout; } +wxPrintout *wxPrintPreviewBase::GetPrintoutForPrinting() const + { return m_printPrintout; } +void wxPrintPreviewBase::SetFrame(wxFrame *frame) + { m_previewFrame = frame; } +void wxPrintPreviewBase::SetCanvas(wxPreviewCanvas *canvas) + { m_previewCanvas = canvas; } +wxFrame *wxPrintPreviewBase::GetFrame() const + { return m_previewFrame; } +wxPreviewCanvas *wxPrintPreviewBase::GetCanvas() const + { return m_previewCanvas; } + +void wxPrintPreviewBase::CalcRects(wxPreviewCanvas *canvas, wxRect& pageRect, wxRect& paperRect) +{ + // Calculate the rectangles for the printable area of the page and the + // entire paper as they appear on the canvas on-screen. + int canvasWidth, canvasHeight; + canvas->GetSize(&canvasWidth, &canvasHeight); + + float zoomScale = float(m_currentZoom) / 100; + float screenPrintableWidth = zoomScale * m_pageWidth * m_previewScaleX; + float screenPrintableHeight = zoomScale * m_pageHeight * m_previewScaleY; + + wxRect devicePaperRect = m_previewPrintout->GetPaperRectPixels(); + wxCoord devicePrintableWidth, devicePrintableHeight; + m_previewPrintout->GetPageSizePixels(&devicePrintableWidth, &devicePrintableHeight); + float scaleX = screenPrintableWidth / devicePrintableWidth; + float scaleY = screenPrintableHeight / devicePrintableHeight; + paperRect.width = wxCoord(scaleX * devicePaperRect.width); + paperRect.height = wxCoord(scaleY * devicePaperRect.height); + + paperRect.x = wxCoord((canvasWidth - paperRect.width)/ 2.0); + if (paperRect.x < m_leftMargin) + paperRect.x = m_leftMargin; + paperRect.y = wxCoord((canvasHeight - paperRect.height)/ 2.0); + if (paperRect.y < m_topMargin) + paperRect.y = m_topMargin; + + pageRect.x = paperRect.x - wxCoord(scaleX * devicePaperRect.x); + pageRect.y = paperRect.y - wxCoord(scaleY * devicePaperRect.y); + pageRect.width = wxCoord(screenPrintableWidth); + pageRect.height = wxCoord(screenPrintableHeight); +} + + +bool wxPrintPreviewBase::PaintPage(wxPreviewCanvas *canvas, wxDC& dc) +{ + DrawBlankPage(canvas, dc); + + if (!m_previewBitmap) + if (!RenderPage(m_currentPage)) + return false; + if (!m_previewBitmap) + return false; + if (!canvas) + return false; + + wxRect pageRect, paperRect; + CalcRects(canvas, pageRect, paperRect); + wxMemoryDC temp_dc; + temp_dc.SelectObject(*m_previewBitmap); + + dc.Blit(pageRect.x, pageRect.y, + m_previewBitmap->GetWidth(), m_previewBitmap->GetHeight(), &temp_dc, 0, 0); + + temp_dc.SelectObject(wxNullBitmap); + return true; +} + +// Adjusts the scrollbars for the current scale +void wxPrintPreviewBase::AdjustScrollbars(wxPreviewCanvas *canvas) +{ + if (!canvas) + return ; + + wxRect pageRect, paperRect; + CalcRects(canvas, pageRect, paperRect); + int totalWidth = paperRect.width + 2 * m_leftMargin; + int totalHeight = paperRect.height + 2 * m_topMargin; + int scrollUnitsX = totalWidth / 10; + int scrollUnitsY = totalHeight / 10; + wxSize virtualSize = canvas->GetVirtualSize(); + if (virtualSize.GetWidth() != totalWidth || virtualSize.GetHeight() != totalHeight) + canvas->SetScrollbars(10, 10, scrollUnitsX, scrollUnitsY, 0, 0, true); +} + +bool wxPrintPreviewBase::RenderPageIntoDC(wxDC& dc, int pageNum) +{ + m_previewPrintout->SetDC(&dc); + m_previewPrintout->SetPageSizePixels(m_pageWidth, m_pageHeight); + + // Need to delay OnPreparePrinting() until here, so we have enough + // information. + if (!m_printingPrepared) + { + m_previewPrintout->OnPreparePrinting(); + int selFrom, selTo; + m_previewPrintout->GetPageInfo(&m_minPage, &m_maxPage, &selFrom, &selTo); + m_printingPrepared = true; + } + + m_previewPrintout->OnBeginPrinting(); + + if (!m_previewPrintout->OnBeginDocument(m_printDialogData.GetFromPage(), m_printDialogData.GetToPage())) + { + wxMessageBox(_("Could not start document preview."), _("Print Preview Failure"), wxOK); + return false; + } + + m_previewPrintout->OnPrintPage(pageNum); + m_previewPrintout->OnEndDocument(); + m_previewPrintout->OnEndPrinting(); + + m_previewPrintout->SetDC(NULL); + + return true; +} + +bool wxPrintPreviewBase::RenderPageIntoBitmap(wxBitmap& bmp, int pageNum) +{ +#if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW + { + if ( RenderPageIntoBitmapHQ(this, + &wxPrintPreviewBase::RenderPageIntoDC, + bmp, pageNum) ) + { + return true; + } + } +#endif // wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW + + wxMemoryDC memoryDC; + memoryDC.SelectObject(bmp); + memoryDC.Clear(); + + return RenderPageIntoDC(memoryDC, pageNum); +} + +bool wxPrintPreviewBase::RenderPage(int pageNum) +{ + wxBusyCursor busy; + + if (!m_previewCanvas) + { + wxFAIL_MSG(_T("wxPrintPreviewBase::RenderPage: must use wxPrintPreviewBase::SetCanvas to let me know about the canvas!")); + return false; + } + + wxRect pageRect, paperRect; + CalcRects(m_previewCanvas, pageRect, paperRect); + + if (!m_previewBitmap) + { + m_previewBitmap = new wxBitmap(pageRect.width, pageRect.height); + + if (!m_previewBitmap || !m_previewBitmap->Ok()) + { + if (m_previewBitmap) { + delete m_previewBitmap; + m_previewBitmap = NULL; + } + wxMessageBox(_("Sorry, not enough memory to create a preview."), _("Print Preview Failure"), wxOK); + return false; + } + } + + if ( !RenderPageIntoBitmap(*m_previewBitmap, pageNum) ) + { + wxMessageBox(_("Could not start document preview."), _("Print Preview Failure"), wxOK); + + delete m_previewBitmap; + m_previewBitmap = NULL; + return false; + } + +#if wxUSE_STATUSBAR + wxString status; + if (m_maxPage != 0) + status = wxString::Format(_("Page %d of %d"), pageNum, m_maxPage); + else + status = wxString::Format(_("Page %d"), pageNum); + + if (m_previewFrame) + m_previewFrame->SetStatusText(status); +#endif + + return true; +} + +bool wxPrintPreviewBase::DrawBlankPage(wxPreviewCanvas *canvas, wxDC& dc) +{ + wxRect pageRect, paperRect; + + CalcRects(canvas, pageRect, paperRect); + + // Draw shadow, allowing for 1-pixel border AROUND the actual paper + wxCoord shadowOffset = 4; + + dc.SetPen(*wxBLACK_PEN); + dc.SetBrush(*wxBLACK_BRUSH); + dc.DrawRectangle(paperRect.x + shadowOffset, paperRect.y + paperRect.height + 1, + paperRect.width, shadowOffset); + + dc.DrawRectangle(paperRect.x + paperRect.width, paperRect.y + shadowOffset, + shadowOffset, paperRect.height); + + // Draw blank page allowing for 1-pixel border AROUND the actual paper + dc.SetPen(*wxBLACK_PEN); + dc.SetBrush(*wxWHITE_BRUSH); + dc.DrawRectangle(paperRect.x - 2, paperRect.y - 1, + paperRect.width + 3, paperRect.height + 2); + + return true; +} + +void wxPrintPreviewBase::SetZoom(int percent) +{ + if (m_currentZoom == percent) + return; + + m_currentZoom = percent; + if (m_previewBitmap) + { + delete m_previewBitmap; + m_previewBitmap = NULL; + } + + if (m_previewCanvas) + { + AdjustScrollbars(m_previewCanvas); + RenderPage(m_currentPage); + ((wxScrolledWindow *) m_previewCanvas)->Scroll(0, 0); + m_previewCanvas->ClearBackground(); + m_previewCanvas->Refresh(); + m_previewCanvas->SetFocus(); + } +} + +wxPrintDialogData& wxPrintPreviewBase::GetPrintDialogData() +{ + return m_printDialogData; +} + +int wxPrintPreviewBase::GetZoom() const +{ return m_currentZoom; } +int wxPrintPreviewBase::GetMaxPage() const +{ return m_maxPage; } +int wxPrintPreviewBase::GetMinPage() const +{ return m_minPage; } +bool wxPrintPreviewBase::IsOk() const +{ return m_isOk; } +void wxPrintPreviewBase::SetOk(bool ok) +{ m_isOk = ok; } + +//---------------------------------------------------------------------------- +// wxPrintPreview +//---------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxPrintPreview, wxPrintPreviewBase) + +wxPrintPreview::wxPrintPreview(wxPrintout *printout, + wxPrintout *printoutForPrinting, + wxPrintDialogData *data) : + wxPrintPreviewBase( printout, printoutForPrinting, data ) +{ + m_pimpl = wxPrintFactory::GetFactory()-> + CreatePrintPreview( printout, printoutForPrinting, data ); +} + +wxPrintPreview::wxPrintPreview(wxPrintout *printout, + wxPrintout *printoutForPrinting, + wxPrintData *data ) : + wxPrintPreviewBase( printout, printoutForPrinting, data ) +{ + m_pimpl = wxPrintFactory::GetFactory()-> + CreatePrintPreview( printout, printoutForPrinting, data ); +} + +wxPrintPreview::~wxPrintPreview() +{ + delete m_pimpl; + + // don't delete twice + m_printPrintout = NULL; + m_previewPrintout = NULL; + m_previewBitmap = NULL; +} + +bool wxPrintPreview::SetCurrentPage(int pageNum) +{ + return m_pimpl->SetCurrentPage( pageNum ); +} + +int wxPrintPreview::GetCurrentPage() const +{ + return m_pimpl->GetCurrentPage(); +} + +void wxPrintPreview::SetPrintout(wxPrintout *printout) +{ + m_pimpl->SetPrintout( printout ); +} + +wxPrintout *wxPrintPreview::GetPrintout() const +{ + return m_pimpl->GetPrintout(); +} + +wxPrintout *wxPrintPreview::GetPrintoutForPrinting() const +{ + return m_pimpl->GetPrintoutForPrinting(); +} + +void wxPrintPreview::SetFrame(wxFrame *frame) +{ + m_pimpl->SetFrame( frame ); +} + +void wxPrintPreview::SetCanvas(wxPreviewCanvas *canvas) +{ + m_pimpl->SetCanvas( canvas ); +} + +wxFrame *wxPrintPreview::GetFrame() const +{ + return m_pimpl->GetFrame(); +} + +wxPreviewCanvas *wxPrintPreview::GetCanvas() const +{ + return m_pimpl->GetCanvas(); +} + +bool wxPrintPreview::PaintPage(wxPreviewCanvas *canvas, wxDC& dc) +{ + return m_pimpl->PaintPage( canvas, dc ); +} + +bool wxPrintPreview::DrawBlankPage(wxPreviewCanvas *canvas, wxDC& dc) +{ + return m_pimpl->DrawBlankPage( canvas, dc ); +} + +void wxPrintPreview::AdjustScrollbars(wxPreviewCanvas *canvas) +{ + m_pimpl->AdjustScrollbars( canvas ); +} + +bool wxPrintPreview::RenderPage(int pageNum) +{ + return m_pimpl->RenderPage( pageNum ); +} + +void wxPrintPreview::SetZoom(int percent) +{ + m_pimpl->SetZoom( percent ); +} + +int wxPrintPreview::GetZoom() const +{ + return m_pimpl->GetZoom(); +} + +wxPrintDialogData& wxPrintPreview::GetPrintDialogData() +{ + return m_pimpl->GetPrintDialogData(); +} + +int wxPrintPreview::GetMaxPage() const +{ + return m_pimpl->GetMaxPage(); +} + +int wxPrintPreview::GetMinPage() const +{ + return m_pimpl->GetMinPage(); +} + +bool wxPrintPreview::IsOk() const +{ + return m_pimpl->Ok(); +} + +void wxPrintPreview::SetOk(bool ok) +{ + m_pimpl->SetOk( ok ); +} + +bool wxPrintPreview::Print(bool interactive) +{ + return m_pimpl->Print( interactive ); +} + +void wxPrintPreview::DetermineScaling() +{ + m_pimpl->DetermineScaling(); +} + +//---------------------------------------------------------------------------- +// experimental backport of high-quality preview on Windows +//---------------------------------------------------------------------------- + +#if wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW +static bool RenderPageIntoBitmapHQ(wxPrintPreviewBase *preview, + RenderPageIntoDCFunc RenderPageIntoDC, + wxBitmap& bmp, int pageNum) +{ + // The preview, as implemented in wxPrintPreviewBase (and as used prior to + // wx3) is inexact: it uses screen DC, which has much lower resolution and + // has other properties different from printer DC, so the preview is not + // quite right. + // + // To make matters worse, if the application depends heavily on + // GetTextExtent() or does text layout itself, the output in preview and on + // paper can be very different. In particular, wxHtmlEasyPrinting is + // affected and the preview can be easily off by several pages. + // + // To fix this, we render the preview into high-resolution enhanced + // metafile with properties identical to the printer DC. This guarantees + // metrics correctness while still being fast. + + + // print the preview into a metafile: + wxPrinterDC printerDC(preview->GetPrintDialogData().GetPrintData()); + wxEnhMetaFileDC metaDC(printerDC, + wxEmptyString, + printerDC.GetSize().x, printerDC.GetSize().y); + + if ( !(preview->*RenderPageIntoDC)(metaDC, pageNum) ) + return false; + + wxEnhMetaFile *metafile = metaDC.Close(); + if ( !metafile ) + return false; + + // now render the metafile: + wxMemoryDC bmpDC; + bmpDC.SelectObject(bmp); + bmpDC.Clear(); + + wxRect outRect(0, 0, bmp.GetWidth(), bmp.GetHeight()); + metafile->Play(&bmpDC, &outRect); + + + delete metafile; + + // TODO: we should keep the metafile and reuse it when changing zoom level + + return true; +} +#endif // wxUSE_HIGH_QUALITY_PREVIEW_IN_WXMSW + +#endif // wxUSE_PRINTING_ARCHITECTURE diff --git a/Source/3rd Party/wx/src/common/process.cpp b/Source/3rd Party/wx/src/common/process.cpp index 3c0ae358c..9e8681ad2 100644 --- a/Source/3rd Party/wx/src/common/process.cpp +++ b/Source/3rd Party/wx/src/common/process.cpp @@ -1,172 +1,172 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: process.cpp -// Purpose: Process termination classes -// Author: Guilhem Lavaux -// Modified by: Vadim Zeitlin to check error codes, added Detach() method -// Created: 24/06/98 -// RCS-ID: $Id: process.cpp 42702 2006-10-30 09:03:18Z JS $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/process.h" - -// ---------------------------------------------------------------------------- -// event tables and such -// ---------------------------------------------------------------------------- - -DEFINE_EVENT_TYPE(wxEVT_END_PROCESS) - -IMPLEMENT_DYNAMIC_CLASS(wxProcess, wxEvtHandler) -IMPLEMENT_DYNAMIC_CLASS(wxProcessEvent, wxEvent) - -// ============================================================================ -// wxProcess implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxProcess creation -// ---------------------------------------------------------------------------- - -void wxProcess::Init(wxEvtHandler *parent, int id, int flags) -{ - if ( parent ) - SetNextHandler(parent); - - m_id = id; - m_pid = 0; - m_redirect = (flags & wxPROCESS_REDIRECT) != 0; - -#if wxUSE_STREAMS - m_inputStream = NULL; - m_errorStream = NULL; - m_outputStream = NULL; -#endif // wxUSE_STREAMS -} - -/* static */ -wxProcess *wxProcess::Open(const wxString& cmd, int flags) -{ - wxASSERT_MSG( !(flags & wxEXEC_SYNC), wxT("wxEXEC_SYNC should not be used." )); - wxProcess *process = new wxProcess(wxPROCESS_REDIRECT); - long pid = wxExecute(cmd, flags, process); - if( !pid ) - { - // couldn't launch the process - delete process; - return NULL; - } - - process->SetPid(pid); - - return process; -} - -// ---------------------------------------------------------------------------- -// wxProcess termination -// ---------------------------------------------------------------------------- - -wxProcess::~wxProcess() -{ -#if wxUSE_STREAMS - delete m_inputStream; - delete m_errorStream; - delete m_outputStream; -#endif // wxUSE_STREAMS -} - -void wxProcess::OnTerminate(int pid, int status) -{ - wxProcessEvent event(m_id, pid, status); - - if ( !ProcessEvent(event) ) - delete this; - //else: the object which processed the event is responsible for deleting - // us! -} - -void wxProcess::Detach() -{ - SetNextHandler(NULL); -} - -// ---------------------------------------------------------------------------- -// process IO redirection -// ---------------------------------------------------------------------------- - -#if wxUSE_STREAMS - -void wxProcess::SetPipeStreams(wxInputStream *inputSstream, - wxOutputStream *outputStream, - wxInputStream *errorStream) -{ - m_inputStream = inputSstream; - m_errorStream = errorStream; - m_outputStream = outputStream; -} - -bool wxProcess::IsInputOpened() const -{ - return m_inputStream && m_inputStream->GetLastError() != wxSTREAM_EOF; -} - -bool wxProcess::IsInputAvailable() const -{ - return m_inputStream && m_inputStream->CanRead(); -} - -bool wxProcess::IsErrorAvailable() const -{ - return m_errorStream && m_errorStream->CanRead(); -} - -#endif // wxUSE_STREAMS - -// ---------------------------------------------------------------------------- -// process killing -// ---------------------------------------------------------------------------- - -/* static */ -wxKillError wxProcess::Kill(int pid, wxSignal sig, int flags) -{ - wxKillError rc; - (void)wxKill(pid, sig, &rc, flags); - - return rc; -} - -/* static */ -bool wxProcess::Exists(int pid) -{ - switch ( Kill(pid, wxSIGNONE) ) - { - case wxKILL_OK: - case wxKILL_ACCESS_DENIED: - return true; - - default: - case wxKILL_ERROR: - case wxKILL_BAD_SIGNAL: - wxFAIL_MSG( _T("unexpected wxProcess::Kill() return code") ); - // fall through - - case wxKILL_NO_PROCESS: - return false; - } -} - +///////////////////////////////////////////////////////////////////////////// +// Name: process.cpp +// Purpose: Process termination classes +// Author: Guilhem Lavaux +// Modified by: Vadim Zeitlin to check error codes, added Detach() method +// Created: 24/06/98 +// RCS-ID: $Id: process.cpp 42702 2006-10-30 09:03:18Z JS $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/process.h" + +// ---------------------------------------------------------------------------- +// event tables and such +// ---------------------------------------------------------------------------- + +DEFINE_EVENT_TYPE(wxEVT_END_PROCESS) + +IMPLEMENT_DYNAMIC_CLASS(wxProcess, wxEvtHandler) +IMPLEMENT_DYNAMIC_CLASS(wxProcessEvent, wxEvent) + +// ============================================================================ +// wxProcess implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxProcess creation +// ---------------------------------------------------------------------------- + +void wxProcess::Init(wxEvtHandler *parent, int id, int flags) +{ + if ( parent ) + SetNextHandler(parent); + + m_id = id; + m_pid = 0; + m_redirect = (flags & wxPROCESS_REDIRECT) != 0; + +#if wxUSE_STREAMS + m_inputStream = NULL; + m_errorStream = NULL; + m_outputStream = NULL; +#endif // wxUSE_STREAMS +} + +/* static */ +wxProcess *wxProcess::Open(const wxString& cmd, int flags) +{ + wxASSERT_MSG( !(flags & wxEXEC_SYNC), wxT("wxEXEC_SYNC should not be used." )); + wxProcess *process = new wxProcess(wxPROCESS_REDIRECT); + long pid = wxExecute(cmd, flags, process); + if( !pid ) + { + // couldn't launch the process + delete process; + return NULL; + } + + process->SetPid(pid); + + return process; +} + +// ---------------------------------------------------------------------------- +// wxProcess termination +// ---------------------------------------------------------------------------- + +wxProcess::~wxProcess() +{ +#if wxUSE_STREAMS + delete m_inputStream; + delete m_errorStream; + delete m_outputStream; +#endif // wxUSE_STREAMS +} + +void wxProcess::OnTerminate(int pid, int status) +{ + wxProcessEvent event(m_id, pid, status); + + if ( !ProcessEvent(event) ) + delete this; + //else: the object which processed the event is responsible for deleting + // us! +} + +void wxProcess::Detach() +{ + SetNextHandler(NULL); +} + +// ---------------------------------------------------------------------------- +// process IO redirection +// ---------------------------------------------------------------------------- + +#if wxUSE_STREAMS + +void wxProcess::SetPipeStreams(wxInputStream *inputSstream, + wxOutputStream *outputStream, + wxInputStream *errorStream) +{ + m_inputStream = inputSstream; + m_errorStream = errorStream; + m_outputStream = outputStream; +} + +bool wxProcess::IsInputOpened() const +{ + return m_inputStream && m_inputStream->GetLastError() != wxSTREAM_EOF; +} + +bool wxProcess::IsInputAvailable() const +{ + return m_inputStream && m_inputStream->CanRead(); +} + +bool wxProcess::IsErrorAvailable() const +{ + return m_errorStream && m_errorStream->CanRead(); +} + +#endif // wxUSE_STREAMS + +// ---------------------------------------------------------------------------- +// process killing +// ---------------------------------------------------------------------------- + +/* static */ +wxKillError wxProcess::Kill(int pid, wxSignal sig, int flags) +{ + wxKillError rc; + (void)wxKill(pid, sig, &rc, flags); + + return rc; +} + +/* static */ +bool wxProcess::Exists(int pid) +{ + switch ( Kill(pid, wxSIGNONE) ) + { + case wxKILL_OK: + case wxKILL_ACCESS_DENIED: + return true; + + default: + case wxKILL_ERROR: + case wxKILL_BAD_SIGNAL: + wxFAIL_MSG( _T("unexpected wxProcess::Kill() return code") ); + // fall through + + case wxKILL_NO_PROCESS: + return false; + } +} + diff --git a/Source/3rd Party/wx/src/common/quantize.cpp b/Source/3rd Party/wx/src/common/quantize.cpp index 85d0f1fc1..7ffa7b19a 100644 --- a/Source/3rd Party/wx/src/common/quantize.cpp +++ b/Source/3rd Party/wx/src/common/quantize.cpp @@ -1,1654 +1,1654 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/quantize.cpp -// Purpose: wxQuantize implementation -// Author: Julian Smart -// Modified by: -// Created: 22/6/2000 -// RCS-ID: $Id: quantize.cpp 39957 2006-07-03 19:02:54Z ABX $ -// Copyright: (c) Thomas G. Lane, Vaclav Slavik, Julian Smart -// Licence: wxWindows licence + JPEG library licence -///////////////////////////////////////////////////////////////////////////// - -/* - * jquant2.c - * - * Copyright (C) 1991-1996, Thomas G. Lane. - * This file is part of the Independent JPEG Group's software. - * For conditions of distribution and use, see the accompanying README file. - * - * This file contains 2-pass color quantization (color mapping) routines. - * These routines provide selection of a custom color map for an image, - * followed by mapping of the image to that color map, with optional - * Floyd-Steinberg dithering. - * It is also possible to use just the second pass to map to an arbitrary - * externally-given color map. - * - * Note: ordered dithering is not supported, since there isn't any fast - * way to compute intercolor distances; it's unclear that ordered dither's - * fundamental assumptions even hold with an irregularly spaced color map. - */ - -/* modified by Vaclav Slavik for use as jpeglib-independent module */ - -// For compilers that support precompilation, includes "wx/wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#if wxUSE_IMAGE - -#include "wx/quantize.h" - -#ifndef WX_PRECOMP - #include "wx/palette.h" - #include "wx/image.h" -#endif - -#ifdef __WXMSW__ - #include "wx/msw/private.h" -#endif - -#include -#include - -#if defined(__OS2__) -#define RGB_RED_OS2 0 -#define RGB_GREEN_OS2 1 -#define RGB_BLUE_OS2 2 -#else -#define RGB_RED 0 -#define RGB_GREEN 1 -#define RGB_BLUE 2 -#endif -#define RGB_PIXELSIZE 3 - -#define MAXJSAMPLE 255 -#define CENTERJSAMPLE 128 -#define BITS_IN_JSAMPLE 8 -#define GETJSAMPLE(value) ((int) (value)) - -#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) - -typedef unsigned short UINT16; -typedef signed short INT16; -#if !(defined(__WATCOMC__) && (defined(__WXMSW__) || defined(__WXMOTIF__))) -typedef signed int INT32; -#endif - -typedef unsigned char JSAMPLE; -typedef JSAMPLE *JSAMPROW; -typedef JSAMPROW *JSAMPARRAY; -typedef unsigned int JDIMENSION; - -typedef struct { - void *cquantize; - JDIMENSION output_width; - JSAMPARRAY colormap; - int actual_number_of_colors; - int desired_number_of_colors; - JSAMPLE *sample_range_limit, *srl_orig; -} j_decompress; - -#if defined(__WINDOWS__) && !defined(__WXMICROWIN__) - #define JMETHOD(type,methodname,arglist) type (__cdecl methodname) arglist -#else - #define JMETHOD(type,methodname,arglist) type (methodname) arglist -#endif - -typedef j_decompress *j_decompress_ptr; -struct jpeg_color_quantizer { - JMETHOD(void, start_pass, (j_decompress_ptr cinfo, bool is_pre_scan)); - JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPARRAY output_buf, - int num_rows)); - JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); - JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); -}; - - - - -/* - * This module implements the well-known Heckbert paradigm for color - * quantization. Most of the ideas used here can be traced back to - * Heckbert's seminal paper - * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display", - * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304. - * - * In the first pass over the image, we accumulate a histogram showing the - * usage count of each possible color. To keep the histogram to a reasonable - * size, we reduce the precision of the input; typical practice is to retain - * 5 or 6 bits per color, so that 8 or 4 different input values are counted - * in the same histogram cell. - * - * Next, the color-selection step begins with a box representing the whole - * color space, and repeatedly splits the "largest" remaining box until we - * have as many boxes as desired colors. Then the mean color in each - * remaining box becomes one of the possible output colors. - * - * The second pass over the image maps each input pixel to the closest output - * color (optionally after applying a Floyd-Steinberg dithering correction). - * This mapping is logically trivial, but making it go fast enough requires - * considerable care. - * - * Heckbert-style quantizers vary a good deal in their policies for choosing - * the "largest" box and deciding where to cut it. The particular policies - * used here have proved out well in experimental comparisons, but better ones - * may yet be found. - * - * In earlier versions of the IJG code, this module quantized in YCbCr color - * space, processing the raw upsampled data without a color conversion step. - * This allowed the color conversion math to be done only once per colormap - * entry, not once per pixel. However, that optimization precluded other - * useful optimizations (such as merging color conversion with upsampling) - * and it also interfered with desired capabilities such as quantizing to an - * externally-supplied colormap. We have therefore abandoned that approach. - * The present code works in the post-conversion color space, typically RGB. - * - * To improve the visual quality of the results, we actually work in scaled - * RGB space, giving G distances more weight than R, and R in turn more than - * B. To do everything in integer math, we must use integer scale factors. - * The 2/3/1 scale factors used here correspond loosely to the relative - * weights of the colors in the NTSC grayscale equation. - * If you want to use this code to quantize a non-RGB color space, you'll - * probably need to change these scale factors. - */ - -#define R_SCALE 2 /* scale R distances by this much */ -#define G_SCALE 3 /* scale G distances by this much */ -#define B_SCALE 1 /* and B by this much */ - -/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined - * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B - * and B,G,R orders. If you define some other weird order in jmorecfg.h, - * you'll get compile errors until you extend this logic. In that case - * you'll probably want to tweak the histogram sizes too. - */ - -#if defined(__OS2__) - -#if RGB_RED_OS2 == 0 -#define C0_SCALE R_SCALE -#endif -#if RGB_BLUE_OS2 == 0 -#define C0_SCALE B_SCALE -#endif -#if RGB_GREEN_OS2 == 1 -#define C1_SCALE G_SCALE -#endif -#if RGB_RED_OS2 == 2 -#define C2_SCALE R_SCALE -#endif -#if RGB_BLUE_OS2 == 2 -#define C2_SCALE B_SCALE -#endif - -#else - -#if RGB_RED == 0 -#define C0_SCALE R_SCALE -#endif -#if RGB_BLUE == 0 -#define C0_SCALE B_SCALE -#endif -#if RGB_GREEN == 1 -#define C1_SCALE G_SCALE -#endif -#if RGB_RED == 2 -#define C2_SCALE R_SCALE -#endif -#if RGB_BLUE == 2 -#define C2_SCALE B_SCALE -#endif - -#endif - -/* - * First we have the histogram data structure and routines for creating it. - * - * The number of bits of precision can be adjusted by changing these symbols. - * We recommend keeping 6 bits for G and 5 each for R and B. - * If you have plenty of memory and cycles, 6 bits all around gives marginally - * better results; if you are short of memory, 5 bits all around will save - * some space but degrade the results. - * To maintain a fully accurate histogram, we'd need to allocate a "long" - * (preferably unsigned long) for each cell. In practice this is overkill; - * we can get by with 16 bits per cell. Few of the cell counts will overflow, - * and clamping those that do overflow to the maximum value will give close- - * enough results. This reduces the recommended histogram size from 256Kb - * to 128Kb, which is a useful savings on PC-class machines. - * (In the second pass the histogram space is re-used for pixel mapping data; - * in that capacity, each cell must be able to store zero to the number of - * desired colors. 16 bits/cell is plenty for that too.) - * Since the JPEG code is intended to run in small memory model on 80x86 - * machines, we can't just allocate the histogram in one chunk. Instead - * of a true 3-D array, we use a row of pointers to 2-D arrays. Each - * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and - * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that - * on 80x86 machines, the pointer row is in near memory but the actual - * arrays are in far memory (same arrangement as we use for image arrays). - */ - -#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */ - -/* These will do the right thing for either R,G,B or B,G,R color order, - * but you may not like the results for other color orders. - */ -#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */ -#define HIST_C1_BITS 6 /* bits of precision in G histogram */ -#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */ - -/* Number of elements along histogram axes. */ -#define HIST_C0_ELEMS (1<cquantize; - register JSAMPROW ptr; - register histptr histp; - register hist3d histogram = cquantize->histogram; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - - for (row = 0; row < num_rows; row++) { - ptr = input_buf[row]; - for (col = width; col > 0; col--) { - - { - - /* get pixel value and index into the histogram */ - histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT] - [GETJSAMPLE(ptr[1]) >> C1_SHIFT] - [GETJSAMPLE(ptr[2]) >> C2_SHIFT]; - /* increment, check for overflow and undo increment if so. */ - if (++(*histp) <= 0) - (*histp)--; - } - ptr += 3; - } - } -} - - -/* - * Next we have the really interesting routines: selection of a colormap - * given the completed histogram. - * These routines work with a list of "boxes", each representing a rectangular - * subset of the input color space (to histogram precision). - */ - -typedef struct { - /* The bounds of the box (inclusive); expressed as histogram indexes */ - int c0min, c0max; - int c1min, c1max; - int c2min, c2max; - /* The volume (actually 2-norm) of the box */ - INT32 volume; - /* The number of nonzero histogram cells within this box */ - long colorcount; -} box; - -typedef box * boxptr; - - -boxptr -find_biggest_color_pop (boxptr boxlist, int numboxes) -/* Find the splittable box with the largest color population */ -/* Returns NULL if no splittable boxes remain */ -{ - register boxptr boxp; - register int i; - register long maxc = 0; - boxptr which = NULL; - - for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { - if (boxp->colorcount > maxc && boxp->volume > 0) { - which = boxp; - maxc = boxp->colorcount; - } - } - return which; -} - - -boxptr -find_biggest_volume (boxptr boxlist, int numboxes) -/* Find the splittable box with the largest (scaled) volume */ -/* Returns NULL if no splittable boxes remain */ -{ - register boxptr boxp; - register int i; - register INT32 maxv = 0; - boxptr which = NULL; - - for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { - if (boxp->volume > maxv) { - which = boxp; - maxv = boxp->volume; - } - } - return which; -} - - -void -update_box (j_decompress_ptr cinfo, boxptr boxp) -/* Shrink the min/max bounds of a box to enclose only nonzero elements, */ -/* and recompute its volume and population */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - histptr histp; - int c0,c1,c2; - int c0min,c0max,c1min,c1max,c2min,c2max; - INT32 dist0,dist1,dist2; - long ccount; - - c0min = boxp->c0min; c0max = boxp->c0max; - c1min = boxp->c1min; c1max = boxp->c1max; - c2min = boxp->c2min; c2max = boxp->c2max; - - if (c0max > c0min) - for (c0 = c0min; c0 <= c0max; c0++) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c0min = c0min = c0; - goto have_c0min; - } - } - have_c0min: - if (c0max > c0min) - for (c0 = c0max; c0 >= c0min; c0--) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c0max = c0max = c0; - goto have_c0max; - } - } - have_c0max: - if (c1max > c1min) - for (c1 = c1min; c1 <= c1max; c1++) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c1min = c1min = c1; - goto have_c1min; - } - } - have_c1min: - if (c1max > c1min) - for (c1 = c1max; c1 >= c1min; c1--) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) - if (*histp++ != 0) { - boxp->c1max = c1max = c1; - goto have_c1max; - } - } - have_c1max: - if (c2max > c2min) - for (c2 = c2min; c2 <= c2max; c2++) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1min][c2]; - for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) - if (*histp != 0) { - boxp->c2min = c2min = c2; - goto have_c2min; - } - } - have_c2min: - if (c2max > c2min) - for (c2 = c2max; c2 >= c2min; c2--) - for (c0 = c0min; c0 <= c0max; c0++) { - histp = & histogram[c0][c1min][c2]; - for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) - if (*histp != 0) { - boxp->c2max = c2max = c2; - goto have_c2max; - } - } - have_c2max: - - /* Update box volume. - * We use 2-norm rather than real volume here; this biases the method - * against making long narrow boxes, and it has the side benefit that - * a box is splittable iff norm > 0. - * Since the differences are expressed in histogram-cell units, - * we have to shift back to JSAMPLE units to get consistent distances; - * after which, we scale according to the selected distance scale factors. - */ - dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE; - dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE; - dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE; - boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2; - - /* Now scan remaining volume of box and compute population */ - ccount = 0; - for (c0 = c0min; c0 <= c0max; c0++) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++, histp++) - if (*histp != 0) { - ccount++; - } - } - boxp->colorcount = ccount; -} - - -int -median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes, - int desired_colors) -/* Repeatedly select and split the largest box until we have enough boxes */ -{ - int n,lb; - int c0,c1,c2,cmax; - register boxptr b1,b2; - - while (numboxes < desired_colors) { - /* Select box to split. - * Current algorithm: by population for first half, then by volume. - */ - if ((numboxes*2) <= desired_colors) { - b1 = find_biggest_color_pop(boxlist, numboxes); - } else { - b1 = find_biggest_volume(boxlist, numboxes); - } - if (b1 == NULL) /* no splittable boxes left! */ - break; - b2 = &boxlist[numboxes]; /* where new box will go */ - /* Copy the color bounds to the new box. */ - b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max; - b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min; - /* Choose which axis to split the box on. - * Current algorithm: longest scaled axis. - * See notes in update_box about scaling distances. - */ - c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE; - c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE; - c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE; - /* We want to break any ties in favor of green, then red, blue last. - * This code does the right thing for R,G,B or B,G,R color orders only. - */ -#if defined(__VISAGECPP__) - -#if RGB_RED_OS2 == 0 - cmax = c1; n = 1; - if (c0 > cmax) { cmax = c0; n = 0; } - if (c2 > cmax) { n = 2; } -#else - cmax = c1; n = 1; - if (c2 > cmax) { cmax = c2; n = 2; } - if (c0 > cmax) { n = 0; } -#endif - -#else - -#if RGB_RED == 0 - cmax = c1; n = 1; - if (c0 > cmax) { cmax = c0; n = 0; } - if (c2 > cmax) { n = 2; } -#else - cmax = c1; n = 1; - if (c2 > cmax) { cmax = c2; n = 2; } - if (c0 > cmax) { n = 0; } -#endif - -#endif - /* Choose split point along selected axis, and update box bounds. - * Current algorithm: split at halfway point. - * (Since the box has been shrunk to minimum volume, - * any split will produce two nonempty subboxes.) - * Note that lb value is max for lower box, so must be < old max. - */ - switch (n) { - case 0: - lb = (b1->c0max + b1->c0min) / 2; - b1->c0max = lb; - b2->c0min = lb+1; - break; - case 1: - lb = (b1->c1max + b1->c1min) / 2; - b1->c1max = lb; - b2->c1min = lb+1; - break; - case 2: - lb = (b1->c2max + b1->c2min) / 2; - b1->c2max = lb; - b2->c2min = lb+1; - break; - } - /* Update stats for boxes */ - update_box(cinfo, b1); - update_box(cinfo, b2); - numboxes++; - } - return numboxes; -} - - -void -compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor) -/* Compute representative color for a box, put it in colormap[icolor] */ -{ - /* Current algorithm: mean weighted by pixels (not colors) */ - /* Note it is important to get the rounding correct! */ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - histptr histp; - int c0,c1,c2; - int c0min,c0max,c1min,c1max,c2min,c2max; - long count; - long total = 0; - long c0total = 0; - long c1total = 0; - long c2total = 0; - - c0min = boxp->c0min; c0max = boxp->c0max; - c1min = boxp->c1min; c1max = boxp->c1max; - c2min = boxp->c2min; c2max = boxp->c2max; - - for (c0 = c0min; c0 <= c0max; c0++) - for (c1 = c1min; c1 <= c1max; c1++) { - histp = & histogram[c0][c1][c2min]; - for (c2 = c2min; c2 <= c2max; c2++) { - if ((count = *histp++) != 0) { - total += count; - c0total += ((c0 << C0_SHIFT) + ((1<>1)) * count; - c1total += ((c1 << C1_SHIFT) + ((1<>1)) * count; - c2total += ((c2 << C2_SHIFT) + ((1<>1)) * count; - } - } - } - - cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); - cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); - cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); -} - - -static void -select_colors (j_decompress_ptr cinfo, int desired_colors) -/* Master routine for color selection */ -{ - boxptr boxlist; - int numboxes; - int i; - - /* Allocate workspace for box list */ - boxlist = (boxptr) malloc(desired_colors * sizeof(box)); - /* Initialize one box containing whole space */ - numboxes = 1; - boxlist[0].c0min = 0; - boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT; - boxlist[0].c1min = 0; - boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT; - boxlist[0].c2min = 0; - boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT; - /* Shrink it to actually-used volume and set its statistics */ - update_box(cinfo, & boxlist[0]); - /* Perform median-cut to produce final box list */ - numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors); - /* Compute the representative color for each box, fill colormap */ - for (i = 0; i < numboxes; i++) - compute_color(cinfo, & boxlist[i], i); - cinfo->actual_number_of_colors = numboxes; - - free(boxlist); //FIXME?? I don't know if this is correct - VS -} - - -/* - * These routines are concerned with the time-critical task of mapping input - * colors to the nearest color in the selected colormap. - * - * We re-use the histogram space as an "inverse color map", essentially a - * cache for the results of nearest-color searches. All colors within a - * histogram cell will be mapped to the same colormap entry, namely the one - * closest to the cell's center. This may not be quite the closest entry to - * the actual input color, but it's almost as good. A zero in the cache - * indicates we haven't found the nearest color for that cell yet; the array - * is cleared to zeroes before starting the mapping pass. When we find the - * nearest color for a cell, its colormap index plus one is recorded in the - * cache for future use. The pass2 scanning routines call fill_inverse_cmap - * when they need to use an unfilled entry in the cache. - * - * Our method of efficiently finding nearest colors is based on the "locally - * sorted search" idea described by Heckbert and on the incremental distance - * calculation described by Spencer W. Thomas in chapter III.1 of Graphics - * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that - * the distances from a given colormap entry to each cell of the histogram can - * be computed quickly using an incremental method: the differences between - * distances to adjacent cells themselves differ by a constant. This allows a - * fairly fast implementation of the "brute force" approach of computing the - * distance from every colormap entry to every histogram cell. Unfortunately, - * it needs a work array to hold the best-distance-so-far for each histogram - * cell (because the inner loop has to be over cells, not colormap entries). - * The work array elements have to be INT32s, so the work array would need - * 256Kb at our recommended precision. This is not feasible in DOS machines. - * - * To get around these problems, we apply Thomas' method to compute the - * nearest colors for only the cells within a small subbox of the histogram. - * The work array need be only as big as the subbox, so the memory usage - * problem is solved. Furthermore, we need not fill subboxes that are never - * referenced in pass2; many images use only part of the color gamut, so a - * fair amount of work is saved. An additional advantage of this - * approach is that we can apply Heckbert's locality criterion to quickly - * eliminate colormap entries that are far away from the subbox; typically - * three-fourths of the colormap entries are rejected by Heckbert's criterion, - * and we need not compute their distances to individual cells in the subbox. - * The speed of this approach is heavily influenced by the subbox size: too - * small means too much overhead, too big loses because Heckbert's criterion - * can't eliminate as many colormap entries. Empirically the best subbox - * size seems to be about 1/512th of the histogram (1/8th in each direction). - * - * Thomas' article also describes a refined method which is asymptotically - * faster than the brute-force method, but it is also far more complex and - * cannot efficiently be applied to small subboxes. It is therefore not - * useful for programs intended to be portable to DOS machines. On machines - * with plenty of memory, filling the whole histogram in one shot with Thomas' - * refined method might be faster than the present code --- but then again, - * it might not be any faster, and it's certainly more complicated. - */ - - -/* log2(histogram cells in update box) for each axis; this can be adjusted */ -#define BOX_C0_LOG (HIST_C0_BITS-3) -#define BOX_C1_LOG (HIST_C1_BITS-3) -#define BOX_C2_LOG (HIST_C2_BITS-3) - -#define BOX_C0_ELEMS (1<actual_number_of_colors; - int maxc0, maxc1, maxc2; - int centerc0, centerc1, centerc2; - int i, x, ncolors; - INT32 minmaxdist, min_dist, max_dist, tdist; - INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */ - - /* Compute true coordinates of update box's upper corner and center. - * Actually we compute the coordinates of the center of the upper-corner - * histogram cell, which are the upper bounds of the volume we care about. - * Note that since ">>" rounds down, the "center" values may be closer to - * min than to max; hence comparisons to them must be "<=", not "<". - */ - maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT)); - centerc0 = (minc0 + maxc0) >> 1; - maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT)); - centerc1 = (minc1 + maxc1) >> 1; - maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT)); - centerc2 = (minc2 + maxc2) >> 1; - - /* For each color in colormap, find: - * 1. its minimum squared-distance to any point in the update box - * (zero if color is within update box); - * 2. its maximum squared-distance to any point in the update box. - * Both of these can be found by considering only the corners of the box. - * We save the minimum distance for each color in mindist[]; - * only the smallest maximum distance is of interest. - */ - minmaxdist = 0x7FFFFFFFL; - - for (i = 0; i < numcolors; i++) { - /* We compute the squared-c0-distance term, then add in the other two. */ - x = GETJSAMPLE(cinfo->colormap[0][i]); - if (x < minc0) { - tdist = (x - minc0) * C0_SCALE; - min_dist = tdist*tdist; - tdist = (x - maxc0) * C0_SCALE; - max_dist = tdist*tdist; - } else if (x > maxc0) { - tdist = (x - maxc0) * C0_SCALE; - min_dist = tdist*tdist; - tdist = (x - minc0) * C0_SCALE; - max_dist = tdist*tdist; - } else { - /* within cell range so no contribution to min_dist */ - min_dist = 0; - if (x <= centerc0) { - tdist = (x - maxc0) * C0_SCALE; - max_dist = tdist*tdist; - } else { - tdist = (x - minc0) * C0_SCALE; - max_dist = tdist*tdist; - } - } - - x = GETJSAMPLE(cinfo->colormap[1][i]); - if (x < minc1) { - tdist = (x - minc1) * C1_SCALE; - min_dist += tdist*tdist; - tdist = (x - maxc1) * C1_SCALE; - max_dist += tdist*tdist; - } else if (x > maxc1) { - tdist = (x - maxc1) * C1_SCALE; - min_dist += tdist*tdist; - tdist = (x - minc1) * C1_SCALE; - max_dist += tdist*tdist; - } else { - /* within cell range so no contribution to min_dist */ - if (x <= centerc1) { - tdist = (x - maxc1) * C1_SCALE; - max_dist += tdist*tdist; - } else { - tdist = (x - minc1) * C1_SCALE; - max_dist += tdist*tdist; - } - } - - x = GETJSAMPLE(cinfo->colormap[2][i]); - if (x < minc2) { - tdist = (x - minc2) * C2_SCALE; - min_dist += tdist*tdist; - tdist = (x - maxc2) * C2_SCALE; - max_dist += tdist*tdist; - } else if (x > maxc2) { - tdist = (x - maxc2) * C2_SCALE; - min_dist += tdist*tdist; - tdist = (x - minc2) * C2_SCALE; - max_dist += tdist*tdist; - } else { - /* within cell range so no contribution to min_dist */ - if (x <= centerc2) { - tdist = (x - maxc2) * C2_SCALE; - max_dist += tdist*tdist; - } else { - tdist = (x - minc2) * C2_SCALE; - max_dist += tdist*tdist; - } - } - - mindist[i] = min_dist; /* save away the results */ - if (max_dist < minmaxdist) - minmaxdist = max_dist; - } - - /* Now we know that no cell in the update box is more than minmaxdist - * away from some colormap entry. Therefore, only colors that are - * within minmaxdist of some part of the box need be considered. - */ - ncolors = 0; - for (i = 0; i < numcolors; i++) { - if (mindist[i] <= minmaxdist) - colorlist[ncolors++] = (JSAMPLE) i; - } - return ncolors; -} - - -static void -find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2, - int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[]) -/* Find the closest colormap entry for each cell in the update box, - * given the list of candidate colors prepared by find_nearby_colors. - * Return the indexes of the closest entries in the bestcolor[] array. - * This routine uses Thomas' incremental distance calculation method to - * find the distance from a colormap entry to successive cells in the box. - */ -{ - int ic0, ic1, ic2; - int i, icolor; - register INT32 * bptr; /* pointer into bestdist[] array */ - JSAMPLE * cptr; /* pointer into bestcolor[] array */ - INT32 dist0, dist1; /* initial distance values */ - register INT32 dist2; /* current distance in inner loop */ - INT32 xx0, xx1; /* distance increments */ - register INT32 xx2; - INT32 inc0, inc1, inc2; /* initial values for increments */ - /* This array holds the distance to the nearest-so-far color for each cell */ - INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; - - /* Initialize best-distance for each cell of the update box */ - bptr = bestdist; - for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--) - *bptr++ = 0x7FFFFFFFL; - - /* For each color selected by find_nearby_colors, - * compute its distance to the center of each cell in the box. - * If that's less than best-so-far, update best distance and color number. - */ - - /* Nominal steps between cell centers ("x" in Thomas article) */ -#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE) -#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE) -#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE) - - for (i = 0; i < numcolors; i++) { - icolor = GETJSAMPLE(colorlist[i]); - /* Compute (square of) distance from minc0/c1/c2 to this color */ - inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE; - dist0 = inc0*inc0; - inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE; - dist0 += inc1*inc1; - inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE; - dist0 += inc2*inc2; - /* Form the initial difference increments */ - inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; - inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; - inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; - /* Now loop over all cells in box, updating distance per Thomas method */ - bptr = bestdist; - cptr = bestcolor; - xx0 = inc0; - for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) { - dist1 = dist0; - xx1 = inc1; - for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) { - dist2 = dist1; - xx2 = inc2; - for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) { - if (dist2 < *bptr) { - *bptr = dist2; - *cptr = (JSAMPLE) icolor; - } - dist2 += xx2; - xx2 += 2 * STEP_C2 * STEP_C2; - bptr++; - cptr++; - } - dist1 += xx1; - xx1 += 2 * STEP_C1 * STEP_C1; - } - dist0 += xx0; - xx0 += 2 * STEP_C0 * STEP_C0; - } - } -} - - -static void -fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2) -/* Fill the inverse-colormap entries in the update box that contains */ -/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */ -/* we can fill as many others as we wish.) */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - int minc0, minc1, minc2; /* lower left corner of update box */ - int ic0, ic1, ic2; - register JSAMPLE * cptr; /* pointer into bestcolor[] array */ - register histptr cachep; /* pointer into main cache array */ - /* This array lists the candidate colormap indexes. */ - JSAMPLE colorlist[MAXNUMCOLORS]; - int numcolors; /* number of candidate colors */ - /* This array holds the actually closest colormap index for each cell. */ - JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; - - /* Convert cell coordinates to update box ID */ - c0 >>= BOX_C0_LOG; - c1 >>= BOX_C1_LOG; - c2 >>= BOX_C2_LOG; - - /* Compute true coordinates of update box's origin corner. - * Actually we compute the coordinates of the center of the corner - * histogram cell, which are the lower bounds of the volume we care about. - */ - minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1); - minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1); - minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1); - - /* Determine which colormap entries are close enough to be candidates - * for the nearest entry to some cell in the update box. - */ - numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist); - - /* Determine the actually nearest colors. */ - find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist, - bestcolor); - - /* Save the best color numbers (plus 1) in the main cache array */ - c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */ - c1 <<= BOX_C1_LOG; - c2 <<= BOX_C2_LOG; - cptr = bestcolor; - for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) { - for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) { - cachep = & histogram[c0+ic0][c1+ic1][c2]; - for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) { - *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1); - } - } - } -} - - -/* - * Map some rows of pixels to the output colormapped representation. - */ - -void -pass2_no_dither (j_decompress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) -/* This version performs no dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - register JSAMPROW inptr, outptr; - register histptr cachep; - register int c0, c1, c2; - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - - for (row = 0; row < num_rows; row++) { - inptr = input_buf[row]; - outptr = output_buf[row]; - for (col = width; col > 0; col--) { - /* get pixel value and index into the cache */ - c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT; - c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT; - c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT; - cachep = & histogram[c0][c1][c2]; - /* If we have not seen this color before, find nearest colormap entry */ - /* and update the cache */ - if (*cachep == 0) - fill_inverse_cmap(cinfo, c0,c1,c2); - /* Now emit the colormap index for this cell */ - *outptr++ = (JSAMPLE) (*cachep - 1); - } - } -} - - -void -pass2_fs_dither (j_decompress_ptr cinfo, - JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) -/* This version performs Floyd-Steinberg dithering */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */ - LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */ - LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */ - register FSERRPTR errorptr; /* => fserrors[] at column before current */ - JSAMPROW inptr; /* => current input pixel */ - JSAMPROW outptr; /* => current output pixel */ - histptr cachep; - int dir; /* +1 or -1 depending on direction */ - int dir3; /* 3*dir, for advancing inptr & errorptr */ - int row; - JDIMENSION col; - JDIMENSION width = cinfo->output_width; - JSAMPLE *range_limit = cinfo->sample_range_limit; - int *error_limit = cquantize->error_limiter; - JSAMPROW colormap0 = cinfo->colormap[0]; - JSAMPROW colormap1 = cinfo->colormap[1]; - JSAMPROW colormap2 = cinfo->colormap[2]; - - - for (row = 0; row < num_rows; row++) { - inptr = input_buf[row]; - outptr = output_buf[row]; - if (cquantize->on_odd_row) { - /* work right to left in this row */ - inptr += (width-1) * 3; /* so point to rightmost pixel */ - outptr += width-1; - dir = -1; - dir3 = -3; - errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */ - cquantize->on_odd_row = false; /* flip for next time */ - } else { - /* work left to right in this row */ - dir = 1; - dir3 = 3; - errorptr = cquantize->fserrors; /* => entry before first real column */ - cquantize->on_odd_row = true; /* flip for next time */ - } - /* Preset error values: no error propagated to first pixel from left */ - cur0 = cur1 = cur2 = 0; - /* and no error propagated to row below yet */ - belowerr0 = belowerr1 = belowerr2 = 0; - bpreverr0 = bpreverr1 = bpreverr2 = 0; - - for (col = width; col > 0; col--) { - /* curN holds the error propagated from the previous pixel on the - * current line. Add the error propagated from the previous line - * to form the complete error correction term for this pixel, and - * round the error term (which is expressed * 16) to an integer. - * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct - * for either sign of the error value. - * Note: errorptr points to *previous* column's array entry. - */ - cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4); - cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4); - cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4); - /* Limit the error using transfer function set by init_error_limit. - * See comments with init_error_limit for rationale. - */ - cur0 = error_limit[cur0]; - cur1 = error_limit[cur1]; - cur2 = error_limit[cur2]; - /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. - * The maximum error is +- MAXJSAMPLE (or less with error limiting); - * this sets the required size of the range_limit array. - */ - cur0 += GETJSAMPLE(inptr[0]); - cur1 += GETJSAMPLE(inptr[1]); - cur2 += GETJSAMPLE(inptr[2]); - cur0 = GETJSAMPLE(range_limit[cur0]); - cur1 = GETJSAMPLE(range_limit[cur1]); - cur2 = GETJSAMPLE(range_limit[cur2]); - /* Index into the cache with adjusted pixel value */ - cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT]; - /* If we have not seen this color before, find nearest colormap */ - /* entry and update the cache */ - if (*cachep == 0) - fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT); - /* Now emit the colormap index for this cell */ - { register int pixcode = *cachep - 1; - *outptr = (JSAMPLE) pixcode; - /* Compute representation error for this pixel */ - cur0 -= GETJSAMPLE(colormap0[pixcode]); - cur1 -= GETJSAMPLE(colormap1[pixcode]); - cur2 -= GETJSAMPLE(colormap2[pixcode]); - } - /* Compute error fractions to be propagated to adjacent pixels. - * Add these into the running sums, and simultaneously shift the - * next-line error sums left by 1 column. - */ - { register LOCFSERROR bnexterr, delta; - - bnexterr = cur0; /* Process component 0 */ - delta = cur0 * 2; - cur0 += delta; /* form error * 3 */ - errorptr[0] = (FSERROR) (bpreverr0 + cur0); - cur0 += delta; /* form error * 5 */ - bpreverr0 = belowerr0 + cur0; - belowerr0 = bnexterr; - cur0 += delta; /* form error * 7 */ - bnexterr = cur1; /* Process component 1 */ - delta = cur1 * 2; - cur1 += delta; /* form error * 3 */ - errorptr[1] = (FSERROR) (bpreverr1 + cur1); - cur1 += delta; /* form error * 5 */ - bpreverr1 = belowerr1 + cur1; - belowerr1 = bnexterr; - cur1 += delta; /* form error * 7 */ - bnexterr = cur2; /* Process component 2 */ - delta = cur2 * 2; - cur2 += delta; /* form error * 3 */ - errorptr[2] = (FSERROR) (bpreverr2 + cur2); - cur2 += delta; /* form error * 5 */ - bpreverr2 = belowerr2 + cur2; - belowerr2 = bnexterr; - cur2 += delta; /* form error * 7 */ - } - /* At this point curN contains the 7/16 error value to be propagated - * to the next pixel on the current line, and all the errors for the - * next line have been shifted over. We are therefore ready to move on. - */ - inptr += dir3; /* Advance pixel pointers to next column */ - outptr += dir; - errorptr += dir3; /* advance errorptr to current column */ - } - /* Post-loop cleanup: we must unload the final error values into the - * final fserrors[] entry. Note we need not unload belowerrN because - * it is for the dummy column before or after the actual array. - */ - errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */ - errorptr[1] = (FSERROR) bpreverr1; - errorptr[2] = (FSERROR) bpreverr2; - } -} - - -/* - * Initialize the error-limiting transfer function (lookup table). - * The raw F-S error computation can potentially compute error values of up to - * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be - * much less, otherwise obviously wrong pixels will be created. (Typical - * effects include weird fringes at color-area boundaries, isolated bright - * pixels in a dark area, etc.) The standard advice for avoiding this problem - * is to ensure that the "corners" of the color cube are allocated as output - * colors; then repeated errors in the same direction cannot cause cascading - * error buildup. However, that only prevents the error from getting - * completely out of hand; Aaron Giles reports that error limiting improves - * the results even with corner colors allocated. - * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty - * well, but the smoother transfer function used below is even better. Thanks - * to Aaron Giles for this idea. - */ - -static void -init_error_limit (j_decompress_ptr cinfo) -/* Allocate and fill in the error_limiter table */ -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - int * table; - int in, out; - - table = (int *) malloc((MAXJSAMPLE*2+1) * sizeof(int)); - table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */ - cquantize->error_limiter = table; - -#define STEPSIZE ((MAXJSAMPLE+1)/16) - /* Map errors 1:1 up to +- MAXJSAMPLE/16 */ - out = 0; - for (in = 0; in < STEPSIZE; in++, out++) { - table[in] = out; table[-in] = -out; - } - /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */ - for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) { - table[in] = out; table[-in] = -out; - } - /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */ - for (; in <= MAXJSAMPLE; in++) { - table[in] = out; table[-in] = -out; - } -#undef STEPSIZE -} - - -/* - * Finish up at the end of each pass. - */ - -void -finish_pass1 (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - - /* Select the representative colors and fill in cinfo->colormap */ - cinfo->colormap = cquantize->sv_colormap; - select_colors(cinfo, cquantize->desired); - /* Force next pass to zero the color index table */ - cquantize->needs_zeroed = true; -} - - -void -finish_pass2 (j_decompress_ptr WXUNUSED(cinfo)) -{ - /* no work */ -} - - -/* - * Initialize for each processing pass. - */ - -void -start_pass_2_quant (j_decompress_ptr cinfo, bool is_pre_scan) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - hist3d histogram = cquantize->histogram; - - if (is_pre_scan) { - /* Set up method pointers */ - cquantize->pub.color_quantize = prescan_quantize; - cquantize->pub.finish_pass = finish_pass1; - cquantize->needs_zeroed = true; /* Always zero histogram */ - } else { - /* Set up method pointers */ - cquantize->pub.color_quantize = pass2_fs_dither; - cquantize->pub.finish_pass = finish_pass2; - - { - size_t arraysize = (size_t) ((cinfo->output_width + 2) * - (3 * sizeof(FSERROR))); - /* Allocate Floyd-Steinberg workspace if we didn't already. */ - if (cquantize->fserrors == NULL) - cquantize->fserrors = (INT16*) malloc(arraysize); - /* Initialize the propagated errors to zero. */ - memset((void *) cquantize->fserrors, 0, arraysize); - /* Make the error-limit table if we didn't already. */ - if (cquantize->error_limiter == NULL) - init_error_limit(cinfo); - cquantize->on_odd_row = false; - } - - } - /* Zero the histogram or inverse color map, if necessary */ - if (cquantize->needs_zeroed) { - for (int i = 0; i < HIST_C0_ELEMS; i++) { - memset((void *) histogram[i], 0, - HIST_C1_ELEMS*HIST_C2_ELEMS * sizeof(histcell)); - } - cquantize->needs_zeroed = false; - } -} - - -/* - * Switch to a new external colormap between output passes. - */ - -void -new_color_map_2_quant (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; - - /* Reset the inverse color map */ - cquantize->needs_zeroed = true; -} - - -/* - * Module initialization routine for 2-pass color quantization. - */ - -void -jinit_2pass_quantizer (j_decompress_ptr cinfo) -{ - my_cquantize_ptr cquantize; - int i; - - cquantize = (my_cquantize_ptr) malloc(sizeof(my_cquantizer)); - cinfo->cquantize = (jpeg_color_quantizer *) cquantize; - cquantize->pub.start_pass = start_pass_2_quant; - cquantize->pub.new_color_map = new_color_map_2_quant; - cquantize->fserrors = NULL; /* flag optional arrays not allocated */ - cquantize->error_limiter = NULL; - - - /* Allocate the histogram/inverse colormap storage */ - cquantize->histogram = (hist3d) malloc(HIST_C0_ELEMS * sizeof(hist2d)); - for (i = 0; i < HIST_C0_ELEMS; i++) { - cquantize->histogram[i] = (hist2d) malloc(HIST_C1_ELEMS*HIST_C2_ELEMS * sizeof(histcell)); - } - cquantize->needs_zeroed = true; /* histogram is garbage now */ - - /* Allocate storage for the completed colormap, if required. - * We do this now since it is storage and may affect - * the memory manager's space calculations. - */ - { - /* Make sure color count is acceptable */ - int desired = cinfo->desired_number_of_colors; - - cquantize->sv_colormap = (JSAMPARRAY) malloc(sizeof(JSAMPROW) * 3); - cquantize->sv_colormap[0] = (JSAMPROW) malloc(sizeof(JSAMPLE) * desired); - cquantize->sv_colormap[1] = (JSAMPROW) malloc(sizeof(JSAMPLE) * desired); - cquantize->sv_colormap[2] = (JSAMPROW) malloc(sizeof(JSAMPLE) * desired); - - cquantize->desired = desired; - } - - /* Allocate Floyd-Steinberg workspace if necessary. - * This isn't really needed until pass 2, but again it is storage. - * Although we will cope with a later change in dither_mode, - * we do not promise to honor max_memory_to_use if dither_mode changes. - */ - { - cquantize->fserrors = (FSERRPTR) malloc( - (size_t) ((cinfo->output_width + 2) * (3 * sizeof(FSERROR)))); - /* Might as well create the error-limiting table too. */ - init_error_limit(cinfo); - } -} - - - - - - - - - - -void -prepare_range_limit_table (j_decompress_ptr cinfo) -/* Allocate and fill in the sample_range_limit table */ -{ - JSAMPLE * table; - int i; - - table = (JSAMPLE *) malloc((5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * sizeof(JSAMPLE)); - cinfo->srl_orig = table; - table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */ - cinfo->sample_range_limit = table; - /* First segment of "simple" table: limit[x] = 0 for x < 0 */ - memset(table - (MAXJSAMPLE+1), 0, (MAXJSAMPLE+1) * sizeof(JSAMPLE)); - /* Main part of "simple" table: limit[x] = x */ - for (i = 0; i <= MAXJSAMPLE; i++) - table[i] = (JSAMPLE) i; - table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */ - /* End of simple table, rest of first half of post-IDCT table */ - for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++) - table[i] = MAXJSAMPLE; - /* Second half of post-IDCT table */ - memset(table + (2 * (MAXJSAMPLE+1)), 0, - (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * sizeof(JSAMPLE)); - memcpy(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE), - cinfo->sample_range_limit, CENTERJSAMPLE * sizeof(JSAMPLE)); -} - - - - -/* - * wxQuantize - */ - -IMPLEMENT_DYNAMIC_CLASS(wxQuantize, wxObject) - -void wxQuantize::DoQuantize(unsigned w, unsigned h, unsigned char **in_rows, unsigned char **out_rows, - unsigned char *palette, int desiredNoColours) -{ - j_decompress dec; - my_cquantize_ptr cquantize; - - dec.output_width = w; - dec.desired_number_of_colors = desiredNoColours; - prepare_range_limit_table(&dec); - jinit_2pass_quantizer(&dec); - cquantize = (my_cquantize_ptr) dec.cquantize; - - - cquantize->pub.start_pass(&dec, true); - cquantize->pub.color_quantize(&dec, in_rows, out_rows, h); - cquantize->pub.finish_pass(&dec); - - cquantize->pub.start_pass(&dec, false); - cquantize->pub.color_quantize(&dec, in_rows, out_rows, h); - cquantize->pub.finish_pass(&dec); - - - for (int i = 0; i < dec.desired_number_of_colors; i++) { - palette[3 * i + 0] = dec.colormap[0][i]; - palette[3 * i + 1] = dec.colormap[1][i]; - palette[3 * i + 2] = dec.colormap[2][i]; - } - - for (int ii = 0; ii < HIST_C0_ELEMS; ii++) free(cquantize->histogram[ii]); - free(cquantize->histogram); - free(dec.colormap[0]); - free(dec.colormap[1]); - free(dec.colormap[2]); - free(dec.colormap); - free(dec.srl_orig); - - //free(cquantize->error_limiter); - free((void*)(cquantize->error_limiter - MAXJSAMPLE)); // To reverse what was done to it - - free(cquantize->fserrors); - free(cquantize); -} - -// TODO: somehow make use of the Windows system colours, rather than ignoring them for the -// purposes of quantization. - -bool wxQuantize::Quantize(const wxImage& src, wxImage& dest, - wxPalette** pPalette, - int desiredNoColours, - unsigned char** eightBitData, - int flags) - -{ - int i; - - int windowsSystemColourCount = 20; - - int paletteShift = 0; - - // Shift the palette up by the number of Windows system colours, - // if necessary - if (flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) - paletteShift = windowsSystemColourCount; - - // Make room for the Windows system colours -#ifdef __WXMSW__ - if ((flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) && (desiredNoColours > (256 - windowsSystemColourCount))) - desiredNoColours = 256 - windowsSystemColourCount; -#endif - - // create rows info: - int h = src.GetHeight(); - int w = src.GetWidth(); - unsigned char **rows = new unsigned char *[h]; - unsigned char *imgdt = src.GetData(); - for (i = 0; i < h; i++) - rows[i] = imgdt + 3/*RGB*/ * w * i; - - unsigned char palette[3*256]; - - // This is the image as represented by palette indexes. - unsigned char *data8bit = new unsigned char[w * h]; - unsigned char **outrows = new unsigned char *[h]; - for (i = 0; i < h; i++) - outrows[i] = data8bit + w * i; - - //RGB->palette - DoQuantize(w, h, rows, outrows, palette, desiredNoColours); - - delete[] rows; - delete[] outrows; - - // palette->RGB(max.256) - - if (flags & wxQUANTIZE_FILL_DESTINATION_IMAGE) - { - if (!dest.Ok()) - dest.Create(w, h); - - imgdt = dest.GetData(); - for (i = 0; i < w * h; i++) - { - unsigned char c = data8bit[i]; - imgdt[3 * i + 0/*R*/] = palette[3 * c + 0]; - imgdt[3 * i + 1/*G*/] = palette[3 * c + 1]; - imgdt[3 * i + 2/*B*/] = palette[3 * c + 2]; - } - } - - if (eightBitData && (flags & wxQUANTIZE_RETURN_8BIT_DATA)) - { -#ifdef __WXMSW__ - if (flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) - { - // We need to shift the palette entries up - // to make room for the Windows system colours. - for (i = 0; i < w * h; i++) - data8bit[i] = (unsigned char)(data8bit[i] + paletteShift); - } -#endif - *eightBitData = data8bit; - } - else - delete[] data8bit; - -#if wxUSE_PALETTE - // Make a wxWidgets palette - if (pPalette) - { - unsigned char* r = new unsigned char[256]; - unsigned char* g = new unsigned char[256]; - unsigned char* b = new unsigned char[256]; - -#ifdef __WXMSW__ - // Fill the first 20 entries with Windows system colours - if (flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) - { - HDC hDC = ::GetDC(NULL); - PALETTEENTRY* entries = new PALETTEENTRY[windowsSystemColourCount]; - ::GetSystemPaletteEntries(hDC, 0, windowsSystemColourCount, entries); - ::ReleaseDC(NULL, hDC); - - for (i = 0; i < windowsSystemColourCount; i++) - { - r[i] = entries[i].peRed; - g[i] = entries[i].peGreen; - b[i] = entries[i].peBlue; - } - delete[] entries; - } -#endif - - for (i = 0; i < desiredNoColours; i++) - { - r[i+paletteShift] = palette[i*3 + 0]; - g[i+paletteShift] = palette[i*3 + 1]; - b[i+paletteShift] = palette[i*3 + 2]; - } - - // Blank out any remaining palette entries - for (i = desiredNoColours+paletteShift; i < 256; i++) - { - r[i] = 0; - g[i] = 0; - b[i] = 0; - } - *pPalette = new wxPalette(256, r, g, b); - delete[] r; - delete[] g; - delete[] b; - } -#endif // wxUSE_PALETTE - - return true; -} - -// This version sets a palette in the destination image so you don't -// have to manage it yourself. - -bool wxQuantize::Quantize(const wxImage& src, - wxImage& dest, - int desiredNoColours, - unsigned char** eightBitData, - int flags) -{ - wxPalette* palette = NULL; - if ( !Quantize(src, dest, & palette, desiredNoColours, eightBitData, flags) ) - return false; - -#if wxUSE_PALETTE - if (palette) - { - dest.SetPalette(* palette); - delete palette; - } -#endif // wxUSE_PALETTE - - return true; -} - -#endif - // wxUSE_IMAGE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/quantize.cpp +// Purpose: wxQuantize implementation +// Author: Julian Smart +// Modified by: +// Created: 22/6/2000 +// RCS-ID: $Id: quantize.cpp 39957 2006-07-03 19:02:54Z ABX $ +// Copyright: (c) Thomas G. Lane, Vaclav Slavik, Julian Smart +// Licence: wxWindows licence + JPEG library licence +///////////////////////////////////////////////////////////////////////////// + +/* + * jquant2.c + * + * Copyright (C) 1991-1996, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains 2-pass color quantization (color mapping) routines. + * These routines provide selection of a custom color map for an image, + * followed by mapping of the image to that color map, with optional + * Floyd-Steinberg dithering. + * It is also possible to use just the second pass to map to an arbitrary + * externally-given color map. + * + * Note: ordered dithering is not supported, since there isn't any fast + * way to compute intercolor distances; it's unclear that ordered dither's + * fundamental assumptions even hold with an irregularly spaced color map. + */ + +/* modified by Vaclav Slavik for use as jpeglib-independent module */ + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ +#pragma hdrstop +#endif + +#if wxUSE_IMAGE + +#include "wx/quantize.h" + +#ifndef WX_PRECOMP + #include "wx/palette.h" + #include "wx/image.h" +#endif + +#ifdef __WXMSW__ + #include "wx/msw/private.h" +#endif + +#include +#include + +#if defined(__OS2__) +#define RGB_RED_OS2 0 +#define RGB_GREEN_OS2 1 +#define RGB_BLUE_OS2 2 +#else +#define RGB_RED 0 +#define RGB_GREEN 1 +#define RGB_BLUE 2 +#endif +#define RGB_PIXELSIZE 3 + +#define MAXJSAMPLE 255 +#define CENTERJSAMPLE 128 +#define BITS_IN_JSAMPLE 8 +#define GETJSAMPLE(value) ((int) (value)) + +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) + +typedef unsigned short UINT16; +typedef signed short INT16; +#if !(defined(__WATCOMC__) && (defined(__WXMSW__) || defined(__WXMOTIF__))) +typedef signed int INT32; +#endif + +typedef unsigned char JSAMPLE; +typedef JSAMPLE *JSAMPROW; +typedef JSAMPROW *JSAMPARRAY; +typedef unsigned int JDIMENSION; + +typedef struct { + void *cquantize; + JDIMENSION output_width; + JSAMPARRAY colormap; + int actual_number_of_colors; + int desired_number_of_colors; + JSAMPLE *sample_range_limit, *srl_orig; +} j_decompress; + +#if defined(__WINDOWS__) && !defined(__WXMICROWIN__) + #define JMETHOD(type,methodname,arglist) type (__cdecl methodname) arglist +#else + #define JMETHOD(type,methodname,arglist) type (methodname) arglist +#endif + +typedef j_decompress *j_decompress_ptr; +struct jpeg_color_quantizer { + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, bool is_pre_scan)); + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + int num_rows)); + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); +}; + + + + +/* + * This module implements the well-known Heckbert paradigm for color + * quantization. Most of the ideas used here can be traced back to + * Heckbert's seminal paper + * Heckbert, Paul. "Color Image Quantization for Frame Buffer Display", + * Proc. SIGGRAPH '82, Computer Graphics v.16 #3 (July 1982), pp 297-304. + * + * In the first pass over the image, we accumulate a histogram showing the + * usage count of each possible color. To keep the histogram to a reasonable + * size, we reduce the precision of the input; typical practice is to retain + * 5 or 6 bits per color, so that 8 or 4 different input values are counted + * in the same histogram cell. + * + * Next, the color-selection step begins with a box representing the whole + * color space, and repeatedly splits the "largest" remaining box until we + * have as many boxes as desired colors. Then the mean color in each + * remaining box becomes one of the possible output colors. + * + * The second pass over the image maps each input pixel to the closest output + * color (optionally after applying a Floyd-Steinberg dithering correction). + * This mapping is logically trivial, but making it go fast enough requires + * considerable care. + * + * Heckbert-style quantizers vary a good deal in their policies for choosing + * the "largest" box and deciding where to cut it. The particular policies + * used here have proved out well in experimental comparisons, but better ones + * may yet be found. + * + * In earlier versions of the IJG code, this module quantized in YCbCr color + * space, processing the raw upsampled data without a color conversion step. + * This allowed the color conversion math to be done only once per colormap + * entry, not once per pixel. However, that optimization precluded other + * useful optimizations (such as merging color conversion with upsampling) + * and it also interfered with desired capabilities such as quantizing to an + * externally-supplied colormap. We have therefore abandoned that approach. + * The present code works in the post-conversion color space, typically RGB. + * + * To improve the visual quality of the results, we actually work in scaled + * RGB space, giving G distances more weight than R, and R in turn more than + * B. To do everything in integer math, we must use integer scale factors. + * The 2/3/1 scale factors used here correspond loosely to the relative + * weights of the colors in the NTSC grayscale equation. + * If you want to use this code to quantize a non-RGB color space, you'll + * probably need to change these scale factors. + */ + +#define R_SCALE 2 /* scale R distances by this much */ +#define G_SCALE 3 /* scale G distances by this much */ +#define B_SCALE 1 /* and B by this much */ + +/* Relabel R/G/B as components 0/1/2, respecting the RGB ordering defined + * in jmorecfg.h. As the code stands, it will do the right thing for R,G,B + * and B,G,R orders. If you define some other weird order in jmorecfg.h, + * you'll get compile errors until you extend this logic. In that case + * you'll probably want to tweak the histogram sizes too. + */ + +#if defined(__OS2__) + +#if RGB_RED_OS2 == 0 +#define C0_SCALE R_SCALE +#endif +#if RGB_BLUE_OS2 == 0 +#define C0_SCALE B_SCALE +#endif +#if RGB_GREEN_OS2 == 1 +#define C1_SCALE G_SCALE +#endif +#if RGB_RED_OS2 == 2 +#define C2_SCALE R_SCALE +#endif +#if RGB_BLUE_OS2 == 2 +#define C2_SCALE B_SCALE +#endif + +#else + +#if RGB_RED == 0 +#define C0_SCALE R_SCALE +#endif +#if RGB_BLUE == 0 +#define C0_SCALE B_SCALE +#endif +#if RGB_GREEN == 1 +#define C1_SCALE G_SCALE +#endif +#if RGB_RED == 2 +#define C2_SCALE R_SCALE +#endif +#if RGB_BLUE == 2 +#define C2_SCALE B_SCALE +#endif + +#endif + +/* + * First we have the histogram data structure and routines for creating it. + * + * The number of bits of precision can be adjusted by changing these symbols. + * We recommend keeping 6 bits for G and 5 each for R and B. + * If you have plenty of memory and cycles, 6 bits all around gives marginally + * better results; if you are short of memory, 5 bits all around will save + * some space but degrade the results. + * To maintain a fully accurate histogram, we'd need to allocate a "long" + * (preferably unsigned long) for each cell. In practice this is overkill; + * we can get by with 16 bits per cell. Few of the cell counts will overflow, + * and clamping those that do overflow to the maximum value will give close- + * enough results. This reduces the recommended histogram size from 256Kb + * to 128Kb, which is a useful savings on PC-class machines. + * (In the second pass the histogram space is re-used for pixel mapping data; + * in that capacity, each cell must be able to store zero to the number of + * desired colors. 16 bits/cell is plenty for that too.) + * Since the JPEG code is intended to run in small memory model on 80x86 + * machines, we can't just allocate the histogram in one chunk. Instead + * of a true 3-D array, we use a row of pointers to 2-D arrays. Each + * pointer corresponds to a C0 value (typically 2^5 = 32 pointers) and + * each 2-D array has 2^6*2^5 = 2048 or 2^6*2^6 = 4096 entries. Note that + * on 80x86 machines, the pointer row is in near memory but the actual + * arrays are in far memory (same arrangement as we use for image arrays). + */ + +#define MAXNUMCOLORS (MAXJSAMPLE+1) /* maximum size of colormap */ + +/* These will do the right thing for either R,G,B or B,G,R color order, + * but you may not like the results for other color orders. + */ +#define HIST_C0_BITS 5 /* bits of precision in R/B histogram */ +#define HIST_C1_BITS 6 /* bits of precision in G histogram */ +#define HIST_C2_BITS 5 /* bits of precision in B/R histogram */ + +/* Number of elements along histogram axes. */ +#define HIST_C0_ELEMS (1<cquantize; + register JSAMPROW ptr; + register histptr histp; + register hist3d histogram = cquantize->histogram; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + ptr = input_buf[row]; + for (col = width; col > 0; col--) { + + { + + /* get pixel value and index into the histogram */ + histp = & histogram[GETJSAMPLE(ptr[0]) >> C0_SHIFT] + [GETJSAMPLE(ptr[1]) >> C1_SHIFT] + [GETJSAMPLE(ptr[2]) >> C2_SHIFT]; + /* increment, check for overflow and undo increment if so. */ + if (++(*histp) <= 0) + (*histp)--; + } + ptr += 3; + } + } +} + + +/* + * Next we have the really interesting routines: selection of a colormap + * given the completed histogram. + * These routines work with a list of "boxes", each representing a rectangular + * subset of the input color space (to histogram precision). + */ + +typedef struct { + /* The bounds of the box (inclusive); expressed as histogram indexes */ + int c0min, c0max; + int c1min, c1max; + int c2min, c2max; + /* The volume (actually 2-norm) of the box */ + INT32 volume; + /* The number of nonzero histogram cells within this box */ + long colorcount; +} box; + +typedef box * boxptr; + + +boxptr +find_biggest_color_pop (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest color population */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register long maxc = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->colorcount > maxc && boxp->volume > 0) { + which = boxp; + maxc = boxp->colorcount; + } + } + return which; +} + + +boxptr +find_biggest_volume (boxptr boxlist, int numboxes) +/* Find the splittable box with the largest (scaled) volume */ +/* Returns NULL if no splittable boxes remain */ +{ + register boxptr boxp; + register int i; + register INT32 maxv = 0; + boxptr which = NULL; + + for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { + if (boxp->volume > maxv) { + which = boxp; + maxv = boxp->volume; + } + } + return which; +} + + +void +update_box (j_decompress_ptr cinfo, boxptr boxp) +/* Shrink the min/max bounds of a box to enclose only nonzero elements, */ +/* and recompute its volume and population */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + INT32 dist0,dist1,dist2; + long ccount; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + if (c0max > c0min) + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0min = c0min = c0; + goto have_c0min; + } + } + have_c0min: + if (c0max > c0min) + for (c0 = c0max; c0 >= c0min; c0--) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c0max = c0max = c0; + goto have_c0max; + } + } + have_c0max: + if (c1max > c1min) + for (c1 = c1min; c1 <= c1max; c1++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1min = c1min = c1; + goto have_c1min; + } + } + have_c1min: + if (c1max > c1min) + for (c1 = c1max; c1 >= c1min; c1--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) + if (*histp++ != 0) { + boxp->c1max = c1max = c1; + goto have_c1max; + } + } + have_c1max: + if (c2max > c2min) + for (c2 = c2min; c2 <= c2max; c2++) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2min = c2min = c2; + goto have_c2min; + } + } + have_c2min: + if (c2max > c2min) + for (c2 = c2max; c2 >= c2min; c2--) + for (c0 = c0min; c0 <= c0max; c0++) { + histp = & histogram[c0][c1min][c2]; + for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) + if (*histp != 0) { + boxp->c2max = c2max = c2; + goto have_c2max; + } + } + have_c2max: + + /* Update box volume. + * We use 2-norm rather than real volume here; this biases the method + * against making long narrow boxes, and it has the side benefit that + * a box is splittable iff norm > 0. + * Since the differences are expressed in histogram-cell units, + * we have to shift back to JSAMPLE units to get consistent distances; + * after which, we scale according to the selected distance scale factors. + */ + dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE; + dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE; + dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE; + boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2; + + /* Now scan remaining volume of box and compute population */ + ccount = 0; + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++, histp++) + if (*histp != 0) { + ccount++; + } + } + boxp->colorcount = ccount; +} + + +int +median_cut (j_decompress_ptr cinfo, boxptr boxlist, int numboxes, + int desired_colors) +/* Repeatedly select and split the largest box until we have enough boxes */ +{ + int n,lb; + int c0,c1,c2,cmax; + register boxptr b1,b2; + + while (numboxes < desired_colors) { + /* Select box to split. + * Current algorithm: by population for first half, then by volume. + */ + if ((numboxes*2) <= desired_colors) { + b1 = find_biggest_color_pop(boxlist, numboxes); + } else { + b1 = find_biggest_volume(boxlist, numboxes); + } + if (b1 == NULL) /* no splittable boxes left! */ + break; + b2 = &boxlist[numboxes]; /* where new box will go */ + /* Copy the color bounds to the new box. */ + b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max; + b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min; + /* Choose which axis to split the box on. + * Current algorithm: longest scaled axis. + * See notes in update_box about scaling distances. + */ + c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE; + c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE; + c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE; + /* We want to break any ties in favor of green, then red, blue last. + * This code does the right thing for R,G,B or B,G,R color orders only. + */ +#if defined(__VISAGECPP__) + +#if RGB_RED_OS2 == 0 + cmax = c1; n = 1; + if (c0 > cmax) { cmax = c0; n = 0; } + if (c2 > cmax) { n = 2; } +#else + cmax = c1; n = 1; + if (c2 > cmax) { cmax = c2; n = 2; } + if (c0 > cmax) { n = 0; } +#endif + +#else + +#if RGB_RED == 0 + cmax = c1; n = 1; + if (c0 > cmax) { cmax = c0; n = 0; } + if (c2 > cmax) { n = 2; } +#else + cmax = c1; n = 1; + if (c2 > cmax) { cmax = c2; n = 2; } + if (c0 > cmax) { n = 0; } +#endif + +#endif + /* Choose split point along selected axis, and update box bounds. + * Current algorithm: split at halfway point. + * (Since the box has been shrunk to minimum volume, + * any split will produce two nonempty subboxes.) + * Note that lb value is max for lower box, so must be < old max. + */ + switch (n) { + case 0: + lb = (b1->c0max + b1->c0min) / 2; + b1->c0max = lb; + b2->c0min = lb+1; + break; + case 1: + lb = (b1->c1max + b1->c1min) / 2; + b1->c1max = lb; + b2->c1min = lb+1; + break; + case 2: + lb = (b1->c2max + b1->c2min) / 2; + b1->c2max = lb; + b2->c2min = lb+1; + break; + } + /* Update stats for boxes */ + update_box(cinfo, b1); + update_box(cinfo, b2); + numboxes++; + } + return numboxes; +} + + +void +compute_color (j_decompress_ptr cinfo, boxptr boxp, int icolor) +/* Compute representative color for a box, put it in colormap[icolor] */ +{ + /* Current algorithm: mean weighted by pixels (not colors) */ + /* Note it is important to get the rounding correct! */ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + histptr histp; + int c0,c1,c2; + int c0min,c0max,c1min,c1max,c2min,c2max; + long count; + long total = 0; + long c0total = 0; + long c1total = 0; + long c2total = 0; + + c0min = boxp->c0min; c0max = boxp->c0max; + c1min = boxp->c1min; c1max = boxp->c1max; + c2min = boxp->c2min; c2max = boxp->c2max; + + for (c0 = c0min; c0 <= c0max; c0++) + for (c1 = c1min; c1 <= c1max; c1++) { + histp = & histogram[c0][c1][c2min]; + for (c2 = c2min; c2 <= c2max; c2++) { + if ((count = *histp++) != 0) { + total += count; + c0total += ((c0 << C0_SHIFT) + ((1<>1)) * count; + c1total += ((c1 << C1_SHIFT) + ((1<>1)) * count; + c2total += ((c2 << C2_SHIFT) + ((1<>1)) * count; + } + } + } + + cinfo->colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); + cinfo->colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); + cinfo->colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); +} + + +static void +select_colors (j_decompress_ptr cinfo, int desired_colors) +/* Master routine for color selection */ +{ + boxptr boxlist; + int numboxes; + int i; + + /* Allocate workspace for box list */ + boxlist = (boxptr) malloc(desired_colors * sizeof(box)); + /* Initialize one box containing whole space */ + numboxes = 1; + boxlist[0].c0min = 0; + boxlist[0].c0max = MAXJSAMPLE >> C0_SHIFT; + boxlist[0].c1min = 0; + boxlist[0].c1max = MAXJSAMPLE >> C1_SHIFT; + boxlist[0].c2min = 0; + boxlist[0].c2max = MAXJSAMPLE >> C2_SHIFT; + /* Shrink it to actually-used volume and set its statistics */ + update_box(cinfo, & boxlist[0]); + /* Perform median-cut to produce final box list */ + numboxes = median_cut(cinfo, boxlist, numboxes, desired_colors); + /* Compute the representative color for each box, fill colormap */ + for (i = 0; i < numboxes; i++) + compute_color(cinfo, & boxlist[i], i); + cinfo->actual_number_of_colors = numboxes; + + free(boxlist); //FIXME?? I don't know if this is correct - VS +} + + +/* + * These routines are concerned with the time-critical task of mapping input + * colors to the nearest color in the selected colormap. + * + * We re-use the histogram space as an "inverse color map", essentially a + * cache for the results of nearest-color searches. All colors within a + * histogram cell will be mapped to the same colormap entry, namely the one + * closest to the cell's center. This may not be quite the closest entry to + * the actual input color, but it's almost as good. A zero in the cache + * indicates we haven't found the nearest color for that cell yet; the array + * is cleared to zeroes before starting the mapping pass. When we find the + * nearest color for a cell, its colormap index plus one is recorded in the + * cache for future use. The pass2 scanning routines call fill_inverse_cmap + * when they need to use an unfilled entry in the cache. + * + * Our method of efficiently finding nearest colors is based on the "locally + * sorted search" idea described by Heckbert and on the incremental distance + * calculation described by Spencer W. Thomas in chapter III.1 of Graphics + * Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that + * the distances from a given colormap entry to each cell of the histogram can + * be computed quickly using an incremental method: the differences between + * distances to adjacent cells themselves differ by a constant. This allows a + * fairly fast implementation of the "brute force" approach of computing the + * distance from every colormap entry to every histogram cell. Unfortunately, + * it needs a work array to hold the best-distance-so-far for each histogram + * cell (because the inner loop has to be over cells, not colormap entries). + * The work array elements have to be INT32s, so the work array would need + * 256Kb at our recommended precision. This is not feasible in DOS machines. + * + * To get around these problems, we apply Thomas' method to compute the + * nearest colors for only the cells within a small subbox of the histogram. + * The work array need be only as big as the subbox, so the memory usage + * problem is solved. Furthermore, we need not fill subboxes that are never + * referenced in pass2; many images use only part of the color gamut, so a + * fair amount of work is saved. An additional advantage of this + * approach is that we can apply Heckbert's locality criterion to quickly + * eliminate colormap entries that are far away from the subbox; typically + * three-fourths of the colormap entries are rejected by Heckbert's criterion, + * and we need not compute their distances to individual cells in the subbox. + * The speed of this approach is heavily influenced by the subbox size: too + * small means too much overhead, too big loses because Heckbert's criterion + * can't eliminate as many colormap entries. Empirically the best subbox + * size seems to be about 1/512th of the histogram (1/8th in each direction). + * + * Thomas' article also describes a refined method which is asymptotically + * faster than the brute-force method, but it is also far more complex and + * cannot efficiently be applied to small subboxes. It is therefore not + * useful for programs intended to be portable to DOS machines. On machines + * with plenty of memory, filling the whole histogram in one shot with Thomas' + * refined method might be faster than the present code --- but then again, + * it might not be any faster, and it's certainly more complicated. + */ + + +/* log2(histogram cells in update box) for each axis; this can be adjusted */ +#define BOX_C0_LOG (HIST_C0_BITS-3) +#define BOX_C1_LOG (HIST_C1_BITS-3) +#define BOX_C2_LOG (HIST_C2_BITS-3) + +#define BOX_C0_ELEMS (1<actual_number_of_colors; + int maxc0, maxc1, maxc2; + int centerc0, centerc1, centerc2; + int i, x, ncolors; + INT32 minmaxdist, min_dist, max_dist, tdist; + INT32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */ + + /* Compute true coordinates of update box's upper corner and center. + * Actually we compute the coordinates of the center of the upper-corner + * histogram cell, which are the upper bounds of the volume we care about. + * Note that since ">>" rounds down, the "center" values may be closer to + * min than to max; hence comparisons to them must be "<=", not "<". + */ + maxc0 = minc0 + ((1 << BOX_C0_SHIFT) - (1 << C0_SHIFT)); + centerc0 = (minc0 + maxc0) >> 1; + maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT)); + centerc1 = (minc1 + maxc1) >> 1; + maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT)); + centerc2 = (minc2 + maxc2) >> 1; + + /* For each color in colormap, find: + * 1. its minimum squared-distance to any point in the update box + * (zero if color is within update box); + * 2. its maximum squared-distance to any point in the update box. + * Both of these can be found by considering only the corners of the box. + * We save the minimum distance for each color in mindist[]; + * only the smallest maximum distance is of interest. + */ + minmaxdist = 0x7FFFFFFFL; + + for (i = 0; i < numcolors; i++) { + /* We compute the squared-c0-distance term, then add in the other two. */ + x = GETJSAMPLE(cinfo->colormap[0][i]); + if (x < minc0) { + tdist = (x - minc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else if (x > maxc0) { + tdist = (x - maxc0) * C0_SCALE; + min_dist = tdist*tdist; + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + min_dist = 0; + if (x <= centerc0) { + tdist = (x - maxc0) * C0_SCALE; + max_dist = tdist*tdist; + } else { + tdist = (x - minc0) * C0_SCALE; + max_dist = tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[1][i]); + if (x < minc1) { + tdist = (x - minc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc1) { + tdist = (x - maxc1) * C1_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc1) { + tdist = (x - maxc1) * C1_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc1) * C1_SCALE; + max_dist += tdist*tdist; + } + } + + x = GETJSAMPLE(cinfo->colormap[2][i]); + if (x < minc2) { + tdist = (x - minc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else if (x > maxc2) { + tdist = (x - maxc2) * C2_SCALE; + min_dist += tdist*tdist; + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + /* within cell range so no contribution to min_dist */ + if (x <= centerc2) { + tdist = (x - maxc2) * C2_SCALE; + max_dist += tdist*tdist; + } else { + tdist = (x - minc2) * C2_SCALE; + max_dist += tdist*tdist; + } + } + + mindist[i] = min_dist; /* save away the results */ + if (max_dist < minmaxdist) + minmaxdist = max_dist; + } + + /* Now we know that no cell in the update box is more than minmaxdist + * away from some colormap entry. Therefore, only colors that are + * within minmaxdist of some part of the box need be considered. + */ + ncolors = 0; + for (i = 0; i < numcolors; i++) { + if (mindist[i] <= minmaxdist) + colorlist[ncolors++] = (JSAMPLE) i; + } + return ncolors; +} + + +static void +find_best_colors (j_decompress_ptr cinfo, int minc0, int minc1, int minc2, + int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[]) +/* Find the closest colormap entry for each cell in the update box, + * given the list of candidate colors prepared by find_nearby_colors. + * Return the indexes of the closest entries in the bestcolor[] array. + * This routine uses Thomas' incremental distance calculation method to + * find the distance from a colormap entry to successive cells in the box. + */ +{ + int ic0, ic1, ic2; + int i, icolor; + register INT32 * bptr; /* pointer into bestdist[] array */ + JSAMPLE * cptr; /* pointer into bestcolor[] array */ + INT32 dist0, dist1; /* initial distance values */ + register INT32 dist2; /* current distance in inner loop */ + INT32 xx0, xx1; /* distance increments */ + register INT32 xx2; + INT32 inc0, inc1, inc2; /* initial values for increments */ + /* This array holds the distance to the nearest-so-far color for each cell */ + INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Initialize best-distance for each cell of the update box */ + bptr = bestdist; + for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--) + *bptr++ = 0x7FFFFFFFL; + + /* For each color selected by find_nearby_colors, + * compute its distance to the center of each cell in the box. + * If that's less than best-so-far, update best distance and color number. + */ + + /* Nominal steps between cell centers ("x" in Thomas article) */ +#define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE) +#define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE) +#define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE) + + for (i = 0; i < numcolors; i++) { + icolor = GETJSAMPLE(colorlist[i]); + /* Compute (square of) distance from minc0/c1/c2 to this color */ + inc0 = (minc0 - GETJSAMPLE(cinfo->colormap[0][icolor])) * C0_SCALE; + dist0 = inc0*inc0; + inc1 = (minc1 - GETJSAMPLE(cinfo->colormap[1][icolor])) * C1_SCALE; + dist0 += inc1*inc1; + inc2 = (minc2 - GETJSAMPLE(cinfo->colormap[2][icolor])) * C2_SCALE; + dist0 += inc2*inc2; + /* Form the initial difference increments */ + inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; + inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; + inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; + /* Now loop over all cells in box, updating distance per Thomas method */ + bptr = bestdist; + cptr = bestcolor; + xx0 = inc0; + for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) { + dist1 = dist0; + xx1 = inc1; + for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) { + dist2 = dist1; + xx2 = inc2; + for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) { + if (dist2 < *bptr) { + *bptr = dist2; + *cptr = (JSAMPLE) icolor; + } + dist2 += xx2; + xx2 += 2 * STEP_C2 * STEP_C2; + bptr++; + cptr++; + } + dist1 += xx1; + xx1 += 2 * STEP_C1 * STEP_C1; + } + dist0 += xx0; + xx0 += 2 * STEP_C0 * STEP_C0; + } + } +} + + +static void +fill_inverse_cmap (j_decompress_ptr cinfo, int c0, int c1, int c2) +/* Fill the inverse-colormap entries in the update box that contains */ +/* histogram cell c0/c1/c2. (Only that one cell MUST be filled, but */ +/* we can fill as many others as we wish.) */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + int minc0, minc1, minc2; /* lower left corner of update box */ + int ic0, ic1, ic2; + register JSAMPLE * cptr; /* pointer into bestcolor[] array */ + register histptr cachep; /* pointer into main cache array */ + /* This array lists the candidate colormap indexes. */ + JSAMPLE colorlist[MAXNUMCOLORS]; + int numcolors; /* number of candidate colors */ + /* This array holds the actually closest colormap index for each cell. */ + JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; + + /* Convert cell coordinates to update box ID */ + c0 >>= BOX_C0_LOG; + c1 >>= BOX_C1_LOG; + c2 >>= BOX_C2_LOG; + + /* Compute true coordinates of update box's origin corner. + * Actually we compute the coordinates of the center of the corner + * histogram cell, which are the lower bounds of the volume we care about. + */ + minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1); + minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1); + minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1); + + /* Determine which colormap entries are close enough to be candidates + * for the nearest entry to some cell in the update box. + */ + numcolors = find_nearby_colors(cinfo, minc0, minc1, minc2, colorlist); + + /* Determine the actually nearest colors. */ + find_best_colors(cinfo, minc0, minc1, minc2, numcolors, colorlist, + bestcolor); + + /* Save the best color numbers (plus 1) in the main cache array */ + c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */ + c1 <<= BOX_C1_LOG; + c2 <<= BOX_C2_LOG; + cptr = bestcolor; + for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) { + for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) { + cachep = & histogram[c0+ic0][c1+ic1][c2]; + for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) { + *cachep++ = (histcell) (GETJSAMPLE(*cptr++) + 1); + } + } + } +} + + +/* + * Map some rows of pixels to the output colormapped representation. + */ + +void +pass2_no_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs no dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register JSAMPROW inptr, outptr; + register histptr cachep; + register int c0, c1, c2; + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + for (col = width; col > 0; col--) { + /* get pixel value and index into the cache */ + c0 = GETJSAMPLE(*inptr++) >> C0_SHIFT; + c1 = GETJSAMPLE(*inptr++) >> C1_SHIFT; + c2 = GETJSAMPLE(*inptr++) >> C2_SHIFT; + cachep = & histogram[c0][c1][c2]; + /* If we have not seen this color before, find nearest colormap entry */ + /* and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, c0,c1,c2); + /* Now emit the colormap index for this cell */ + *outptr++ = (JSAMPLE) (*cachep - 1); + } + } +} + + +void +pass2_fs_dither (j_decompress_ptr cinfo, + JSAMPARRAY input_buf, JSAMPARRAY output_buf, int num_rows) +/* This version performs Floyd-Steinberg dithering */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */ + LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */ + LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */ + register FSERRPTR errorptr; /* => fserrors[] at column before current */ + JSAMPROW inptr; /* => current input pixel */ + JSAMPROW outptr; /* => current output pixel */ + histptr cachep; + int dir; /* +1 or -1 depending on direction */ + int dir3; /* 3*dir, for advancing inptr & errorptr */ + int row; + JDIMENSION col; + JDIMENSION width = cinfo->output_width; + JSAMPLE *range_limit = cinfo->sample_range_limit; + int *error_limit = cquantize->error_limiter; + JSAMPROW colormap0 = cinfo->colormap[0]; + JSAMPROW colormap1 = cinfo->colormap[1]; + JSAMPROW colormap2 = cinfo->colormap[2]; + + + for (row = 0; row < num_rows; row++) { + inptr = input_buf[row]; + outptr = output_buf[row]; + if (cquantize->on_odd_row) { + /* work right to left in this row */ + inptr += (width-1) * 3; /* so point to rightmost pixel */ + outptr += width-1; + dir = -1; + dir3 = -3; + errorptr = cquantize->fserrors + (width+1)*3; /* => entry after last column */ + cquantize->on_odd_row = false; /* flip for next time */ + } else { + /* work left to right in this row */ + dir = 1; + dir3 = 3; + errorptr = cquantize->fserrors; /* => entry before first real column */ + cquantize->on_odd_row = true; /* flip for next time */ + } + /* Preset error values: no error propagated to first pixel from left */ + cur0 = cur1 = cur2 = 0; + /* and no error propagated to row below yet */ + belowerr0 = belowerr1 = belowerr2 = 0; + bpreverr0 = bpreverr1 = bpreverr2 = 0; + + for (col = width; col > 0; col--) { + /* curN holds the error propagated from the previous pixel on the + * current line. Add the error propagated from the previous line + * to form the complete error correction term for this pixel, and + * round the error term (which is expressed * 16) to an integer. + * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct + * for either sign of the error value. + * Note: errorptr points to *previous* column's array entry. + */ + cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4); + cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4); + cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4); + /* Limit the error using transfer function set by init_error_limit. + * See comments with init_error_limit for rationale. + */ + cur0 = error_limit[cur0]; + cur1 = error_limit[cur1]; + cur2 = error_limit[cur2]; + /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE. + * The maximum error is +- MAXJSAMPLE (or less with error limiting); + * this sets the required size of the range_limit array. + */ + cur0 += GETJSAMPLE(inptr[0]); + cur1 += GETJSAMPLE(inptr[1]); + cur2 += GETJSAMPLE(inptr[2]); + cur0 = GETJSAMPLE(range_limit[cur0]); + cur1 = GETJSAMPLE(range_limit[cur1]); + cur2 = GETJSAMPLE(range_limit[cur2]); + /* Index into the cache with adjusted pixel value */ + cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT]; + /* If we have not seen this color before, find nearest colormap */ + /* entry and update the cache */ + if (*cachep == 0) + fill_inverse_cmap(cinfo, cur0>>C0_SHIFT,cur1>>C1_SHIFT,cur2>>C2_SHIFT); + /* Now emit the colormap index for this cell */ + { register int pixcode = *cachep - 1; + *outptr = (JSAMPLE) pixcode; + /* Compute representation error for this pixel */ + cur0 -= GETJSAMPLE(colormap0[pixcode]); + cur1 -= GETJSAMPLE(colormap1[pixcode]); + cur2 -= GETJSAMPLE(colormap2[pixcode]); + } + /* Compute error fractions to be propagated to adjacent pixels. + * Add these into the running sums, and simultaneously shift the + * next-line error sums left by 1 column. + */ + { register LOCFSERROR bnexterr, delta; + + bnexterr = cur0; /* Process component 0 */ + delta = cur0 * 2; + cur0 += delta; /* form error * 3 */ + errorptr[0] = (FSERROR) (bpreverr0 + cur0); + cur0 += delta; /* form error * 5 */ + bpreverr0 = belowerr0 + cur0; + belowerr0 = bnexterr; + cur0 += delta; /* form error * 7 */ + bnexterr = cur1; /* Process component 1 */ + delta = cur1 * 2; + cur1 += delta; /* form error * 3 */ + errorptr[1] = (FSERROR) (bpreverr1 + cur1); + cur1 += delta; /* form error * 5 */ + bpreverr1 = belowerr1 + cur1; + belowerr1 = bnexterr; + cur1 += delta; /* form error * 7 */ + bnexterr = cur2; /* Process component 2 */ + delta = cur2 * 2; + cur2 += delta; /* form error * 3 */ + errorptr[2] = (FSERROR) (bpreverr2 + cur2); + cur2 += delta; /* form error * 5 */ + bpreverr2 = belowerr2 + cur2; + belowerr2 = bnexterr; + cur2 += delta; /* form error * 7 */ + } + /* At this point curN contains the 7/16 error value to be propagated + * to the next pixel on the current line, and all the errors for the + * next line have been shifted over. We are therefore ready to move on. + */ + inptr += dir3; /* Advance pixel pointers to next column */ + outptr += dir; + errorptr += dir3; /* advance errorptr to current column */ + } + /* Post-loop cleanup: we must unload the final error values into the + * final fserrors[] entry. Note we need not unload belowerrN because + * it is for the dummy column before or after the actual array. + */ + errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */ + errorptr[1] = (FSERROR) bpreverr1; + errorptr[2] = (FSERROR) bpreverr2; + } +} + + +/* + * Initialize the error-limiting transfer function (lookup table). + * The raw F-S error computation can potentially compute error values of up to + * +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be + * much less, otherwise obviously wrong pixels will be created. (Typical + * effects include weird fringes at color-area boundaries, isolated bright + * pixels in a dark area, etc.) The standard advice for avoiding this problem + * is to ensure that the "corners" of the color cube are allocated as output + * colors; then repeated errors in the same direction cannot cause cascading + * error buildup. However, that only prevents the error from getting + * completely out of hand; Aaron Giles reports that error limiting improves + * the results even with corner colors allocated. + * A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty + * well, but the smoother transfer function used below is even better. Thanks + * to Aaron Giles for this idea. + */ + +static void +init_error_limit (j_decompress_ptr cinfo) +/* Allocate and fill in the error_limiter table */ +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + int * table; + int in, out; + + table = (int *) malloc((MAXJSAMPLE*2+1) * sizeof(int)); + table += MAXJSAMPLE; /* so can index -MAXJSAMPLE .. +MAXJSAMPLE */ + cquantize->error_limiter = table; + +#define STEPSIZE ((MAXJSAMPLE+1)/16) + /* Map errors 1:1 up to +- MAXJSAMPLE/16 */ + out = 0; + for (in = 0; in < STEPSIZE; in++, out++) { + table[in] = out; table[-in] = -out; + } + /* Map errors 1:2 up to +- 3*MAXJSAMPLE/16 */ + for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) { + table[in] = out; table[-in] = -out; + } + /* Clamp the rest to final out value (which is (MAXJSAMPLE+1)/8) */ + for (; in <= MAXJSAMPLE; in++) { + table[in] = out; table[-in] = -out; + } +#undef STEPSIZE +} + + +/* + * Finish up at the end of each pass. + */ + +void +finish_pass1 (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Select the representative colors and fill in cinfo->colormap */ + cinfo->colormap = cquantize->sv_colormap; + select_colors(cinfo, cquantize->desired); + /* Force next pass to zero the color index table */ + cquantize->needs_zeroed = true; +} + + +void +finish_pass2 (j_decompress_ptr WXUNUSED(cinfo)) +{ + /* no work */ +} + + +/* + * Initialize for each processing pass. + */ + +void +start_pass_2_quant (j_decompress_ptr cinfo, bool is_pre_scan) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + hist3d histogram = cquantize->histogram; + + if (is_pre_scan) { + /* Set up method pointers */ + cquantize->pub.color_quantize = prescan_quantize; + cquantize->pub.finish_pass = finish_pass1; + cquantize->needs_zeroed = true; /* Always zero histogram */ + } else { + /* Set up method pointers */ + cquantize->pub.color_quantize = pass2_fs_dither; + cquantize->pub.finish_pass = finish_pass2; + + { + size_t arraysize = (size_t) ((cinfo->output_width + 2) * + (3 * sizeof(FSERROR))); + /* Allocate Floyd-Steinberg workspace if we didn't already. */ + if (cquantize->fserrors == NULL) + cquantize->fserrors = (INT16*) malloc(arraysize); + /* Initialize the propagated errors to zero. */ + memset((void *) cquantize->fserrors, 0, arraysize); + /* Make the error-limit table if we didn't already. */ + if (cquantize->error_limiter == NULL) + init_error_limit(cinfo); + cquantize->on_odd_row = false; + } + + } + /* Zero the histogram or inverse color map, if necessary */ + if (cquantize->needs_zeroed) { + for (int i = 0; i < HIST_C0_ELEMS; i++) { + memset((void *) histogram[i], 0, + HIST_C1_ELEMS*HIST_C2_ELEMS * sizeof(histcell)); + } + cquantize->needs_zeroed = false; + } +} + + +/* + * Switch to a new external colormap between output passes. + */ + +void +new_color_map_2_quant (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize = (my_cquantize_ptr) cinfo->cquantize; + + /* Reset the inverse color map */ + cquantize->needs_zeroed = true; +} + + +/* + * Module initialization routine for 2-pass color quantization. + */ + +void +jinit_2pass_quantizer (j_decompress_ptr cinfo) +{ + my_cquantize_ptr cquantize; + int i; + + cquantize = (my_cquantize_ptr) malloc(sizeof(my_cquantizer)); + cinfo->cquantize = (jpeg_color_quantizer *) cquantize; + cquantize->pub.start_pass = start_pass_2_quant; + cquantize->pub.new_color_map = new_color_map_2_quant; + cquantize->fserrors = NULL; /* flag optional arrays not allocated */ + cquantize->error_limiter = NULL; + + + /* Allocate the histogram/inverse colormap storage */ + cquantize->histogram = (hist3d) malloc(HIST_C0_ELEMS * sizeof(hist2d)); + for (i = 0; i < HIST_C0_ELEMS; i++) { + cquantize->histogram[i] = (hist2d) malloc(HIST_C1_ELEMS*HIST_C2_ELEMS * sizeof(histcell)); + } + cquantize->needs_zeroed = true; /* histogram is garbage now */ + + /* Allocate storage for the completed colormap, if required. + * We do this now since it is storage and may affect + * the memory manager's space calculations. + */ + { + /* Make sure color count is acceptable */ + int desired = cinfo->desired_number_of_colors; + + cquantize->sv_colormap = (JSAMPARRAY) malloc(sizeof(JSAMPROW) * 3); + cquantize->sv_colormap[0] = (JSAMPROW) malloc(sizeof(JSAMPLE) * desired); + cquantize->sv_colormap[1] = (JSAMPROW) malloc(sizeof(JSAMPLE) * desired); + cquantize->sv_colormap[2] = (JSAMPROW) malloc(sizeof(JSAMPLE) * desired); + + cquantize->desired = desired; + } + + /* Allocate Floyd-Steinberg workspace if necessary. + * This isn't really needed until pass 2, but again it is storage. + * Although we will cope with a later change in dither_mode, + * we do not promise to honor max_memory_to_use if dither_mode changes. + */ + { + cquantize->fserrors = (FSERRPTR) malloc( + (size_t) ((cinfo->output_width + 2) * (3 * sizeof(FSERROR)))); + /* Might as well create the error-limiting table too. */ + init_error_limit(cinfo); + } +} + + + + + + + + + + +void +prepare_range_limit_table (j_decompress_ptr cinfo) +/* Allocate and fill in the sample_range_limit table */ +{ + JSAMPLE * table; + int i; + + table = (JSAMPLE *) malloc((5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * sizeof(JSAMPLE)); + cinfo->srl_orig = table; + table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */ + cinfo->sample_range_limit = table; + /* First segment of "simple" table: limit[x] = 0 for x < 0 */ + memset(table - (MAXJSAMPLE+1), 0, (MAXJSAMPLE+1) * sizeof(JSAMPLE)); + /* Main part of "simple" table: limit[x] = x */ + for (i = 0; i <= MAXJSAMPLE; i++) + table[i] = (JSAMPLE) i; + table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */ + /* End of simple table, rest of first half of post-IDCT table */ + for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++) + table[i] = MAXJSAMPLE; + /* Second half of post-IDCT table */ + memset(table + (2 * (MAXJSAMPLE+1)), 0, + (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * sizeof(JSAMPLE)); + memcpy(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE), + cinfo->sample_range_limit, CENTERJSAMPLE * sizeof(JSAMPLE)); +} + + + + +/* + * wxQuantize + */ + +IMPLEMENT_DYNAMIC_CLASS(wxQuantize, wxObject) + +void wxQuantize::DoQuantize(unsigned w, unsigned h, unsigned char **in_rows, unsigned char **out_rows, + unsigned char *palette, int desiredNoColours) +{ + j_decompress dec; + my_cquantize_ptr cquantize; + + dec.output_width = w; + dec.desired_number_of_colors = desiredNoColours; + prepare_range_limit_table(&dec); + jinit_2pass_quantizer(&dec); + cquantize = (my_cquantize_ptr) dec.cquantize; + + + cquantize->pub.start_pass(&dec, true); + cquantize->pub.color_quantize(&dec, in_rows, out_rows, h); + cquantize->pub.finish_pass(&dec); + + cquantize->pub.start_pass(&dec, false); + cquantize->pub.color_quantize(&dec, in_rows, out_rows, h); + cquantize->pub.finish_pass(&dec); + + + for (int i = 0; i < dec.desired_number_of_colors; i++) { + palette[3 * i + 0] = dec.colormap[0][i]; + palette[3 * i + 1] = dec.colormap[1][i]; + palette[3 * i + 2] = dec.colormap[2][i]; + } + + for (int ii = 0; ii < HIST_C0_ELEMS; ii++) free(cquantize->histogram[ii]); + free(cquantize->histogram); + free(dec.colormap[0]); + free(dec.colormap[1]); + free(dec.colormap[2]); + free(dec.colormap); + free(dec.srl_orig); + + //free(cquantize->error_limiter); + free((void*)(cquantize->error_limiter - MAXJSAMPLE)); // To reverse what was done to it + + free(cquantize->fserrors); + free(cquantize); +} + +// TODO: somehow make use of the Windows system colours, rather than ignoring them for the +// purposes of quantization. + +bool wxQuantize::Quantize(const wxImage& src, wxImage& dest, + wxPalette** pPalette, + int desiredNoColours, + unsigned char** eightBitData, + int flags) + +{ + int i; + + int windowsSystemColourCount = 20; + + int paletteShift = 0; + + // Shift the palette up by the number of Windows system colours, + // if necessary + if (flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) + paletteShift = windowsSystemColourCount; + + // Make room for the Windows system colours +#ifdef __WXMSW__ + if ((flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) && (desiredNoColours > (256 - windowsSystemColourCount))) + desiredNoColours = 256 - windowsSystemColourCount; +#endif + + // create rows info: + int h = src.GetHeight(); + int w = src.GetWidth(); + unsigned char **rows = new unsigned char *[h]; + unsigned char *imgdt = src.GetData(); + for (i = 0; i < h; i++) + rows[i] = imgdt + 3/*RGB*/ * w * i; + + unsigned char palette[3*256]; + + // This is the image as represented by palette indexes. + unsigned char *data8bit = new unsigned char[w * h]; + unsigned char **outrows = new unsigned char *[h]; + for (i = 0; i < h; i++) + outrows[i] = data8bit + w * i; + + //RGB->palette + DoQuantize(w, h, rows, outrows, palette, desiredNoColours); + + delete[] rows; + delete[] outrows; + + // palette->RGB(max.256) + + if (flags & wxQUANTIZE_FILL_DESTINATION_IMAGE) + { + if (!dest.Ok()) + dest.Create(w, h); + + imgdt = dest.GetData(); + for (i = 0; i < w * h; i++) + { + unsigned char c = data8bit[i]; + imgdt[3 * i + 0/*R*/] = palette[3 * c + 0]; + imgdt[3 * i + 1/*G*/] = palette[3 * c + 1]; + imgdt[3 * i + 2/*B*/] = palette[3 * c + 2]; + } + } + + if (eightBitData && (flags & wxQUANTIZE_RETURN_8BIT_DATA)) + { +#ifdef __WXMSW__ + if (flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) + { + // We need to shift the palette entries up + // to make room for the Windows system colours. + for (i = 0; i < w * h; i++) + data8bit[i] = (unsigned char)(data8bit[i] + paletteShift); + } +#endif + *eightBitData = data8bit; + } + else + delete[] data8bit; + +#if wxUSE_PALETTE + // Make a wxWidgets palette + if (pPalette) + { + unsigned char* r = new unsigned char[256]; + unsigned char* g = new unsigned char[256]; + unsigned char* b = new unsigned char[256]; + +#ifdef __WXMSW__ + // Fill the first 20 entries with Windows system colours + if (flags & wxQUANTIZE_INCLUDE_WINDOWS_COLOURS) + { + HDC hDC = ::GetDC(NULL); + PALETTEENTRY* entries = new PALETTEENTRY[windowsSystemColourCount]; + ::GetSystemPaletteEntries(hDC, 0, windowsSystemColourCount, entries); + ::ReleaseDC(NULL, hDC); + + for (i = 0; i < windowsSystemColourCount; i++) + { + r[i] = entries[i].peRed; + g[i] = entries[i].peGreen; + b[i] = entries[i].peBlue; + } + delete[] entries; + } +#endif + + for (i = 0; i < desiredNoColours; i++) + { + r[i+paletteShift] = palette[i*3 + 0]; + g[i+paletteShift] = palette[i*3 + 1]; + b[i+paletteShift] = palette[i*3 + 2]; + } + + // Blank out any remaining palette entries + for (i = desiredNoColours+paletteShift; i < 256; i++) + { + r[i] = 0; + g[i] = 0; + b[i] = 0; + } + *pPalette = new wxPalette(256, r, g, b); + delete[] r; + delete[] g; + delete[] b; + } +#endif // wxUSE_PALETTE + + return true; +} + +// This version sets a palette in the destination image so you don't +// have to manage it yourself. + +bool wxQuantize::Quantize(const wxImage& src, + wxImage& dest, + int desiredNoColours, + unsigned char** eightBitData, + int flags) +{ + wxPalette* palette = NULL; + if ( !Quantize(src, dest, & palette, desiredNoColours, eightBitData, flags) ) + return false; + +#if wxUSE_PALETTE + if (palette) + { + dest.SetPalette(* palette); + delete palette; + } +#endif // wxUSE_PALETTE + + return true; +} + +#endif + // wxUSE_IMAGE diff --git a/Source/3rd Party/wx/src/common/radiocmn.cpp b/Source/3rd Party/wx/src/common/radiocmn.cpp index 89f28f091..418d4f04f 100644 --- a/Source/3rd Party/wx/src/common/radiocmn.cpp +++ b/Source/3rd Party/wx/src/common/radiocmn.cpp @@ -1,304 +1,304 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/radiocmn.cpp -// Purpose: wxRadioBox methods common to all ports -// Author: Vadim Zeitlin -// Modified by: -// Created: 03.06.01 -// RCS-ID: $Id: radiocmn.cpp 54930 2008-08-02 19:45:23Z VZ $ -// Copyright: (c) 2001 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_RADIOBOX - -#ifndef WX_PRECOMP - #include "wx/radiobox.h" -#endif //WX_PRECOMP - -#if wxUSE_TOOLTIPS - #include "wx/tooltip.h" -#endif // wxUSE_TOOLTIPS - -#if wxUSE_HELP - #include "wx/cshelp.h" -#endif - -// ============================================================================ -// implementation -// ============================================================================ - -void wxRadioBoxBase::SetMajorDim(unsigned int majorDim, long style) -{ - wxCHECK_RET( majorDim != 0, _T("major radiobox dimension can't be 0") ); - - m_majorDim = majorDim; - - int minorDim = (GetCount() + m_majorDim - 1) / m_majorDim; - - if ( style & wxRA_SPECIFY_COLS ) - { - m_numCols = majorDim; - m_numRows = minorDim; - } - else // wxRA_SPECIFY_ROWS - { - m_numCols = minorDim; - m_numRows = majorDim; - } -} - -int wxRadioBoxBase::GetNextItem(int item, wxDirection dir, long style) const -{ - const int itemStart = item; - - int count = GetCount(), - numCols = GetColumnCount(), - numRows = GetRowCount(); - - bool horz = (style & wxRA_SPECIFY_COLS) != 0; - - do - { - switch ( dir ) - { - case wxUP: - if ( horz ) - { - item -= numCols; - } - else // vertical layout - { - if ( !item-- ) - item = count - 1; - } - break; - - case wxLEFT: - if ( horz ) - { - if ( !item-- ) - item = count - 1; - } - else // vertical layout - { - item -= numRows; - } - break; - - case wxDOWN: - if ( horz ) - { - item += numCols; - } - else // vertical layout - { - if ( ++item == count ) - item = 0; - } - break; - - case wxRIGHT: - if ( horz ) - { - if ( ++item == count ) - item = 0; - } - else // vertical layout - { - item += numRows; - } - break; - - default: - wxFAIL_MSG( _T("unexpected wxDirection value") ); - return wxNOT_FOUND; - } - - // ensure that the item is in range [0..count) - if ( item < 0 ) - { - // first map the item to the one in the same column but in the last - // row - item += count; - - // now there are 2 cases: either it is the first item of the last - // row in which case we need to wrap again and get to the last item - // or we can just go to the previous item - if ( item % (horz ? numCols : numRows) ) - item--; - else - item = count - 1; - } - else if ( item >= count ) - { - // same logic as above - item -= count; - - // ... except that we need to check if this is not the last item, - // not the first one - if ( (item + 1) % (horz ? numCols : numRows) ) - item++; - else - item = 0; - } - - wxASSERT_MSG( item < count && item >= 0, - _T("logic error in wxRadioBox::GetNextItem()") ); - } - // we shouldn't select the non-active items, continue looking for a - // visible and shown one unless we came back to the item we started from in - // which case bail out to avoid infinite loop - while ( !(IsItemShown(item) && IsItemEnabled(item)) && item != itemStart ); - - return item; -} - -#if wxUSE_TOOLTIPS - -void wxRadioBoxBase::SetItemToolTip(unsigned int item, const wxString& text) -{ - wxASSERT_MSG( item < GetCount(), _T("Invalid item index") ); - - // extend the array to have entries for all our items on first use - if ( !m_itemsTooltips ) - { - m_itemsTooltips = new wxToolTipArray; - m_itemsTooltips->resize(GetCount()); - } - - wxToolTip *tooltip = (*m_itemsTooltips)[item]; - - bool changed = true; - if ( text.empty() ) - { - if ( tooltip ) - { - // delete the tooltip - delete tooltip; - tooltip = NULL; - } - else // nothing to do - { - changed = false; - } - } - else // non empty tooltip text - { - if ( tooltip ) - { - // just change the existing tooltip text, don't change the tooltip - tooltip->SetTip(text); - changed = false; - } - else // no tooltip yet - { - // create the new one - tooltip = new wxToolTip(text); - } - } - - if ( changed ) - { - (*m_itemsTooltips)[item] = tooltip; - DoSetItemToolTip(item, tooltip); - } -} - -void -wxRadioBoxBase::DoSetItemToolTip(unsigned int WXUNUSED(item), - wxToolTip * WXUNUSED(tooltip)) -{ - // per-item tooltips not implemented by default -} - -#endif // wxUSE_TOOLTIPS - -wxRadioBoxBase::~wxRadioBoxBase() -{ -#if wxUSE_TOOLTIPS - if ( m_itemsTooltips ) - { - const size_t n = m_itemsTooltips->size(); - for ( size_t i = 0; i < n; i++ ) - delete (*m_itemsTooltips)[i]; - - delete m_itemsTooltips; - } -#endif // wxUSE_TOOLTIPS -} - -#if wxUSE_HELP - -// set helptext for a particular item -void wxRadioBoxBase::SetItemHelpText(unsigned int n, const wxString& helpText) -{ - wxCHECK_RET( n < GetCount(), _T("Invalid item index") ); - - if ( m_itemsHelpTexts.empty() ) - { - // once-only initialization of the array: reserve space for all items - m_itemsHelpTexts.Add(wxEmptyString, GetCount()); - } - - m_itemsHelpTexts[n] = helpText; -} - -// retrieve helptext for a particular item -wxString wxRadioBoxBase::GetItemHelpText( unsigned int n ) const -{ - wxCHECK_MSG( n < GetCount(), wxEmptyString, _T("Invalid item index") ); - - return m_itemsHelpTexts.empty() ? wxString() : m_itemsHelpTexts[n]; -} - -// return help text for the item for which wxEVT_HELP was generated. -wxString wxRadioBoxBase::DoGetHelpTextAtPoint(const wxWindow *derived, - const wxPoint& pt, - wxHelpEvent::Origin origin) const -{ - const int item = origin == wxHelpEvent::Origin_HelpButton - ? GetItemFromPoint(pt) - : GetSelection(); - - if ( item != wxNOT_FOUND ) - { - wxString text = GetItemHelpText(wx_static_cast(unsigned int, item)); - if( !text.empty() ) - return text; - } - - return derived->wxWindowBase::GetHelpTextAtPoint(pt, origin); -} - -#endif // wxUSE_HELP - -#if WXWIN_COMPATIBILITY_2_4 - -// these functions are deprecated and don't do anything -int wxRadioBoxBase::GetNumberOfRowsOrCols() const -{ - return 1; -} - -void wxRadioBoxBase::SetNumberOfRowsOrCols(int WXUNUSED(n)) -{ -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -#endif // wxUSE_RADIOBOX +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/radiocmn.cpp +// Purpose: wxRadioBox methods common to all ports +// Author: Vadim Zeitlin +// Modified by: +// Created: 03.06.01 +// RCS-ID: $Id: radiocmn.cpp 54930 2008-08-02 19:45:23Z VZ $ +// Copyright: (c) 2001 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_RADIOBOX + +#ifndef WX_PRECOMP + #include "wx/radiobox.h" +#endif //WX_PRECOMP + +#if wxUSE_TOOLTIPS + #include "wx/tooltip.h" +#endif // wxUSE_TOOLTIPS + +#if wxUSE_HELP + #include "wx/cshelp.h" +#endif + +// ============================================================================ +// implementation +// ============================================================================ + +void wxRadioBoxBase::SetMajorDim(unsigned int majorDim, long style) +{ + wxCHECK_RET( majorDim != 0, _T("major radiobox dimension can't be 0") ); + + m_majorDim = majorDim; + + int minorDim = (GetCount() + m_majorDim - 1) / m_majorDim; + + if ( style & wxRA_SPECIFY_COLS ) + { + m_numCols = majorDim; + m_numRows = minorDim; + } + else // wxRA_SPECIFY_ROWS + { + m_numCols = minorDim; + m_numRows = majorDim; + } +} + +int wxRadioBoxBase::GetNextItem(int item, wxDirection dir, long style) const +{ + const int itemStart = item; + + int count = GetCount(), + numCols = GetColumnCount(), + numRows = GetRowCount(); + + bool horz = (style & wxRA_SPECIFY_COLS) != 0; + + do + { + switch ( dir ) + { + case wxUP: + if ( horz ) + { + item -= numCols; + } + else // vertical layout + { + if ( !item-- ) + item = count - 1; + } + break; + + case wxLEFT: + if ( horz ) + { + if ( !item-- ) + item = count - 1; + } + else // vertical layout + { + item -= numRows; + } + break; + + case wxDOWN: + if ( horz ) + { + item += numCols; + } + else // vertical layout + { + if ( ++item == count ) + item = 0; + } + break; + + case wxRIGHT: + if ( horz ) + { + if ( ++item == count ) + item = 0; + } + else // vertical layout + { + item += numRows; + } + break; + + default: + wxFAIL_MSG( _T("unexpected wxDirection value") ); + return wxNOT_FOUND; + } + + // ensure that the item is in range [0..count) + if ( item < 0 ) + { + // first map the item to the one in the same column but in the last + // row + item += count; + + // now there are 2 cases: either it is the first item of the last + // row in which case we need to wrap again and get to the last item + // or we can just go to the previous item + if ( item % (horz ? numCols : numRows) ) + item--; + else + item = count - 1; + } + else if ( item >= count ) + { + // same logic as above + item -= count; + + // ... except that we need to check if this is not the last item, + // not the first one + if ( (item + 1) % (horz ? numCols : numRows) ) + item++; + else + item = 0; + } + + wxASSERT_MSG( item < count && item >= 0, + _T("logic error in wxRadioBox::GetNextItem()") ); + } + // we shouldn't select the non-active items, continue looking for a + // visible and shown one unless we came back to the item we started from in + // which case bail out to avoid infinite loop + while ( !(IsItemShown(item) && IsItemEnabled(item)) && item != itemStart ); + + return item; +} + +#if wxUSE_TOOLTIPS + +void wxRadioBoxBase::SetItemToolTip(unsigned int item, const wxString& text) +{ + wxASSERT_MSG( item < GetCount(), _T("Invalid item index") ); + + // extend the array to have entries for all our items on first use + if ( !m_itemsTooltips ) + { + m_itemsTooltips = new wxToolTipArray; + m_itemsTooltips->resize(GetCount()); + } + + wxToolTip *tooltip = (*m_itemsTooltips)[item]; + + bool changed = true; + if ( text.empty() ) + { + if ( tooltip ) + { + // delete the tooltip + delete tooltip; + tooltip = NULL; + } + else // nothing to do + { + changed = false; + } + } + else // non empty tooltip text + { + if ( tooltip ) + { + // just change the existing tooltip text, don't change the tooltip + tooltip->SetTip(text); + changed = false; + } + else // no tooltip yet + { + // create the new one + tooltip = new wxToolTip(text); + } + } + + if ( changed ) + { + (*m_itemsTooltips)[item] = tooltip; + DoSetItemToolTip(item, tooltip); + } +} + +void +wxRadioBoxBase::DoSetItemToolTip(unsigned int WXUNUSED(item), + wxToolTip * WXUNUSED(tooltip)) +{ + // per-item tooltips not implemented by default +} + +#endif // wxUSE_TOOLTIPS + +wxRadioBoxBase::~wxRadioBoxBase() +{ +#if wxUSE_TOOLTIPS + if ( m_itemsTooltips ) + { + const size_t n = m_itemsTooltips->size(); + for ( size_t i = 0; i < n; i++ ) + delete (*m_itemsTooltips)[i]; + + delete m_itemsTooltips; + } +#endif // wxUSE_TOOLTIPS +} + +#if wxUSE_HELP + +// set helptext for a particular item +void wxRadioBoxBase::SetItemHelpText(unsigned int n, const wxString& helpText) +{ + wxCHECK_RET( n < GetCount(), _T("Invalid item index") ); + + if ( m_itemsHelpTexts.empty() ) + { + // once-only initialization of the array: reserve space for all items + m_itemsHelpTexts.Add(wxEmptyString, GetCount()); + } + + m_itemsHelpTexts[n] = helpText; +} + +// retrieve helptext for a particular item +wxString wxRadioBoxBase::GetItemHelpText( unsigned int n ) const +{ + wxCHECK_MSG( n < GetCount(), wxEmptyString, _T("Invalid item index") ); + + return m_itemsHelpTexts.empty() ? wxString() : m_itemsHelpTexts[n]; +} + +// return help text for the item for which wxEVT_HELP was generated. +wxString wxRadioBoxBase::DoGetHelpTextAtPoint(const wxWindow *derived, + const wxPoint& pt, + wxHelpEvent::Origin origin) const +{ + const int item = origin == wxHelpEvent::Origin_HelpButton + ? GetItemFromPoint(pt) + : GetSelection(); + + if ( item != wxNOT_FOUND ) + { + wxString text = GetItemHelpText(wx_static_cast(unsigned int, item)); + if( !text.empty() ) + return text; + } + + return derived->wxWindowBase::GetHelpTextAtPoint(pt, origin); +} + +#endif // wxUSE_HELP + +#if WXWIN_COMPATIBILITY_2_4 + +// these functions are deprecated and don't do anything +int wxRadioBoxBase::GetNumberOfRowsOrCols() const +{ + return 1; +} + +void wxRadioBoxBase::SetNumberOfRowsOrCols(int WXUNUSED(n)) +{ +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +#endif // wxUSE_RADIOBOX diff --git a/Source/3rd Party/wx/src/common/regex.cpp b/Source/3rd Party/wx/src/common/regex.cpp index bda88f56f..bd77aafe2 100644 --- a/Source/3rd Party/wx/src/common/regex.cpp +++ b/Source/3rd Party/wx/src/common/regex.cpp @@ -1,689 +1,689 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/regex.cpp -// Purpose: regular expression matching -// Author: Karsten Ballueder and Vadim Zeitlin -// Modified by: -// Created: 13.07.01 -// RCS-ID: $Id: regex.cpp 57779 2009-01-02 17:35:16Z PC $ -// Copyright: (c) 2000 Karsten Ballueder -// 2001 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_REGEX - -#include "wx/regex.h" - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/log.h" - #include "wx/intl.h" -#endif //WX_PRECOMP - -// FreeBSD, Watcom and DMars require this, CW doesn't have nor need it. -// Others also don't seem to need it. If you have an error related to -// (not) including please report details to -// wx-dev@lists.wxwindows.org -#if defined(__UNIX__) || defined(__WATCOMC__) || defined(__DIGITALMARS__) -# include -#endif - -#include - -// WXREGEX_USING_BUILTIN defined when using the built-in regex lib -// WXREGEX_USING_RE_SEARCH defined when using re_search in the GNU regex lib -// WXREGEX_IF_NEED_LEN() wrap the len parameter only used with the built-in -// or GNU regex -// WXREGEX_CONVERT_TO_MB defined when the regex lib is using chars and -// wxChar is wide, so conversion must be done -// WXREGEX_CHAR(x) Convert wxChar to wxRegChar -// -#ifdef __REG_NOFRONT -# define WXREGEX_USING_BUILTIN -# define WXREGEX_IF_NEED_LEN(x) ,x -# define WXREGEX_CHAR(x) x -#else -# ifdef HAVE_RE_SEARCH -# define WXREGEX_IF_NEED_LEN(x) ,x -# define WXREGEX_USING_RE_SEARCH -# else -# define WXREGEX_IF_NEED_LEN(x) -# endif -# if wxUSE_UNICODE -# define WXREGEX_CONVERT_TO_MB -# endif -# define WXREGEX_CHAR(x) wxConvertWX2MB(x) -# define wx_regfree regfree -# define wx_regerror regerror -#endif - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -#ifndef WXREGEX_USING_RE_SEARCH - -// the array of offsets for the matches, the usual POSIX regmatch_t array. -class wxRegExMatches -{ -public: - typedef regmatch_t *match_type; - - wxRegExMatches(size_t n) { m_matches = new regmatch_t[n]; } - ~wxRegExMatches() { delete [] m_matches; } - - // we just use casts here because the fields of regmatch_t struct may be 64 - // bit but we're limited to size_t in our public API and are not going to - // change it because operating on strings longer than 4GB using it is - // absolutely impractical anyhow - size_t Start(size_t n) const - { - return wx_truncate_cast(size_t, m_matches[n].rm_so); - } - - size_t End(size_t n) const - { - return wx_truncate_cast(size_t, m_matches[n].rm_eo); - } - - regmatch_t *get() const { return m_matches; } - -private: - regmatch_t *m_matches; -}; - -#else // WXREGEX_USING_RE_SEARCH - -// the array of offsets for the matches, the struct used by the GNU lib -class wxRegExMatches -{ -public: - typedef re_registers *match_type; - - wxRegExMatches(size_t n) - { - m_matches.num_regs = n; - m_matches.start = new regoff_t[n]; - m_matches.end = new regoff_t[n]; - } - - ~wxRegExMatches() - { - delete [] m_matches.start; - delete [] m_matches.end; - } - - size_t Start(size_t n) const { return m_matches.start[n]; } - size_t End(size_t n) const { return m_matches.end[n]; } - - re_registers *get() { return &m_matches; } - -private: - re_registers m_matches; -}; - -#endif // WXREGEX_USING_RE_SEARCH - -// the character type used by the regular expression engine -#ifndef WXREGEX_CONVERT_TO_MB -typedef wxChar wxRegChar; -#else -typedef char wxRegChar; -#endif - -// the real implementation of wxRegEx -class wxRegExImpl -{ -public: - // ctor and dtor - wxRegExImpl(); - ~wxRegExImpl(); - - // return true if Compile() had been called successfully - bool IsValid() const { return m_isCompiled; } - - // RE operations - bool Compile(const wxString& expr, int flags = 0); - bool Matches(const wxRegChar *str, int flags - WXREGEX_IF_NEED_LEN(size_t len)) const; - bool GetMatch(size_t *start, size_t *len, size_t index = 0) const; - size_t GetMatchCount() const; - int Replace(wxString *pattern, const wxString& replacement, - size_t maxMatches = 0) const; - -private: - // return the string containing the error message for the given err code - wxString GetErrorMsg(int errorcode, bool badconv) const; - - // init the members - void Init() - { - m_isCompiled = false; - m_Matches = NULL; - m_nMatches = 0; - } - - // free the RE if compiled - void Free() - { - if ( IsValid() ) - { - wx_regfree(&m_RegEx); - } - - delete m_Matches; - } - - // free the RE if any and reinit the members - void Reinit() - { - Free(); - Init(); - } - - // compiled RE - regex_t m_RegEx; - - // the subexpressions data - wxRegExMatches *m_Matches; - size_t m_nMatches; - - // true if m_RegEx is valid - bool m_isCompiled; -}; - - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxRegExImpl -// ---------------------------------------------------------------------------- - -wxRegExImpl::wxRegExImpl() -{ - Init(); -} - -wxRegExImpl::~wxRegExImpl() -{ - Free(); -} - -wxString wxRegExImpl::GetErrorMsg(int errorcode, bool badconv) const -{ -#ifdef WXREGEX_CONVERT_TO_MB - // currently only needed when using system library in Unicode mode - if ( badconv ) - { - return _("conversion to 8-bit encoding failed"); - } -#else - // 'use' badconv to avoid a compiler warning - (void)badconv; -#endif - - wxString szError; - - // first get the string length needed - int len = wx_regerror(errorcode, &m_RegEx, NULL, 0); - if ( len > 0 ) - { - char* szcmbError = new char[++len]; - - (void)wx_regerror(errorcode, &m_RegEx, szcmbError, len); - - szError = wxConvertMB2WX(szcmbError); - delete [] szcmbError; - } - else // regerror() returned 0 - { - szError = _("unknown error"); - } - - return szError; -} - -bool wxRegExImpl::Compile(const wxString& expr, int flags) -{ - Reinit(); - -#ifdef WX_NO_REGEX_ADVANCED -# define FLAVORS wxRE_BASIC -#else -# define FLAVORS (wxRE_ADVANCED | wxRE_BASIC) - wxASSERT_MSG( (flags & FLAVORS) != FLAVORS, - _T("incompatible flags in wxRegEx::Compile") ); -#endif - wxASSERT_MSG( !(flags & ~(FLAVORS | wxRE_ICASE | wxRE_NOSUB | wxRE_NEWLINE)), - _T("unrecognized flags in wxRegEx::Compile") ); - - // translate our flags to regcomp() ones - int flagsRE = 0; - if ( !(flags & wxRE_BASIC) ) - { -#ifndef WX_NO_REGEX_ADVANCED - if (flags & wxRE_ADVANCED) - flagsRE |= REG_ADVANCED; - else -#endif - flagsRE |= REG_EXTENDED; - } - - if ( flags & wxRE_ICASE ) - flagsRE |= REG_ICASE; - if ( flags & wxRE_NOSUB ) - flagsRE |= REG_NOSUB; - if ( flags & wxRE_NEWLINE ) - flagsRE |= REG_NEWLINE; - - // compile it -#ifdef WXREGEX_USING_BUILTIN - bool conv = true; - int errorcode = wx_re_comp(&m_RegEx, expr, expr.length(), flagsRE); -#else - const wxWX2MBbuf conv = expr.mbc_str(); - int errorcode = conv ? regcomp(&m_RegEx, conv, flagsRE) : REG_BADPAT; -#endif - - if ( errorcode ) - { - wxLogError(_("Invalid regular expression '%s': %s"), - expr.c_str(), GetErrorMsg(errorcode, !conv).c_str()); - - m_isCompiled = false; - } - else // ok - { - // don't allocate the matches array now, but do it later if necessary - if ( flags & wxRE_NOSUB ) - { - // we don't need it at all - m_nMatches = 0; - } - else - { - // we will alloc the array later (only if really needed) but count - // the number of sub-expressions in the regex right now - - // there is always one for the whole expression - m_nMatches = 1; - - // and some more for bracketed subexperessions - for ( const wxChar *cptr = expr.c_str(); *cptr; cptr++ ) - { - if ( *cptr == _T('\\') ) - { - // in basic RE syntax groups are inside \(...\) - if ( *++cptr == _T('(') && (flags & wxRE_BASIC) ) - { - m_nMatches++; - } - } - else if ( *cptr == _T('(') && !(flags & wxRE_BASIC) ) - { - // we know that the previous character is not an unquoted - // backslash because it would have been eaten above, so we - // have a bare '(' and this indicates a group start for the - // extended syntax. '(?' is used for extensions by perl- - // like REs (e.g. advanced), and is not valid for POSIX - // extended, so ignore them always. - if ( cptr[1] != _T('?') ) - m_nMatches++; - } - } - } - - m_isCompiled = true; - } - - return IsValid(); -} - -#ifdef WXREGEX_USING_RE_SEARCH - -// On GNU, regexec is implemented as a wrapper around re_search. re_search -// requires a length parameter which the POSIX regexec does not have, -// therefore regexec must do a strlen on the search text each time it is -// called. This can drastically affect performance when matching is done in -// a loop along a string, such as during a search and replace. Therefore if -// re_search is detected by configure, it is used directly. -// -static int ReSearch(const regex_t *preg, - const char *text, - size_t len, - re_registers *matches, - int eflags) -{ - regex_t *pattern = wx_const_cast(regex_t*, preg); - - pattern->not_bol = (eflags & REG_NOTBOL) != 0; - pattern->not_eol = (eflags & REG_NOTEOL) != 0; - pattern->regs_allocated = REGS_FIXED; - - int ret = re_search(pattern, text, len, 0, len, matches); - return ret >= 0 ? 0 : REG_NOMATCH; -} - -#endif // WXREGEX_USING_RE_SEARCH - -bool wxRegExImpl::Matches(const wxRegChar *str, - int flags - WXREGEX_IF_NEED_LEN(size_t len)) const -{ - wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); - - // translate our flags to regexec() ones - wxASSERT_MSG( !(flags & ~(wxRE_NOTBOL | wxRE_NOTEOL)), - _T("unrecognized flags in wxRegEx::Matches") ); - - int flagsRE = 0; - if ( flags & wxRE_NOTBOL ) - flagsRE |= REG_NOTBOL; - if ( flags & wxRE_NOTEOL ) - flagsRE |= REG_NOTEOL; - - // allocate matches array if needed - wxRegExImpl *self = wxConstCast(this, wxRegExImpl); - if ( !m_Matches && m_nMatches ) - { - self->m_Matches = new wxRegExMatches(m_nMatches); - } - - wxRegExMatches::match_type matches = m_Matches ? m_Matches->get() : NULL; - - // do match it -#if defined WXREGEX_USING_BUILTIN - int rc = wx_re_exec(&self->m_RegEx, str, len, NULL, m_nMatches, matches, flagsRE); -#elif defined WXREGEX_USING_RE_SEARCH - int rc = str ? ReSearch(&self->m_RegEx, str, len, matches, flagsRE) : REG_BADPAT; -#else - int rc = str ? regexec(&self->m_RegEx, str, m_nMatches, matches, flagsRE) : REG_BADPAT; -#endif - - switch ( rc ) - { - case 0: - // matched successfully - return true; - - default: - // an error occurred - wxLogError(_("Failed to find match for regular expression: %s"), - GetErrorMsg(rc, !str).c_str()); - // fall through - - case REG_NOMATCH: - // no match - return false; - } -} - -bool wxRegExImpl::GetMatch(size_t *start, size_t *len, size_t index) const -{ - wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); - wxCHECK_MSG( m_nMatches, false, _T("can't use with wxRE_NOSUB") ); - wxCHECK_MSG( m_Matches, false, _T("must call Matches() first") ); - wxCHECK_MSG( index < m_nMatches, false, _T("invalid match index") ); - - if ( start ) - *start = m_Matches->Start(index); - if ( len ) - *len = m_Matches->End(index) - m_Matches->Start(index); - - return true; -} - -size_t wxRegExImpl::GetMatchCount() const -{ - wxCHECK_MSG( IsValid(), 0, _T("must successfully Compile() first") ); - wxCHECK_MSG( m_nMatches, 0, _T("can't use with wxRE_NOSUB") ); - - return m_nMatches; -} - -int wxRegExImpl::Replace(wxString *text, - const wxString& replacement, - size_t maxMatches) const -{ - wxCHECK_MSG( text, wxNOT_FOUND, _T("NULL text in wxRegEx::Replace") ); - wxCHECK_MSG( IsValid(), wxNOT_FOUND, _T("must successfully Compile() first") ); - - // the input string -#ifndef WXREGEX_CONVERT_TO_MB - const wxChar *textstr = text->c_str(); - size_t textlen = text->length(); -#else - const wxWX2MBbuf textstr = WXREGEX_CHAR(*text); - if (!textstr) - { - wxLogError(_("Failed to find match for regular expression: %s"), - GetErrorMsg(0, true).c_str()); - return 0; - } - size_t textlen = strlen(textstr); - text->clear(); -#endif - - // the replacement text - wxString textNew; - - // the result, allow 25% extra - wxString result; - result.reserve(5 * textlen / 4); - - // attempt at optimization: don't iterate over the string if it doesn't - // contain back references at all - bool mayHaveBackrefs = - replacement.find_first_of(_T("\\&")) != wxString::npos; - - if ( !mayHaveBackrefs ) - { - textNew = replacement; - } - - // the position where we start looking for the match - size_t matchStart = 0; - - // number of replacement made: we won't make more than maxMatches of them - // (unless maxMatches is 0 which doesn't limit the number of replacements) - size_t countRepl = 0; - - // note that "^" shouldn't match after the first call to Matches() so we - // use wxRE_NOTBOL to prevent it from happening - while ( (!maxMatches || countRepl < maxMatches) && - Matches(textstr + matchStart, - countRepl ? wxRE_NOTBOL : 0 - WXREGEX_IF_NEED_LEN(textlen - matchStart)) ) - { - // the string possibly contains back references: we need to calculate - // the replacement text anew after each match - if ( mayHaveBackrefs ) - { - mayHaveBackrefs = false; - textNew.clear(); - textNew.reserve(replacement.length()); - - for ( const wxChar *p = replacement.c_str(); *p; p++ ) - { - size_t index = (size_t)-1; - - if ( *p == _T('\\') ) - { - if ( wxIsdigit(*++p) ) - { - // back reference - wxChar *end; - index = (size_t)wxStrtoul(p, &end, 10); - p = end - 1; // -1 to compensate for p++ in the loop - } - //else: backslash used as escape character - } - else if ( *p == _T('&') ) - { - // treat this as "\0" for compatbility with ed and such - index = 0; - } - - // do we have a back reference? - if ( index != (size_t)-1 ) - { - // yes, get its text - size_t start, len; - if ( !GetMatch(&start, &len, index) ) - { - wxFAIL_MSG( _T("invalid back reference") ); - - // just eat it... - } - else - { - textNew += wxString(textstr + matchStart + start, - *wxConvCurrent, len); - - mayHaveBackrefs = true; - } - } - else // ordinary character - { - textNew += *p; - } - } - } - - size_t start, len; - if ( !GetMatch(&start, &len) ) - { - // we did have match as Matches() returned true above! - wxFAIL_MSG( _T("internal logic error in wxRegEx::Replace") ); - - return wxNOT_FOUND; - } - - // an insurance against implementations that don't grow exponentially - // to ensure building the result takes linear time - if (result.capacity() < result.length() + start + textNew.length()) - result.reserve(2 * result.length()); - -#ifndef WXREGEX_CONVERT_TO_MB - result.append(*text, matchStart, start); -#else - result.append(wxString(textstr + matchStart, *wxConvCurrent, start)); -#endif - matchStart += start; - result.append(textNew); - - countRepl++; - - matchStart += len; - } - -#ifndef WXREGEX_CONVERT_TO_MB - result.append(*text, matchStart, wxString::npos); -#else - result.append(wxString(textstr + matchStart, *wxConvCurrent)); -#endif - *text = result; - - return countRepl; -} - -// ---------------------------------------------------------------------------- -// wxRegEx: all methods are mostly forwarded to wxRegExImpl -// ---------------------------------------------------------------------------- - -void wxRegEx::Init() -{ - m_impl = NULL; -} - -wxRegEx::~wxRegEx() -{ - delete m_impl; -} - -bool wxRegEx::Compile(const wxString& expr, int flags) -{ - if ( !m_impl ) - { - m_impl = new wxRegExImpl; - } - - if ( !m_impl->Compile(expr, flags) ) - { - // error message already given in wxRegExImpl::Compile - delete m_impl; - m_impl = NULL; - - return false; - } - - return true; -} - -bool wxRegEx::Matches(const wxChar *str, int flags, size_t len) const -{ - wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); - (void)len; - - return m_impl->Matches(WXREGEX_CHAR(str), flags WXREGEX_IF_NEED_LEN(len)); -} - -bool wxRegEx::Matches(const wxChar *str, int flags) const -{ - wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); - - return m_impl->Matches(WXREGEX_CHAR(str), - flags - WXREGEX_IF_NEED_LEN(wxStrlen(str))); -} - -bool wxRegEx::GetMatch(size_t *start, size_t *len, size_t index) const -{ - wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); - - return m_impl->GetMatch(start, len, index); -} - -wxString wxRegEx::GetMatch(const wxString& text, size_t index) const -{ - size_t start, len; - if ( !GetMatch(&start, &len, index) ) - return wxEmptyString; - - return text.Mid(start, len); -} - -size_t wxRegEx::GetMatchCount() const -{ - wxCHECK_MSG( IsValid(), 0, _T("must successfully Compile() first") ); - - return m_impl->GetMatchCount(); -} - -int wxRegEx::Replace(wxString *pattern, - const wxString& replacement, - size_t maxMatches) const -{ - wxCHECK_MSG( IsValid(), wxNOT_FOUND, _T("must successfully Compile() first") ); - - return m_impl->Replace(pattern, replacement, maxMatches); -} - -#endif // wxUSE_REGEX +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/regex.cpp +// Purpose: regular expression matching +// Author: Karsten Ballueder and Vadim Zeitlin +// Modified by: +// Created: 13.07.01 +// RCS-ID: $Id: regex.cpp 57779 2009-01-02 17:35:16Z PC $ +// Copyright: (c) 2000 Karsten Ballueder +// 2001 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_REGEX + +#include "wx/regex.h" + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/log.h" + #include "wx/intl.h" +#endif //WX_PRECOMP + +// FreeBSD, Watcom and DMars require this, CW doesn't have nor need it. +// Others also don't seem to need it. If you have an error related to +// (not) including please report details to +// wx-dev@lists.wxwindows.org +#if defined(__UNIX__) || defined(__WATCOMC__) || defined(__DIGITALMARS__) +# include +#endif + +#include + +// WXREGEX_USING_BUILTIN defined when using the built-in regex lib +// WXREGEX_USING_RE_SEARCH defined when using re_search in the GNU regex lib +// WXREGEX_IF_NEED_LEN() wrap the len parameter only used with the built-in +// or GNU regex +// WXREGEX_CONVERT_TO_MB defined when the regex lib is using chars and +// wxChar is wide, so conversion must be done +// WXREGEX_CHAR(x) Convert wxChar to wxRegChar +// +#ifdef __REG_NOFRONT +# define WXREGEX_USING_BUILTIN +# define WXREGEX_IF_NEED_LEN(x) ,x +# define WXREGEX_CHAR(x) x +#else +# ifdef HAVE_RE_SEARCH +# define WXREGEX_IF_NEED_LEN(x) ,x +# define WXREGEX_USING_RE_SEARCH +# else +# define WXREGEX_IF_NEED_LEN(x) +# endif +# if wxUSE_UNICODE +# define WXREGEX_CONVERT_TO_MB +# endif +# define WXREGEX_CHAR(x) wxConvertWX2MB(x) +# define wx_regfree regfree +# define wx_regerror regerror +#endif + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +#ifndef WXREGEX_USING_RE_SEARCH + +// the array of offsets for the matches, the usual POSIX regmatch_t array. +class wxRegExMatches +{ +public: + typedef regmatch_t *match_type; + + wxRegExMatches(size_t n) { m_matches = new regmatch_t[n]; } + ~wxRegExMatches() { delete [] m_matches; } + + // we just use casts here because the fields of regmatch_t struct may be 64 + // bit but we're limited to size_t in our public API and are not going to + // change it because operating on strings longer than 4GB using it is + // absolutely impractical anyhow + size_t Start(size_t n) const + { + return wx_truncate_cast(size_t, m_matches[n].rm_so); + } + + size_t End(size_t n) const + { + return wx_truncate_cast(size_t, m_matches[n].rm_eo); + } + + regmatch_t *get() const { return m_matches; } + +private: + regmatch_t *m_matches; +}; + +#else // WXREGEX_USING_RE_SEARCH + +// the array of offsets for the matches, the struct used by the GNU lib +class wxRegExMatches +{ +public: + typedef re_registers *match_type; + + wxRegExMatches(size_t n) + { + m_matches.num_regs = n; + m_matches.start = new regoff_t[n]; + m_matches.end = new regoff_t[n]; + } + + ~wxRegExMatches() + { + delete [] m_matches.start; + delete [] m_matches.end; + } + + size_t Start(size_t n) const { return m_matches.start[n]; } + size_t End(size_t n) const { return m_matches.end[n]; } + + re_registers *get() { return &m_matches; } + +private: + re_registers m_matches; +}; + +#endif // WXREGEX_USING_RE_SEARCH + +// the character type used by the regular expression engine +#ifndef WXREGEX_CONVERT_TO_MB +typedef wxChar wxRegChar; +#else +typedef char wxRegChar; +#endif + +// the real implementation of wxRegEx +class wxRegExImpl +{ +public: + // ctor and dtor + wxRegExImpl(); + ~wxRegExImpl(); + + // return true if Compile() had been called successfully + bool IsValid() const { return m_isCompiled; } + + // RE operations + bool Compile(const wxString& expr, int flags = 0); + bool Matches(const wxRegChar *str, int flags + WXREGEX_IF_NEED_LEN(size_t len)) const; + bool GetMatch(size_t *start, size_t *len, size_t index = 0) const; + size_t GetMatchCount() const; + int Replace(wxString *pattern, const wxString& replacement, + size_t maxMatches = 0) const; + +private: + // return the string containing the error message for the given err code + wxString GetErrorMsg(int errorcode, bool badconv) const; + + // init the members + void Init() + { + m_isCompiled = false; + m_Matches = NULL; + m_nMatches = 0; + } + + // free the RE if compiled + void Free() + { + if ( IsValid() ) + { + wx_regfree(&m_RegEx); + } + + delete m_Matches; + } + + // free the RE if any and reinit the members + void Reinit() + { + Free(); + Init(); + } + + // compiled RE + regex_t m_RegEx; + + // the subexpressions data + wxRegExMatches *m_Matches; + size_t m_nMatches; + + // true if m_RegEx is valid + bool m_isCompiled; +}; + + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxRegExImpl +// ---------------------------------------------------------------------------- + +wxRegExImpl::wxRegExImpl() +{ + Init(); +} + +wxRegExImpl::~wxRegExImpl() +{ + Free(); +} + +wxString wxRegExImpl::GetErrorMsg(int errorcode, bool badconv) const +{ +#ifdef WXREGEX_CONVERT_TO_MB + // currently only needed when using system library in Unicode mode + if ( badconv ) + { + return _("conversion to 8-bit encoding failed"); + } +#else + // 'use' badconv to avoid a compiler warning + (void)badconv; +#endif + + wxString szError; + + // first get the string length needed + int len = wx_regerror(errorcode, &m_RegEx, NULL, 0); + if ( len > 0 ) + { + char* szcmbError = new char[++len]; + + (void)wx_regerror(errorcode, &m_RegEx, szcmbError, len); + + szError = wxConvertMB2WX(szcmbError); + delete [] szcmbError; + } + else // regerror() returned 0 + { + szError = _("unknown error"); + } + + return szError; +} + +bool wxRegExImpl::Compile(const wxString& expr, int flags) +{ + Reinit(); + +#ifdef WX_NO_REGEX_ADVANCED +# define FLAVORS wxRE_BASIC +#else +# define FLAVORS (wxRE_ADVANCED | wxRE_BASIC) + wxASSERT_MSG( (flags & FLAVORS) != FLAVORS, + _T("incompatible flags in wxRegEx::Compile") ); +#endif + wxASSERT_MSG( !(flags & ~(FLAVORS | wxRE_ICASE | wxRE_NOSUB | wxRE_NEWLINE)), + _T("unrecognized flags in wxRegEx::Compile") ); + + // translate our flags to regcomp() ones + int flagsRE = 0; + if ( !(flags & wxRE_BASIC) ) + { +#ifndef WX_NO_REGEX_ADVANCED + if (flags & wxRE_ADVANCED) + flagsRE |= REG_ADVANCED; + else +#endif + flagsRE |= REG_EXTENDED; + } + + if ( flags & wxRE_ICASE ) + flagsRE |= REG_ICASE; + if ( flags & wxRE_NOSUB ) + flagsRE |= REG_NOSUB; + if ( flags & wxRE_NEWLINE ) + flagsRE |= REG_NEWLINE; + + // compile it +#ifdef WXREGEX_USING_BUILTIN + bool conv = true; + int errorcode = wx_re_comp(&m_RegEx, expr, expr.length(), flagsRE); +#else + const wxWX2MBbuf conv = expr.mbc_str(); + int errorcode = conv ? regcomp(&m_RegEx, conv, flagsRE) : REG_BADPAT; +#endif + + if ( errorcode ) + { + wxLogError(_("Invalid regular expression '%s': %s"), + expr.c_str(), GetErrorMsg(errorcode, !conv).c_str()); + + m_isCompiled = false; + } + else // ok + { + // don't allocate the matches array now, but do it later if necessary + if ( flags & wxRE_NOSUB ) + { + // we don't need it at all + m_nMatches = 0; + } + else + { + // we will alloc the array later (only if really needed) but count + // the number of sub-expressions in the regex right now + + // there is always one for the whole expression + m_nMatches = 1; + + // and some more for bracketed subexperessions + for ( const wxChar *cptr = expr.c_str(); *cptr; cptr++ ) + { + if ( *cptr == _T('\\') ) + { + // in basic RE syntax groups are inside \(...\) + if ( *++cptr == _T('(') && (flags & wxRE_BASIC) ) + { + m_nMatches++; + } + } + else if ( *cptr == _T('(') && !(flags & wxRE_BASIC) ) + { + // we know that the previous character is not an unquoted + // backslash because it would have been eaten above, so we + // have a bare '(' and this indicates a group start for the + // extended syntax. '(?' is used for extensions by perl- + // like REs (e.g. advanced), and is not valid for POSIX + // extended, so ignore them always. + if ( cptr[1] != _T('?') ) + m_nMatches++; + } + } + } + + m_isCompiled = true; + } + + return IsValid(); +} + +#ifdef WXREGEX_USING_RE_SEARCH + +// On GNU, regexec is implemented as a wrapper around re_search. re_search +// requires a length parameter which the POSIX regexec does not have, +// therefore regexec must do a strlen on the search text each time it is +// called. This can drastically affect performance when matching is done in +// a loop along a string, such as during a search and replace. Therefore if +// re_search is detected by configure, it is used directly. +// +static int ReSearch(const regex_t *preg, + const char *text, + size_t len, + re_registers *matches, + int eflags) +{ + regex_t *pattern = wx_const_cast(regex_t*, preg); + + pattern->not_bol = (eflags & REG_NOTBOL) != 0; + pattern->not_eol = (eflags & REG_NOTEOL) != 0; + pattern->regs_allocated = REGS_FIXED; + + int ret = re_search(pattern, text, len, 0, len, matches); + return ret >= 0 ? 0 : REG_NOMATCH; +} + +#endif // WXREGEX_USING_RE_SEARCH + +bool wxRegExImpl::Matches(const wxRegChar *str, + int flags + WXREGEX_IF_NEED_LEN(size_t len)) const +{ + wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); + + // translate our flags to regexec() ones + wxASSERT_MSG( !(flags & ~(wxRE_NOTBOL | wxRE_NOTEOL)), + _T("unrecognized flags in wxRegEx::Matches") ); + + int flagsRE = 0; + if ( flags & wxRE_NOTBOL ) + flagsRE |= REG_NOTBOL; + if ( flags & wxRE_NOTEOL ) + flagsRE |= REG_NOTEOL; + + // allocate matches array if needed + wxRegExImpl *self = wxConstCast(this, wxRegExImpl); + if ( !m_Matches && m_nMatches ) + { + self->m_Matches = new wxRegExMatches(m_nMatches); + } + + wxRegExMatches::match_type matches = m_Matches ? m_Matches->get() : NULL; + + // do match it +#if defined WXREGEX_USING_BUILTIN + int rc = wx_re_exec(&self->m_RegEx, str, len, NULL, m_nMatches, matches, flagsRE); +#elif defined WXREGEX_USING_RE_SEARCH + int rc = str ? ReSearch(&self->m_RegEx, str, len, matches, flagsRE) : REG_BADPAT; +#else + int rc = str ? regexec(&self->m_RegEx, str, m_nMatches, matches, flagsRE) : REG_BADPAT; +#endif + + switch ( rc ) + { + case 0: + // matched successfully + return true; + + default: + // an error occurred + wxLogError(_("Failed to find match for regular expression: %s"), + GetErrorMsg(rc, !str).c_str()); + // fall through + + case REG_NOMATCH: + // no match + return false; + } +} + +bool wxRegExImpl::GetMatch(size_t *start, size_t *len, size_t index) const +{ + wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); + wxCHECK_MSG( m_nMatches, false, _T("can't use with wxRE_NOSUB") ); + wxCHECK_MSG( m_Matches, false, _T("must call Matches() first") ); + wxCHECK_MSG( index < m_nMatches, false, _T("invalid match index") ); + + if ( start ) + *start = m_Matches->Start(index); + if ( len ) + *len = m_Matches->End(index) - m_Matches->Start(index); + + return true; +} + +size_t wxRegExImpl::GetMatchCount() const +{ + wxCHECK_MSG( IsValid(), 0, _T("must successfully Compile() first") ); + wxCHECK_MSG( m_nMatches, 0, _T("can't use with wxRE_NOSUB") ); + + return m_nMatches; +} + +int wxRegExImpl::Replace(wxString *text, + const wxString& replacement, + size_t maxMatches) const +{ + wxCHECK_MSG( text, wxNOT_FOUND, _T("NULL text in wxRegEx::Replace") ); + wxCHECK_MSG( IsValid(), wxNOT_FOUND, _T("must successfully Compile() first") ); + + // the input string +#ifndef WXREGEX_CONVERT_TO_MB + const wxChar *textstr = text->c_str(); + size_t textlen = text->length(); +#else + const wxWX2MBbuf textstr = WXREGEX_CHAR(*text); + if (!textstr) + { + wxLogError(_("Failed to find match for regular expression: %s"), + GetErrorMsg(0, true).c_str()); + return 0; + } + size_t textlen = strlen(textstr); + text->clear(); +#endif + + // the replacement text + wxString textNew; + + // the result, allow 25% extra + wxString result; + result.reserve(5 * textlen / 4); + + // attempt at optimization: don't iterate over the string if it doesn't + // contain back references at all + bool mayHaveBackrefs = + replacement.find_first_of(_T("\\&")) != wxString::npos; + + if ( !mayHaveBackrefs ) + { + textNew = replacement; + } + + // the position where we start looking for the match + size_t matchStart = 0; + + // number of replacement made: we won't make more than maxMatches of them + // (unless maxMatches is 0 which doesn't limit the number of replacements) + size_t countRepl = 0; + + // note that "^" shouldn't match after the first call to Matches() so we + // use wxRE_NOTBOL to prevent it from happening + while ( (!maxMatches || countRepl < maxMatches) && + Matches(textstr + matchStart, + countRepl ? wxRE_NOTBOL : 0 + WXREGEX_IF_NEED_LEN(textlen - matchStart)) ) + { + // the string possibly contains back references: we need to calculate + // the replacement text anew after each match + if ( mayHaveBackrefs ) + { + mayHaveBackrefs = false; + textNew.clear(); + textNew.reserve(replacement.length()); + + for ( const wxChar *p = replacement.c_str(); *p; p++ ) + { + size_t index = (size_t)-1; + + if ( *p == _T('\\') ) + { + if ( wxIsdigit(*++p) ) + { + // back reference + wxChar *end; + index = (size_t)wxStrtoul(p, &end, 10); + p = end - 1; // -1 to compensate for p++ in the loop + } + //else: backslash used as escape character + } + else if ( *p == _T('&') ) + { + // treat this as "\0" for compatbility with ed and such + index = 0; + } + + // do we have a back reference? + if ( index != (size_t)-1 ) + { + // yes, get its text + size_t start, len; + if ( !GetMatch(&start, &len, index) ) + { + wxFAIL_MSG( _T("invalid back reference") ); + + // just eat it... + } + else + { + textNew += wxString(textstr + matchStart + start, + *wxConvCurrent, len); + + mayHaveBackrefs = true; + } + } + else // ordinary character + { + textNew += *p; + } + } + } + + size_t start, len; + if ( !GetMatch(&start, &len) ) + { + // we did have match as Matches() returned true above! + wxFAIL_MSG( _T("internal logic error in wxRegEx::Replace") ); + + return wxNOT_FOUND; + } + + // an insurance against implementations that don't grow exponentially + // to ensure building the result takes linear time + if (result.capacity() < result.length() + start + textNew.length()) + result.reserve(2 * result.length()); + +#ifndef WXREGEX_CONVERT_TO_MB + result.append(*text, matchStart, start); +#else + result.append(wxString(textstr + matchStart, *wxConvCurrent, start)); +#endif + matchStart += start; + result.append(textNew); + + countRepl++; + + matchStart += len; + } + +#ifndef WXREGEX_CONVERT_TO_MB + result.append(*text, matchStart, wxString::npos); +#else + result.append(wxString(textstr + matchStart, *wxConvCurrent)); +#endif + *text = result; + + return countRepl; +} + +// ---------------------------------------------------------------------------- +// wxRegEx: all methods are mostly forwarded to wxRegExImpl +// ---------------------------------------------------------------------------- + +void wxRegEx::Init() +{ + m_impl = NULL; +} + +wxRegEx::~wxRegEx() +{ + delete m_impl; +} + +bool wxRegEx::Compile(const wxString& expr, int flags) +{ + if ( !m_impl ) + { + m_impl = new wxRegExImpl; + } + + if ( !m_impl->Compile(expr, flags) ) + { + // error message already given in wxRegExImpl::Compile + delete m_impl; + m_impl = NULL; + + return false; + } + + return true; +} + +bool wxRegEx::Matches(const wxChar *str, int flags, size_t len) const +{ + wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); + (void)len; + + return m_impl->Matches(WXREGEX_CHAR(str), flags WXREGEX_IF_NEED_LEN(len)); +} + +bool wxRegEx::Matches(const wxChar *str, int flags) const +{ + wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); + + return m_impl->Matches(WXREGEX_CHAR(str), + flags + WXREGEX_IF_NEED_LEN(wxStrlen(str))); +} + +bool wxRegEx::GetMatch(size_t *start, size_t *len, size_t index) const +{ + wxCHECK_MSG( IsValid(), false, _T("must successfully Compile() first") ); + + return m_impl->GetMatch(start, len, index); +} + +wxString wxRegEx::GetMatch(const wxString& text, size_t index) const +{ + size_t start, len; + if ( !GetMatch(&start, &len, index) ) + return wxEmptyString; + + return text.Mid(start, len); +} + +size_t wxRegEx::GetMatchCount() const +{ + wxCHECK_MSG( IsValid(), 0, _T("must successfully Compile() first") ); + + return m_impl->GetMatchCount(); +} + +int wxRegEx::Replace(wxString *pattern, + const wxString& replacement, + size_t maxMatches) const +{ + wxCHECK_MSG( IsValid(), wxNOT_FOUND, _T("must successfully Compile() first") ); + + return m_impl->Replace(pattern, replacement, maxMatches); +} + +#endif // wxUSE_REGEX diff --git a/Source/3rd Party/wx/src/common/rendcmn.cpp b/Source/3rd Party/wx/src/common/rendcmn.cpp index 9d77c390b..702ffb4fa 100644 --- a/Source/3rd Party/wx/src/common/rendcmn.cpp +++ b/Source/3rd Party/wx/src/common/rendcmn.cpp @@ -1,208 +1,208 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/rendcmn.cpp -// Purpose: wxRendererNative common functions -// Author: Vadim Zeitlin -// Modified by: -// Created: 28.07.03 -// RCS-ID: $Id: rendcmn.cpp 41216 2006-09-14 16:04:18Z ABX $ -// Copyright: (c) 2003 Vadim Zeitlin -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/log.h" - #include "wx/intl.h" -#endif //WX_PRECOMP - -#include "wx/apptrait.h" -#include "wx/renderer.h" - -#include "wx/ptr_scpd.h" - -#if wxUSE_DYNLIB_CLASS - #include "wx/dynlib.h" -#endif // wxUSE_DYNLIB_CLASS - -// ---------------------------------------------------------------------------- -// wxRendererPtr: auto pointer holding the global renderer -// ---------------------------------------------------------------------------- - -wxDECLARE_SCOPED_PTR(wxRendererNative, wxRendererPtrBase) -wxDEFINE_SCOPED_PTR(wxRendererNative, wxRendererPtrBase) - -class wxRendererPtr : public wxRendererPtrBase -{ -public: - // return true if we have a renderer, false otherwise - bool IsOk() - { - if ( !m_initialized ) - { - // only try to create the renderer once - m_initialized = true; - - DoInit(); - } - - return get() != NULL; - } - - // return the global and unique wxRendererPtr - static wxRendererPtr& Get(); - -private: - wxRendererPtr() : wxRendererPtrBase(NULL) { m_initialized = false; } - - void DoInit() - { - wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; - if ( traits ) - { - // ask the traits object to create a renderer for us - reset(traits->CreateRenderer()); - } - } - - bool m_initialized; - - // just to suppress a gcc warning - friend class wxRendererPtrDummyFriend; - - DECLARE_NO_COPY_CLASS(wxRendererPtr) -}; - -// return the global and unique wxRendererPtr -/*static*/ wxRendererPtr& wxRendererPtr::Get() -{ - static wxRendererPtr s_renderer; - - return s_renderer; -} - -#if wxUSE_DYNLIB_CLASS - -// ---------------------------------------------------------------------------- -// wxRendererFromDynLib: represents a renderer dynamically loaded from a DLL -// ---------------------------------------------------------------------------- - -class wxRendererFromDynLib : public wxDelegateRendererNative -{ -public: - // create the object wrapping the given renderer created from this DLL - // - // we take ownership of the pointer and will delete it (and also unload the - // DLL) when we're deleted - wxRendererFromDynLib(wxDynamicLibrary& dll, wxRendererNative *renderer) - : wxDelegateRendererNative(*renderer), - m_renderer(renderer), - m_dllHandle(dll.Detach()) - { - } - - virtual ~wxRendererFromDynLib() - { - delete m_renderer; - wxDynamicLibrary::Unload(m_dllHandle); - } - -private: - wxRendererNative *m_renderer; - wxDllType m_dllHandle; -}; - -#endif // wxUSE_DYNLIB_CLASS - -// ============================================================================ -// wxRendererNative implementation -// ============================================================================ - -wxRendererNative::~wxRendererNative() -{ - // empty but necessary -} - -// ---------------------------------------------------------------------------- -// Managing the global renderer -// ---------------------------------------------------------------------------- - -/* static */ -wxRendererNative& wxRendererNative::Get() -{ - wxRendererPtr& renderer = wxRendererPtr::Get(); - - return renderer.IsOk() ? *renderer.get() : GetDefault(); -} - -/* static */ -wxRendererNative *wxRendererNative::Set(wxRendererNative *rendererNew) -{ - wxRendererPtr& renderer = wxRendererPtr::Get(); - - wxRendererNative *rendererOld = renderer.release(); - - renderer.reset(rendererNew); - - return rendererOld; -} - - -// ---------------------------------------------------------------------------- -// Dynamic renderers loading -// ---------------------------------------------------------------------------- - -#if wxUSE_DYNLIB_CLASS - -/* static */ -wxRendererNative *wxRendererNative::Load(const wxString& name) -{ - wxString fullname = wxDynamicLibrary::CanonicalizePluginName(name); - - wxDynamicLibrary dll(fullname); - if ( !dll.IsLoaded() ) - return NULL; - - // each theme DLL must export a wxCreateRenderer() function with this - // signature - typedef wxRendererNative *(*wxCreateRenderer_t)(); - - wxDYNLIB_FUNCTION(wxCreateRenderer_t, wxCreateRenderer, dll); - if ( !pfnwxCreateRenderer ) - return NULL; - - // create a renderer object - wxRendererNative *renderer = (*pfnwxCreateRenderer)(); - if ( !renderer ) - return NULL; - - // check that its version is compatible with ours - wxRendererVersion ver = renderer->GetVersion(); - if ( !wxRendererVersion::IsCompatible(ver) ) - { - wxLogError(_("Renderer \"%s\" has incompatible version %d.%d and couldn't be loaded."), - name.c_str(), ver.version, ver.age); - delete renderer; - - return NULL; - } - - // finally wrap the renderer in an object which will delete it and unload - // the library when it is deleted and return it to the caller - return new wxRendererFromDynLib(dll, renderer); -} - -#endif // wxUSE_DYNLIB_CLASS +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/rendcmn.cpp +// Purpose: wxRendererNative common functions +// Author: Vadim Zeitlin +// Modified by: +// Created: 28.07.03 +// RCS-ID: $Id: rendcmn.cpp 41216 2006-09-14 16:04:18Z ABX $ +// Copyright: (c) 2003 Vadim Zeitlin +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/log.h" + #include "wx/intl.h" +#endif //WX_PRECOMP + +#include "wx/apptrait.h" +#include "wx/renderer.h" + +#include "wx/ptr_scpd.h" + +#if wxUSE_DYNLIB_CLASS + #include "wx/dynlib.h" +#endif // wxUSE_DYNLIB_CLASS + +// ---------------------------------------------------------------------------- +// wxRendererPtr: auto pointer holding the global renderer +// ---------------------------------------------------------------------------- + +wxDECLARE_SCOPED_PTR(wxRendererNative, wxRendererPtrBase) +wxDEFINE_SCOPED_PTR(wxRendererNative, wxRendererPtrBase) + +class wxRendererPtr : public wxRendererPtrBase +{ +public: + // return true if we have a renderer, false otherwise + bool IsOk() + { + if ( !m_initialized ) + { + // only try to create the renderer once + m_initialized = true; + + DoInit(); + } + + return get() != NULL; + } + + // return the global and unique wxRendererPtr + static wxRendererPtr& Get(); + +private: + wxRendererPtr() : wxRendererPtrBase(NULL) { m_initialized = false; } + + void DoInit() + { + wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; + if ( traits ) + { + // ask the traits object to create a renderer for us + reset(traits->CreateRenderer()); + } + } + + bool m_initialized; + + // just to suppress a gcc warning + friend class wxRendererPtrDummyFriend; + + DECLARE_NO_COPY_CLASS(wxRendererPtr) +}; + +// return the global and unique wxRendererPtr +/*static*/ wxRendererPtr& wxRendererPtr::Get() +{ + static wxRendererPtr s_renderer; + + return s_renderer; +} + +#if wxUSE_DYNLIB_CLASS + +// ---------------------------------------------------------------------------- +// wxRendererFromDynLib: represents a renderer dynamically loaded from a DLL +// ---------------------------------------------------------------------------- + +class wxRendererFromDynLib : public wxDelegateRendererNative +{ +public: + // create the object wrapping the given renderer created from this DLL + // + // we take ownership of the pointer and will delete it (and also unload the + // DLL) when we're deleted + wxRendererFromDynLib(wxDynamicLibrary& dll, wxRendererNative *renderer) + : wxDelegateRendererNative(*renderer), + m_renderer(renderer), + m_dllHandle(dll.Detach()) + { + } + + virtual ~wxRendererFromDynLib() + { + delete m_renderer; + wxDynamicLibrary::Unload(m_dllHandle); + } + +private: + wxRendererNative *m_renderer; + wxDllType m_dllHandle; +}; + +#endif // wxUSE_DYNLIB_CLASS + +// ============================================================================ +// wxRendererNative implementation +// ============================================================================ + +wxRendererNative::~wxRendererNative() +{ + // empty but necessary +} + +// ---------------------------------------------------------------------------- +// Managing the global renderer +// ---------------------------------------------------------------------------- + +/* static */ +wxRendererNative& wxRendererNative::Get() +{ + wxRendererPtr& renderer = wxRendererPtr::Get(); + + return renderer.IsOk() ? *renderer.get() : GetDefault(); +} + +/* static */ +wxRendererNative *wxRendererNative::Set(wxRendererNative *rendererNew) +{ + wxRendererPtr& renderer = wxRendererPtr::Get(); + + wxRendererNative *rendererOld = renderer.release(); + + renderer.reset(rendererNew); + + return rendererOld; +} + + +// ---------------------------------------------------------------------------- +// Dynamic renderers loading +// ---------------------------------------------------------------------------- + +#if wxUSE_DYNLIB_CLASS + +/* static */ +wxRendererNative *wxRendererNative::Load(const wxString& name) +{ + wxString fullname = wxDynamicLibrary::CanonicalizePluginName(name); + + wxDynamicLibrary dll(fullname); + if ( !dll.IsLoaded() ) + return NULL; + + // each theme DLL must export a wxCreateRenderer() function with this + // signature + typedef wxRendererNative *(*wxCreateRenderer_t)(); + + wxDYNLIB_FUNCTION(wxCreateRenderer_t, wxCreateRenderer, dll); + if ( !pfnwxCreateRenderer ) + return NULL; + + // create a renderer object + wxRendererNative *renderer = (*pfnwxCreateRenderer)(); + if ( !renderer ) + return NULL; + + // check that its version is compatible with ours + wxRendererVersion ver = renderer->GetVersion(); + if ( !wxRendererVersion::IsCompatible(ver) ) + { + wxLogError(_("Renderer \"%s\" has incompatible version %d.%d and couldn't be loaded."), + name.c_str(), ver.version, ver.age); + delete renderer; + + return NULL; + } + + // finally wrap the renderer in an object which will delete it and unload + // the library when it is deleted and return it to the caller + return new wxRendererFromDynLib(dll, renderer); +} + +#endif // wxUSE_DYNLIB_CLASS diff --git a/Source/3rd Party/wx/src/common/rgncmn.cpp b/Source/3rd Party/wx/src/common/rgncmn.cpp index ca5ff249d..0f9c8b216 100644 --- a/Source/3rd Party/wx/src/common/rgncmn.cpp +++ b/Source/3rd Party/wx/src/common/rgncmn.cpp @@ -1,192 +1,192 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/rgncmn.cpp -// Purpose: Methods of wxRegion that have a generic implementation -// Author: Robin Dunn -// Modified by: -// Created: 27-Mar-2003 -// RCS-ID: $Id: rgncmn.cpp 41901 2006-10-10 17:33:49Z PC $ -// Copyright: (c) Robin Dunn -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/region.h" - -#ifndef WX_PRECOMP - #include "wx/dcmemory.h" - #include "wx/bitmap.h" - #include "wx/image.h" -#endif //WX_PRECOMP - -// ============================================================================ -// wxRegionBase implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// region comparision -// ---------------------------------------------------------------------------- - -bool wxRegionBase::IsEqual(const wxRegion& region) const -{ - if ( m_refData == region.GetRefData() ) - { - // regions are identical, hence equal - return true; - } - - if ( !m_refData || !region.GetRefData() ) - { - // one, but not both, of the regions is invalid - return false; - } - - return DoIsEqual(region); -} - -// ---------------------------------------------------------------------------- -// region to/from bitmap conversions -// ---------------------------------------------------------------------------- - -wxBitmap wxRegionBase::ConvertToBitmap() const -{ - wxRect box = GetBox(); - wxBitmap bmp(box.GetRight(), box.GetBottom()); - wxMemoryDC dc; - dc.SelectObject(bmp); - dc.SetBackground(*wxBLACK_BRUSH); - dc.Clear(); - dc.SetClippingRegion(*wx_static_cast(const wxRegion *, this)); - dc.SetBackground(*wxWHITE_BRUSH); - dc.Clear(); - dc.SelectObject(wxNullBitmap); - return bmp; -} - -#if wxUSE_IMAGE - -static bool DoRegionUnion(wxRegionBase& region, - const wxImage& image, - unsigned char loR, - unsigned char loG, - unsigned char loB, - int tolerance) -{ - unsigned char hiR, hiG, hiB; - - hiR = (unsigned char)wxMin(0xFF, loR + tolerance); - hiG = (unsigned char)wxMin(0xFF, loG + tolerance); - hiB = (unsigned char)wxMin(0xFF, loB + tolerance); - - // Loop through the image row by row, pixel by pixel, building up - // rectangles to add to the region. - int width = image.GetWidth(); - int height = image.GetHeight(); - for (int y=0; y < height; y++) - { - wxRect rect; - rect.y = y; - rect.height = 1; - - for (int x=0; x < width; x++) - { - // search for a continuous range of non-transparent pixels - int x0 = x; - while ( x < width) - { - unsigned char R = image.GetRed(x,y); - unsigned char G = image.GetGreen(x,y); - unsigned char B = image.GetBlue(x,y); - if (( R >= loR && R <= hiR) && - ( G >= loG && G <= hiG) && - ( B >= loB && B <= hiB)) // It's transparent - break; - x++; - } - - // Add the run of non-transparent pixels (if any) to the region - if (x > x0) { - rect.x = x0; - rect.width = x - x0; - region.Union(rect); - } - } - } - - return true; -} - - -bool wxRegionBase::Union(const wxBitmap& bmp) -{ - if (bmp.GetMask()) - { - wxImage image = bmp.ConvertToImage(); - wxASSERT_MSG( image.HasMask(), _T("wxBitmap::ConvertToImage doesn't preserve mask?") ); - return DoRegionUnion(*this, image, - image.GetMaskRed(), - image.GetMaskGreen(), - image.GetMaskBlue(), - 0); - } - else - { - return Union(0, 0, bmp.GetWidth(), bmp.GetHeight()); - } -} - -bool wxRegionBase::Union(const wxBitmap& bmp, - const wxColour& transColour, - int tolerance) -{ - wxImage image = bmp.ConvertToImage(); - return DoRegionUnion(*this, image, - transColour.Red(), - transColour.Green(), - transColour.Blue(), - tolerance); -} - -#endif // wxUSE_IMAGE - -#ifdef wxHAS_REGION_COMBINE -// ============================================================================ -// wxRegionWithCombine -// ============================================================================ - -// implement some wxRegionBase pure virtuals in terms of Combine() -bool wxRegionWithCombine::DoUnionWithRect(const wxRect& rect) -{ - return Combine(rect, wxRGN_OR); -} - -bool wxRegionWithCombine::DoUnionWithRegion(const wxRegion& region) -{ - return DoCombine(region, wxRGN_OR); -} - -bool wxRegionWithCombine::DoIntersect(const wxRegion& region) -{ - return DoCombine(region, wxRGN_AND); -} - -bool wxRegionWithCombine::DoSubtract(const wxRegion& region) -{ - return DoCombine(region, wxRGN_DIFF); -} - -bool wxRegionWithCombine::DoXor(const wxRegion& region) -{ - return DoCombine(region, wxRGN_XOR); -} - -#endif // wxHAS_REGION_COMBINE +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/rgncmn.cpp +// Purpose: Methods of wxRegion that have a generic implementation +// Author: Robin Dunn +// Modified by: +// Created: 27-Mar-2003 +// RCS-ID: $Id: rgncmn.cpp 41901 2006-10-10 17:33:49Z PC $ +// Copyright: (c) Robin Dunn +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/region.h" + +#ifndef WX_PRECOMP + #include "wx/dcmemory.h" + #include "wx/bitmap.h" + #include "wx/image.h" +#endif //WX_PRECOMP + +// ============================================================================ +// wxRegionBase implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// region comparision +// ---------------------------------------------------------------------------- + +bool wxRegionBase::IsEqual(const wxRegion& region) const +{ + if ( m_refData == region.GetRefData() ) + { + // regions are identical, hence equal + return true; + } + + if ( !m_refData || !region.GetRefData() ) + { + // one, but not both, of the regions is invalid + return false; + } + + return DoIsEqual(region); +} + +// ---------------------------------------------------------------------------- +// region to/from bitmap conversions +// ---------------------------------------------------------------------------- + +wxBitmap wxRegionBase::ConvertToBitmap() const +{ + wxRect box = GetBox(); + wxBitmap bmp(box.GetRight(), box.GetBottom()); + wxMemoryDC dc; + dc.SelectObject(bmp); + dc.SetBackground(*wxBLACK_BRUSH); + dc.Clear(); + dc.SetClippingRegion(*wx_static_cast(const wxRegion *, this)); + dc.SetBackground(*wxWHITE_BRUSH); + dc.Clear(); + dc.SelectObject(wxNullBitmap); + return bmp; +} + +#if wxUSE_IMAGE + +static bool DoRegionUnion(wxRegionBase& region, + const wxImage& image, + unsigned char loR, + unsigned char loG, + unsigned char loB, + int tolerance) +{ + unsigned char hiR, hiG, hiB; + + hiR = (unsigned char)wxMin(0xFF, loR + tolerance); + hiG = (unsigned char)wxMin(0xFF, loG + tolerance); + hiB = (unsigned char)wxMin(0xFF, loB + tolerance); + + // Loop through the image row by row, pixel by pixel, building up + // rectangles to add to the region. + int width = image.GetWidth(); + int height = image.GetHeight(); + for (int y=0; y < height; y++) + { + wxRect rect; + rect.y = y; + rect.height = 1; + + for (int x=0; x < width; x++) + { + // search for a continuous range of non-transparent pixels + int x0 = x; + while ( x < width) + { + unsigned char R = image.GetRed(x,y); + unsigned char G = image.GetGreen(x,y); + unsigned char B = image.GetBlue(x,y); + if (( R >= loR && R <= hiR) && + ( G >= loG && G <= hiG) && + ( B >= loB && B <= hiB)) // It's transparent + break; + x++; + } + + // Add the run of non-transparent pixels (if any) to the region + if (x > x0) { + rect.x = x0; + rect.width = x - x0; + region.Union(rect); + } + } + } + + return true; +} + + +bool wxRegionBase::Union(const wxBitmap& bmp) +{ + if (bmp.GetMask()) + { + wxImage image = bmp.ConvertToImage(); + wxASSERT_MSG( image.HasMask(), _T("wxBitmap::ConvertToImage doesn't preserve mask?") ); + return DoRegionUnion(*this, image, + image.GetMaskRed(), + image.GetMaskGreen(), + image.GetMaskBlue(), + 0); + } + else + { + return Union(0, 0, bmp.GetWidth(), bmp.GetHeight()); + } +} + +bool wxRegionBase::Union(const wxBitmap& bmp, + const wxColour& transColour, + int tolerance) +{ + wxImage image = bmp.ConvertToImage(); + return DoRegionUnion(*this, image, + transColour.Red(), + transColour.Green(), + transColour.Blue(), + tolerance); +} + +#endif // wxUSE_IMAGE + +#ifdef wxHAS_REGION_COMBINE +// ============================================================================ +// wxRegionWithCombine +// ============================================================================ + +// implement some wxRegionBase pure virtuals in terms of Combine() +bool wxRegionWithCombine::DoUnionWithRect(const wxRect& rect) +{ + return Combine(rect, wxRGN_OR); +} + +bool wxRegionWithCombine::DoUnionWithRegion(const wxRegion& region) +{ + return DoCombine(region, wxRGN_OR); +} + +bool wxRegionWithCombine::DoIntersect(const wxRegion& region) +{ + return DoCombine(region, wxRGN_AND); +} + +bool wxRegionWithCombine::DoSubtract(const wxRegion& region) +{ + return DoCombine(region, wxRGN_DIFF); +} + +bool wxRegionWithCombine::DoXor(const wxRegion& region) +{ + return DoCombine(region, wxRGN_XOR); +} + +#endif // wxHAS_REGION_COMBINE diff --git a/Source/3rd Party/wx/src/common/settcmn.cpp b/Source/3rd Party/wx/src/common/settcmn.cpp index 2aa32ea0d..334a8f8b8 100644 --- a/Source/3rd Party/wx/src/common/settcmn.cpp +++ b/Source/3rd Party/wx/src/common/settcmn.cpp @@ -1,88 +1,88 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/settcmn.cpp -// Purpose: common (to all ports) wxWindow functions -// Author: Robert Roebling -// RCS-ID: $Id: settcmn.cpp 39310 2006-05-24 07:16:32Z ABX $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/settings.h" - -#ifndef WX_PRECOMP - #include "wx/utils.h" -#endif //WX_PRECOMP - -// ---------------------------------------------------------------------------- -// static data -// ---------------------------------------------------------------------------- - -wxSystemScreenType wxSystemSettings::ms_screen = wxSYS_SCREEN_NONE; - -// ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- - -wxSystemScreenType wxSystemSettings::GetScreenType() -{ - if (ms_screen == wxSYS_SCREEN_NONE) - { - // wxUniv will be used on small devices, too. - int x = GetMetric( wxSYS_SCREEN_X ); - - ms_screen = wxSYS_SCREEN_DESKTOP; - - if (x < 800) - ms_screen = wxSYS_SCREEN_SMALL; - - if (x < 640) - ms_screen = wxSYS_SCREEN_PDA; - - if (x < 200) - ms_screen = wxSYS_SCREEN_TINY; - - // This is probably a bug, but VNC seems to report 0 - if (x < 10) - ms_screen = wxSYS_SCREEN_DESKTOP; - } - - return ms_screen; -} - -void wxSystemSettings::SetScreenType( wxSystemScreenType screen ) -{ - ms_screen = screen; -} - -#if WXWIN_COMPATIBILITY_2_4 - -wxColour wxSystemSettings::GetSystemColour(int index) -{ - return GetColour((wxSystemColour)index); -} - -wxFont wxSystemSettings::GetSystemFont(int index) -{ - return GetFont((wxSystemFont)index); -} - -int wxSystemSettings::GetSystemMetric(int index) -{ - return GetMetric((wxSystemMetric)index); -} - -#endif // WXWIN_COMPATIBILITY_2_4 +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/settcmn.cpp +// Purpose: common (to all ports) wxWindow functions +// Author: Robert Roebling +// RCS-ID: $Id: settcmn.cpp 39310 2006-05-24 07:16:32Z ABX $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/settings.h" + +#ifndef WX_PRECOMP + #include "wx/utils.h" +#endif //WX_PRECOMP + +// ---------------------------------------------------------------------------- +// static data +// ---------------------------------------------------------------------------- + +wxSystemScreenType wxSystemSettings::ms_screen = wxSYS_SCREEN_NONE; + +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- + +wxSystemScreenType wxSystemSettings::GetScreenType() +{ + if (ms_screen == wxSYS_SCREEN_NONE) + { + // wxUniv will be used on small devices, too. + int x = GetMetric( wxSYS_SCREEN_X ); + + ms_screen = wxSYS_SCREEN_DESKTOP; + + if (x < 800) + ms_screen = wxSYS_SCREEN_SMALL; + + if (x < 640) + ms_screen = wxSYS_SCREEN_PDA; + + if (x < 200) + ms_screen = wxSYS_SCREEN_TINY; + + // This is probably a bug, but VNC seems to report 0 + if (x < 10) + ms_screen = wxSYS_SCREEN_DESKTOP; + } + + return ms_screen; +} + +void wxSystemSettings::SetScreenType( wxSystemScreenType screen ) +{ + ms_screen = screen; +} + +#if WXWIN_COMPATIBILITY_2_4 + +wxColour wxSystemSettings::GetSystemColour(int index) +{ + return GetColour((wxSystemColour)index); +} + +wxFont wxSystemSettings::GetSystemFont(int index) +{ + return GetFont((wxSystemFont)index); +} + +int wxSystemSettings::GetSystemMetric(int index) +{ + return GetMetric((wxSystemMetric)index); +} + +#endif // WXWIN_COMPATIBILITY_2_4 diff --git a/Source/3rd Party/wx/src/common/sizer.cpp b/Source/3rd Party/wx/src/common/sizer.cpp index 931030d76..34a649aaa 100644 --- a/Source/3rd Party/wx/src/common/sizer.cpp +++ b/Source/3rd Party/wx/src/common/sizer.cpp @@ -1,2265 +1,2265 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/sizer.cpp -// Purpose: provide new wxSizer class for layout -// Author: Robert Roebling and Robin Dunn, contributions by -// Dirk Holtwick, Ron Lee -// Modified by: Ron Lee -// Created: -// RCS-ID: $Id: sizer.cpp 66936 2011-02-17 09:52:57Z JS $ -// Copyright: (c) Robin Dunn, Robert Roebling -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/display.h" -#include "wx/sizer.h" - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/math.h" - #include "wx/utils.h" - #include "wx/settings.h" - #include "wx/button.h" - #include "wx/statbox.h" - #include "wx/toplevel.h" -#endif // WX_PRECOMP - -#include "wx/listimpl.cpp" - -#if WXWIN_COMPATIBILITY_2_4 - #include "wx/notebook.h" -#endif - -//--------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxSizerItem, wxObject) -IMPLEMENT_CLASS(wxSizer, wxObject) -IMPLEMENT_CLASS(wxGridSizer, wxSizer) -IMPLEMENT_CLASS(wxFlexGridSizer, wxGridSizer) -IMPLEMENT_CLASS(wxBoxSizer, wxSizer) -#if wxUSE_STATBOX -IMPLEMENT_CLASS(wxStaticBoxSizer, wxBoxSizer) -#endif -#if wxUSE_BUTTON -IMPLEMENT_CLASS(wxStdDialogButtonSizer, wxBoxSizer) -#endif - -WX_DEFINE_EXPORTED_LIST( wxSizerItemList ) - -/* - TODO PROPERTIES - sizeritem - object - object_ref - minsize - option - flag - border - spacer - option - flag - borfder - boxsizer - orient - staticboxsizer - orient - label - gridsizer - rows - cols - vgap - hgap - flexgridsizer - rows - cols - vgap - hgap - growablerows - growablecols - minsize -*/ - - -// ---------------------------------------------------------------------------- -// wxSizerFlags -// ---------------------------------------------------------------------------- - -wxSizerFlags& wxSizerFlags::ReserveSpaceEvenIfHidden() -{ - m_flags |= wxRESERVE_SPACE_EVEN_IF_HIDDEN; - return *this; -} - -// ---------------------------------------------------------------------------- -// wxSizerItem -// ---------------------------------------------------------------------------- - -void wxSizerItem::Init(const wxSizerFlags& flags) -{ - Init(); - - m_proportion = flags.GetProportion(); - m_flag = flags.GetFlags(); - m_border = flags.GetBorderInPixels(); -} - -wxSizerItem::wxSizerItem() -{ - Init(); - - m_proportion = 0; - m_border = 0; - m_flag = 0; - - m_kind = Item_None; -} - -// window item -void wxSizerItem::SetWindow(wxWindow *window) -{ - wxCHECK_RET( window, _T("NULL window in wxSizerItem::SetWindow()") ); - - m_kind = Item_Window; - m_window = window; - - // window doesn't become smaller than its initial size, whatever happens - m_minSize = window->GetSize(); - - if ( m_flag & wxFIXED_MINSIZE ) - window->SetMinSize(m_minSize); - - // aspect ratio calculated from initial size - SetRatio(m_minSize); -} - -wxSizerItem::wxSizerItem(wxWindow *window, - int proportion, - int flag, - int border, - wxObject* userData) - : m_proportion(proportion), - m_border(border), - m_flag(flag), - m_userData(userData) -{ - SetWindow(window); -} - -// sizer item -void wxSizerItem::SetSizer(wxSizer *sizer) -{ - m_kind = Item_Sizer; - m_sizer = sizer; -} - -wxSizerItem::wxSizerItem(wxSizer *sizer, - int proportion, - int flag, - int border, - wxObject* userData) - : m_proportion(proportion), - m_border(border), - m_flag(flag), - m_ratio(0.0), - m_userData(userData) -{ - SetSizer(sizer); - - // m_minSize is set later -} - -// spacer item -void wxSizerItem::SetSpacer(const wxSize& size) -{ - m_kind = Item_Spacer; - m_spacer = new wxSizerSpacer(size); - m_minSize = size; - SetRatio(size); -} - -wxSizerItem::wxSizerItem(int width, - int height, - int proportion, - int flag, - int border, - wxObject* userData) - : m_minSize(width, height), // minimal size is the initial size - m_proportion(proportion), - m_border(border), - m_flag(flag), - m_userData(userData) -{ - SetSpacer(width, height); -} - -wxSizerItem::~wxSizerItem() -{ - delete m_userData; - - switch ( m_kind ) - { - case Item_None: - break; - - case Item_Window: - m_window->SetContainingSizer(NULL); - break; - - case Item_Sizer: - delete m_sizer; - break; - - case Item_Spacer: - delete m_spacer; - break; - - case Item_Max: - default: - wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); - } -} - -wxSize wxSizerItem::GetSpacer() const -{ - wxSize size; - if ( m_kind == Item_Spacer ) - size = m_spacer->GetSize(); - - return size; -} - - -wxSize wxSizerItem::GetSize() const -{ - wxSize ret; - switch ( m_kind ) - { - case Item_None: - break; - - case Item_Window: - ret = m_window->GetSize(); - break; - - case Item_Sizer: - ret = m_sizer->GetSize(); - break; - - case Item_Spacer: - ret = m_spacer->GetSize(); - break; - - case Item_Max: - default: - wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); - } - - if (m_flag & wxWEST) - ret.x += m_border; - if (m_flag & wxEAST) - ret.x += m_border; - if (m_flag & wxNORTH) - ret.y += m_border; - if (m_flag & wxSOUTH) - ret.y += m_border; - - return ret; -} - -wxSize wxSizerItem::CalcMin() -{ - if (IsSizer()) - { - m_minSize = m_sizer->GetMinSize(); - - // if we have to preserve aspect ratio _AND_ this is - // the first-time calculation, consider ret to be initial size - if ( (m_flag & wxSHAPED) && wxIsNullDouble(m_ratio) ) - SetRatio(m_minSize); - } - else if ( IsWindow() ) - { - // Since the size of the window may change during runtime, we - // should use the current minimal/best size. - m_minSize = m_window->GetEffectiveMinSize(); - } - - return GetMinSizeWithBorder(); -} - -wxSize wxSizerItem::GetMinSizeWithBorder() const -{ - wxSize ret = m_minSize; - - if (m_flag & wxWEST) - ret.x += m_border; - if (m_flag & wxEAST) - ret.x += m_border; - if (m_flag & wxNORTH) - ret.y += m_border; - if (m_flag & wxSOUTH) - ret.y += m_border; - - return ret; -} - - -void wxSizerItem::SetDimension( const wxPoint& pos_, const wxSize& size_ ) -{ - wxPoint pos = pos_; - wxSize size = size_; - if (m_flag & wxSHAPED) - { - // adjust aspect ratio - int rwidth = (int) (size.y * m_ratio); - if (rwidth > size.x) - { - // fit horizontally - int rheight = (int) (size.x / m_ratio); - // add vertical space - if (m_flag & wxALIGN_CENTER_VERTICAL) - pos.y += (size.y - rheight) / 2; - else if (m_flag & wxALIGN_BOTTOM) - pos.y += (size.y - rheight); - // use reduced dimensions - size.y =rheight; - } - else if (rwidth < size.x) - { - // add horizontal space - if (m_flag & wxALIGN_CENTER_HORIZONTAL) - pos.x += (size.x - rwidth) / 2; - else if (m_flag & wxALIGN_RIGHT) - pos.x += (size.x - rwidth); - size.x = rwidth; - } - } - - // This is what GetPosition() returns. Since we calculate - // borders afterwards, GetPosition() will be the left/top - // corner of the surrounding border. - m_pos = pos; - - if (m_flag & wxWEST) - { - pos.x += m_border; - size.x -= m_border; - } - if (m_flag & wxEAST) - { - size.x -= m_border; - } - if (m_flag & wxNORTH) - { - pos.y += m_border; - size.y -= m_border; - } - if (m_flag & wxSOUTH) - { - size.y -= m_border; - } - - if (size.x < 0) - size.x = 0; - if (size.y < 0) - size.y = 0; - - m_rect = wxRect(pos, size); - - switch ( m_kind ) - { - case Item_None: - wxFAIL_MSG( _T("can't set size of uninitialized sizer item") ); - break; - - case Item_Window: - m_window->SetSize(pos.x, pos.y, size.x, size.y, - wxSIZE_ALLOW_MINUS_ONE); - break; - - case Item_Sizer: - m_sizer->SetDimension(pos.x, pos.y, size.x, size.y); - break; - - case Item_Spacer: - m_spacer->SetSize(size); - break; - - case Item_Max: - default: - wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); - } -} - -void wxSizerItem::DeleteWindows() -{ - switch ( m_kind ) - { - case Item_None: - case Item_Spacer: - break; - - case Item_Window: - //We are deleting the window from this sizer - normally - //the window destroys the sizer associated with it, - //which might destroy this, which we don't want - m_window->SetContainingSizer(NULL); - m_window->Destroy(); - //Putting this after the switch will result in a spacer - //not being deleted properly on destruction - m_kind = Item_None; - break; - - case Item_Sizer: - m_sizer->DeleteWindows(); - break; - - case Item_Max: - default: - wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); - } - -} - -void wxSizerItem::Show( bool show ) -{ - switch ( m_kind ) - { - case Item_None: - wxFAIL_MSG( _T("can't show uninitialized sizer item") ); - break; - - case Item_Window: - m_window->Show(show); - break; - - case Item_Sizer: - m_sizer->Show(show); - break; - - case Item_Spacer: - m_spacer->Show(show); - break; - - case Item_Max: - default: - wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); - } -} - -bool wxSizerItem::IsShown() const -{ - switch ( m_kind ) - { - case Item_None: - // we may be called from CalcMin(), just return false so that we're - // not used - break; - - case Item_Window: - return m_window->IsShown(); - - case Item_Sizer: - // arbitrarily decide that if at least one of our elements is - // shown, so are we (this arbitrariness is the reason for - // deprecating this function) - { - // Some apps (such as dialog editors) depend on an empty sizer still - // being laid out correctly and reporting the correct size and position. - if (m_sizer->GetChildren().GetCount() == 0) - return true; - - for ( wxSizerItemList::compatibility_iterator - node = m_sizer->GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - if ( node->GetData()->IsShown() ) - return true; - } - } - return false; - - case Item_Spacer: - return m_spacer->IsShown(); - - case Item_Max: - default: - wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); - } - - return false; -} - -// This is a helper to support wxRESERVE_SPACE_EVEN_IF_HIDDEN. In wx 2.9+, -// this flag is respected by IsShown(), but not in wx 2.8. -bool wxSizerItem::ShouldAccountFor() const -{ - if ( m_flag & wxRESERVE_SPACE_EVEN_IF_HIDDEN ) - return true; - - if ( IsSizer() ) - { - // this mirrors wxSizerItem::IsShown() code above - const wxSizerItemList& children = m_sizer->GetChildren(); - if ( children.GetCount() == 0 ) - return true; - - for ( wxSizerItemList::compatibility_iterator - node = children.GetFirst(); - node; - node = node->GetNext() ) - { - if ( node->GetData()->ShouldAccountFor() ) - return true; - } - return false; - } - else - { - return IsShown(); - } -} - - -#if WXWIN_COMPATIBILITY_2_6 -void wxSizerItem::SetOption( int option ) -{ - SetProportion( option ); -} - -int wxSizerItem::GetOption() const -{ - return GetProportion(); -} -#endif // WXWIN_COMPATIBILITY_2_6 - - -//--------------------------------------------------------------------------- -// wxSizer -//--------------------------------------------------------------------------- - -wxSizer::~wxSizer() -{ - WX_CLEAR_LIST(wxSizerItemList, m_children); -} - -wxSizerItem* wxSizer::Insert( size_t index, wxSizerItem *item ) -{ - m_children.Insert( index, item ); - - if ( item->GetWindow() ) - item->GetWindow()->SetContainingSizer( this ); - - if ( item->GetSizer() ) - item->GetSizer()->SetContainingWindow( m_containingWindow ); - - return item; -} - -void wxSizer::SetContainingWindow(wxWindow *win) -{ - if ( win == m_containingWindow ) - return; - - m_containingWindow = win; - - // set the same window for all nested sizers as well, they also are in the - // same window - for ( wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - node; - node = node->GetNext() ) - { - wxSizerItem *const item = node->GetData(); - wxSizer *const sizer = item->GetSizer(); - - if ( sizer ) - { - sizer->SetContainingWindow(win); - } - } -} - -#if WXWIN_COMPATIBILITY_2_6 -bool wxSizer::Remove( wxWindow *window ) -{ - return Detach( window ); -} -#endif // WXWIN_COMPATIBILITY_2_6 - -bool wxSizer::Remove( wxSizer *sizer ) -{ - wxASSERT_MSG( sizer, _T("Removing NULL sizer") ); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetSizer() == sizer) - { - delete item; - m_children.Erase( node ); - return true; - } - - node = node->GetNext(); - } - - return false; -} - -bool wxSizer::Remove( int index ) -{ - wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(), - false, - _T("Remove index is out of range") ); - - wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - - wxCHECK_MSG( node, false, _T("Failed to find child node") ); - - wxSizerItem *item = node->GetData(); - - if ( item->IsWindow() ) - item->GetWindow()->SetContainingSizer( NULL ); - - delete item; - m_children.Erase( node ); - return true; -} - -bool wxSizer::Detach( wxSizer *sizer ) -{ - wxASSERT_MSG( sizer, _T("Detaching NULL sizer") ); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetSizer() == sizer) - { - item->DetachSizer(); - delete item; - m_children.Erase( node ); - return true; - } - node = node->GetNext(); - } - - return false; -} - -bool wxSizer::Detach( wxWindow *window ) -{ - wxASSERT_MSG( window, _T("Detaching NULL window") ); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetWindow() == window) - { - item->GetWindow()->SetContainingSizer( NULL ); - delete item; - m_children.Erase( node ); - return true; - } - node = node->GetNext(); - } - - return false; -} - -bool wxSizer::Detach( int index ) -{ - wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(), - false, - _T("Detach index is out of range") ); - - wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - - wxCHECK_MSG( node, false, _T("Failed to find child node") ); - - wxSizerItem *item = node->GetData(); - - if ( item->IsSizer() ) - item->DetachSizer(); - else if ( item->IsWindow() ) - item->GetWindow()->SetContainingSizer( NULL ); - - delete item; - m_children.Erase( node ); - return true; -} - -bool wxSizer::Replace( wxWindow *oldwin, wxWindow *newwin, bool recursive ) -{ - wxASSERT_MSG( oldwin, _T("Replacing NULL window") ); - wxASSERT_MSG( newwin, _T("Replacing with NULL window") ); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetWindow() == oldwin) - { - item->GetWindow()->SetContainingSizer( NULL ); - item->SetWindow(newwin); - newwin->SetContainingSizer( this ); - return true; - } - else if (recursive && item->IsSizer()) - { - if (item->GetSizer()->Replace( oldwin, newwin, true )) - return true; - } - - node = node->GetNext(); - } - - return false; -} - -bool wxSizer::Replace( wxSizer *oldsz, wxSizer *newsz, bool recursive ) -{ - wxASSERT_MSG( oldsz, _T("Replacing NULL sizer") ); - wxASSERT_MSG( newsz, _T("Replacing with NULL sizer") ); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetSizer() == oldsz) - { - wxSizer *old = item->GetSizer(); - item->SetSizer(newsz); - delete old; - return true; - } - else if (recursive && item->IsSizer()) - { - if (item->GetSizer()->Replace( oldsz, newsz, true )) - return true; - } - - node = node->GetNext(); - } - - return false; -} - -bool wxSizer::Replace( size_t old, wxSizerItem *newitem ) -{ - wxCHECK_MSG( old < m_children.GetCount(), false, _T("Replace index is out of range") ); - wxASSERT_MSG( newitem, _T("Replacing with NULL item") ); - - wxSizerItemList::compatibility_iterator node = m_children.Item( old ); - - wxCHECK_MSG( node, false, _T("Failed to find child node") ); - - wxSizerItem *item = node->GetData(); - node->SetData(newitem); - - if (item->IsWindow() && item->GetWindow()) - item->GetWindow()->SetContainingSizer(NULL); - - delete item; - - return true; -} - -void wxSizer::Clear( bool delete_windows ) -{ - // First clear the ContainingSizer pointers - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->IsWindow()) - item->GetWindow()->SetContainingSizer( NULL ); - node = node->GetNext(); - } - - // Destroy the windows if needed - if (delete_windows) - DeleteWindows(); - - // Now empty the list - WX_CLEAR_LIST(wxSizerItemList, m_children); -} - -void wxSizer::DeleteWindows() -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - item->DeleteWindows(); - node = node->GetNext(); - } -} - -wxSize wxSizer::ComputeFittingWindowSize(wxWindow *window) -{ - // take the min size by default and limit it by max size - wxSize size = GetMinWindowSize(window); - wxSize sizeMax = GetMaxWindowSize(window); - - wxTopLevelWindow *tlw = wxDynamicCast(window, wxTopLevelWindow); - if ( tlw ) - { - // hack for small screen devices where TLWs are always full screen - if ( tlw->IsAlwaysMaximized() ) - { - size = tlw->GetSize(); - } - else // normal situation - { - // limit the window to the size of the display it is on - int disp = wxDisplay::GetFromWindow(window); - if ( disp == wxNOT_FOUND ) - { - // or, if we don't know which one it is, of the main one - disp = 0; - } - - sizeMax = wxDisplay(disp).GetClientArea().GetSize(); - } - } - - if ( sizeMax.x != wxDefaultCoord && size.x > sizeMax.x ) - size.x = sizeMax.x; - if ( sizeMax.y != wxDefaultCoord && size.y > sizeMax.y ) - size.y = sizeMax.y; - - return size; -} - -wxSize wxSizer::ComputeFittingClientSize(wxWindow *window) -{ - wxCHECK_MSG( window, wxDefaultSize, _T("window can't be NULL") ); - - return window->WindowToClientSize(ComputeFittingWindowSize(window)); -} - -wxSize wxSizer::Fit( wxWindow *window ) -{ - wxSize size = ComputeFittingWindowSize(window); - window->SetSize(size); - return size; -} - -void wxSizer::FitInside( wxWindow *window ) -{ - wxSize size; - if (window->IsTopLevel()) - size = VirtualFitSize( window ); - else - size = GetMinClientSize( window ); - - window->SetVirtualSize( size ); -} - -void wxSizer::Layout() -{ - // (re)calculates minimums needed for each item and other preparations - // for layout - CalcMin(); - - // Applies the layout and repositions/resizes the items - RecalcSizes(); -} - -void wxSizer::SetSizeHints( wxWindow *window ) -{ - // Preserve the window's max size hints, but set the - // lower bound according to the sizer calculations. - - // This is equivalent to calling Fit(), except that we need to set - // the size hints _in between_ the two steps performed by Fit - // (1. ComputeFittingWindowSize, 2. SetSize). That's because - // otherwise SetSize() could have no effect if there already are - // size hints in effect that forbid requested size. - const wxSize size = ComputeFittingWindowSize(window); - - window->SetSizeHints( size.x, - size.y, - window->GetMaxWidth(), - window->GetMaxHeight() ); - - window->SetSize(size); -} - -void wxSizer::SetVirtualSizeHints( wxWindow *window ) -{ - // Preserve the window's max size hints, but set the - // lower bound according to the sizer calculations. - - FitInside( window ); - wxSize size( window->GetVirtualSize() ); - window->SetVirtualSizeHints( size.x, - size.y, - window->GetMaxWidth(), - window->GetMaxHeight() ); -} - -wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const -{ - return window->GetMaxSize(); -} - -wxSize wxSizer::GetMinWindowSize( wxWindow *window ) -{ - wxSize minSize( GetMinSize() ); - wxSize size( window->GetSize() ); - wxSize client_size( window->GetClientSize() ); - - return wxSize( minSize.x+size.x-client_size.x, - minSize.y+size.y-client_size.y ); -} - -// TODO on mac we need a function that determines how much free space this -// min size contains, in order to make sure that we have 20 pixels of free -// space around the controls -wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const -{ - wxSize maxSize( window->GetMaxSize() ); - - if ( maxSize != wxDefaultSize ) - { - wxSize size( window->GetSize() ); - wxSize client_size( window->GetClientSize() ); - - return wxSize( maxSize.x + client_size.x - size.x, - maxSize.y + client_size.y - size.y ); - } - else - return wxDefaultSize; -} - -wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) ) -{ - return GetMinSize(); // Already returns client size. -} - -wxSize wxSizer::VirtualFitSize( wxWindow *window ) -{ - wxSize size = GetMinClientSize( window ); - wxSize sizeMax = GetMaxClientSize( window ); - - // Limit the size if sizeMax != wxDefaultSize - - if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord ) - size.x = sizeMax.x; - if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord ) - size.y = sizeMax.y; - - return size; -} - -void wxSizer::SetDimension( int x, int y, int width, int height ) -{ - m_position.x = x; - m_position.y = y; - m_size.x = width; - m_size.y = height; - Layout(); -} - -wxSize wxSizer::GetMinSize() -{ - wxSize ret( CalcMin() ); - if (ret.x < m_minSize.x) ret.x = m_minSize.x; - if (ret.y < m_minSize.y) ret.y = m_minSize.y; - return ret; -} - -void wxSizer::DoSetMinSize( int width, int height ) -{ - m_minSize.x = width; - m_minSize.y = height; -} - -bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height ) -{ - wxASSERT_MSG( window, _T("SetMinSize for NULL window") ); - - // Is it our immediate child? - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetWindow() == window) - { - item->SetMinSize( width, height ); - return true; - } - node = node->GetNext(); - } - - // No? Search any subsizers we own then - - node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if ( item->GetSizer() && - item->GetSizer()->DoSetItemMinSize( window, width, height ) ) - { - // A child sizer found the requested windw, exit. - return true; - } - node = node->GetNext(); - } - - return false; -} - -bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height ) -{ - wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") ); - - // Is it our immediate child? - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetSizer() == sizer) - { - item->GetSizer()->DoSetMinSize( width, height ); - return true; - } - node = node->GetNext(); - } - - // No? Search any subsizers we own then - - node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if ( item->GetSizer() && - item->GetSizer()->DoSetItemMinSize( sizer, width, height ) ) - { - // A child found the requested sizer, exit. - return true; - } - node = node->GetNext(); - } - - return false; -} - -bool wxSizer::DoSetItemMinSize( size_t index, int width, int height ) -{ - wxSizerItemList::compatibility_iterator node = m_children.Item( index ); - - wxCHECK_MSG( node, false, _T("Failed to find child node") ); - - wxSizerItem *item = node->GetData(); - - if (item->GetSizer()) - { - // Sizers contains the minimal size in them, if not calculated ... - item->GetSizer()->DoSetMinSize( width, height ); - } - else - { - // ... but the minimal size of spacers and windows is stored via the item - item->SetMinSize( width, height ); - } - - return true; -} - -wxSizerItem* wxSizer::GetItem( wxWindow *window, bool recursive ) -{ - wxASSERT_MSG( window, _T("GetItem for NULL window") ); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetWindow() == window) - { - return item; - } - else if (recursive && item->IsSizer()) - { - wxSizerItem *subitem = item->GetSizer()->GetItem( window, true ); - if (subitem) - return subitem; - } - - node = node->GetNext(); - } - - return NULL; -} - -wxSizerItem* wxSizer::GetItem( wxSizer *sizer, bool recursive ) -{ - wxASSERT_MSG( sizer, _T("GetItem for NULL sizer") ); - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetSizer() == sizer) - { - return item; - } - else if (recursive && item->IsSizer()) - { - wxSizerItem *subitem = item->GetSizer()->GetItem( sizer, true ); - if (subitem) - return subitem; - } - - node = node->GetNext(); - } - - return NULL; -} - -wxSizerItem* wxSizer::GetItem( size_t index ) -{ - wxCHECK_MSG( index < m_children.GetCount(), - NULL, - _T("GetItem index is out of range") ); - - return m_children.Item( index )->GetData(); -} - -bool wxSizer::Show( wxWindow *window, bool show, bool recursive ) -{ - wxSizerItem *item = GetItem( window, recursive ); - - if ( item ) - { - item->Show( show ); - return true; - } - - return false; -} - -bool wxSizer::Show( wxSizer *sizer, bool show, bool recursive ) -{ - wxSizerItem *item = GetItem( sizer, recursive ); - - if ( item ) - { - item->Show( show ); - return true; - } - - return false; -} - -bool wxSizer::Show( size_t index, bool show) -{ - wxSizerItem *item = GetItem( index ); - - if ( item ) - { - item->Show( show ); - return true; - } - - return false; -} - -void wxSizer::ShowItems( bool show ) -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - node->GetData()->Show( show ); - node = node->GetNext(); - } -} - -bool wxSizer::IsShown( wxWindow *window ) const -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetWindow() == window) - { - return item->IsShown(); - } - node = node->GetNext(); - } - - wxFAIL_MSG( _T("IsShown failed to find sizer item") ); - - return false; -} - -bool wxSizer::IsShown( wxSizer *sizer ) const -{ - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->GetSizer() == sizer) - { - return item->IsShown(); - } - node = node->GetNext(); - } - - wxFAIL_MSG( _T("IsShown failed to find sizer item") ); - - return false; -} - -bool wxSizer::IsShown( size_t index ) const -{ - wxCHECK_MSG( index < m_children.GetCount(), - false, - _T("IsShown index is out of range") ); - - return m_children.Item( index )->GetData()->IsShown(); -} - - -//--------------------------------------------------------------------------- -// wxGridSizer -//--------------------------------------------------------------------------- - -wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap ) - : m_rows( ( cols == 0 && rows == 0 ) ? 1 : rows ) - , m_cols( cols ) - , m_vgap( vgap ) - , m_hgap( hgap ) -{ -} - -wxGridSizer::wxGridSizer( int cols, int vgap, int hgap ) - : m_rows( cols == 0 ? 1 : 0 ) - , m_cols( cols ) - , m_vgap( vgap ) - , m_hgap( hgap ) -{ -} - -int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const -{ - int nitems = m_children.GetCount(); - if ( nitems) - { - if ( m_cols ) - { - ncols = m_cols; - nrows = (nitems + m_cols - 1) / m_cols; - } - else if ( m_rows ) - { - ncols = (nitems + m_rows - 1) / m_rows; - nrows = m_rows; - } - else // 0 columns, 0 rows? - { - wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") ); - - nrows = ncols = 0; - } - } - - return nitems; -} - -void wxGridSizer::RecalcSizes() -{ - int nitems, nrows, ncols; - if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 ) - return; - - wxSize sz( GetSize() ); - wxPoint pt( GetPosition() ); - - int w = (sz.x - (ncols - 1) * m_hgap) / ncols; - int h = (sz.y - (nrows - 1) * m_vgap) / nrows; - - int x = pt.x; - for (int c = 0; c < ncols; c++) - { - int y = pt.y; - for (int r = 0; r < nrows; r++) - { - int i = r * ncols + c; - if (i < nitems) - { - wxSizerItemList::compatibility_iterator node = m_children.Item( i ); - - wxASSERT_MSG( node, _T("Failed to find SizerItemList node") ); - - SetItemBounds( node->GetData(), x, y, w, h); - } - y = y + h + m_vgap; - } - x = x + w + m_hgap; - } -} - -wxSize wxGridSizer::CalcMin() -{ - int nrows, ncols; - if ( CalcRowsCols(nrows, ncols) == 0 ) - return wxSize(); - - // Find the max width and height for any component - int w = 0; - int h = 0; - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - wxSize sz( item->CalcMin() ); - - w = wxMax( w, sz.x ); - h = wxMax( h, sz.y ); - - node = node->GetNext(); - } - - return wxSize( ncols * w + (ncols-1) * m_hgap, - nrows * h + (nrows-1) * m_vgap ); -} - -void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h ) -{ - wxPoint pt( x,y ); - wxSize sz( item->GetMinSizeWithBorder() ); - int flag = item->GetFlag(); - - if ((flag & wxEXPAND) || (flag & wxSHAPED)) - { - sz = wxSize(w, h); - } - else - { - if (flag & wxALIGN_CENTER_HORIZONTAL) - { - pt.x = x + (w - sz.x) / 2; - } - else if (flag & wxALIGN_RIGHT) - { - pt.x = x + (w - sz.x); - } - - if (flag & wxALIGN_CENTER_VERTICAL) - { - pt.y = y + (h - sz.y) / 2; - } - else if (flag & wxALIGN_BOTTOM) - { - pt.y = y + (h - sz.y); - } - } - - item->SetDimension(pt, sz); -} - -//--------------------------------------------------------------------------- -// wxFlexGridSizer -//--------------------------------------------------------------------------- - -wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap ) - : wxGridSizer( rows, cols, vgap, hgap ), - m_flexDirection(wxBOTH), - m_growMode(wxFLEX_GROWMODE_SPECIFIED) -{ -} - -wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap ) - : wxGridSizer( cols, vgap, hgap ), - m_flexDirection(wxBOTH), - m_growMode(wxFLEX_GROWMODE_SPECIFIED) -{ -} - -wxFlexGridSizer::~wxFlexGridSizer() -{ -} - -void wxFlexGridSizer::RecalcSizes() -{ - int nitems, nrows, ncols; - if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 ) - return; - - wxPoint pt( GetPosition() ); - wxSize sz( GetSize() ); - - AdjustForGrowables(sz, m_calculatedMinSize, nrows, ncols); - - sz = wxSize( pt.x + sz.x, pt.y + sz.y ); - - int x = pt.x; - for (int c = 0; c < ncols; c++) - { - int y = pt.y; - for (int r = 0; r < nrows; r++) - { - int i = r * ncols + c; - if (i < nitems) - { - wxSizerItemList::compatibility_iterator node = m_children.Item( i ); - - wxASSERT_MSG( node, _T("Failed to find node") ); - - int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) ); - int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) ); - - SetItemBounds( node->GetData(), x, y, w, h); - } - if (m_rowHeights[r] != -1) - y = y + m_rowHeights[r] + m_vgap; - } - if (m_colWidths[c] != -1) - x = x + m_colWidths[c] + m_hgap; - } -} - -wxSize wxFlexGridSizer::CalcMin() -{ - int nrows, - ncols; - size_t i, s; - - // Number of rows/columns can change as items are added or removed. - if ( !CalcRowsCols(nrows, ncols) ) - return wxSize(); - - m_rowHeights.SetCount(nrows); - m_colWidths.SetCount(ncols); - - // We have to recalcuate the sizes in case the item minimum size has - // changed since the previous layout, or the item has been hidden using - // wxSizer::Show(). If all the items in a row/column are hidden, the final - // dimension of the row/column will be -1, indicating that the column - // itself is hidden. - for( s = m_rowHeights.GetCount(), i = 0; i < s; ++i ) - m_rowHeights[ i ] = -1; - for( s = m_colWidths.GetCount(), i = 0; i < s; ++i ) - m_colWidths[ i ] = -1; - - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - - i = 0; - while (node) - { - wxSizerItem *item = node->GetData(); - if ( item->ShouldAccountFor() ) - { - wxSize sz( item->CalcMin() ); - int row = i / ncols; - int col = i % ncols; - - m_rowHeights[ row ] = wxMax( wxMax( 0, sz.y ), m_rowHeights[ row ] ); - m_colWidths[ col ] = wxMax( wxMax( 0, sz.x ), m_colWidths[ col ] ); - } - - node = node->GetNext(); - i++; - } - - AdjustForFlexDirection(); - - // Sum total minimum size, including gaps between rows/columns. - // -1 is used as a magic number meaning empty column. - int width = 0; - for (int col = 0; col < ncols; col++) - if ( m_colWidths[ col ] != -1 ) - width += m_colWidths[ col ] + m_hgap; - if (width > 0) - width -= m_hgap; - - int height = 0; - for (int row = 0; row < nrows; row++) - if ( m_rowHeights[ row ] != -1 ) - height += m_rowHeights[ row ] + m_vgap; - if (height > 0) - height -= m_vgap; - - m_calculatedMinSize = wxSize( width, height ); - return m_calculatedMinSize; -} - -void wxFlexGridSizer::AdjustForFlexDirection() -{ - // the logic in CalcMin works when we resize flexibly in both directions - // but maybe this is not the case - if ( m_flexDirection != wxBOTH ) - { - // select the array corresponding to the direction in which we do *not* - // resize flexibly - wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths - : m_rowHeights; - - const size_t count = array.GetCount(); - - // find the largest value in this array - size_t n; - int largest = 0; - - for ( n = 0; n < count; ++n ) - { - if ( array[n] > largest ) - largest = array[n]; - } - - // and now fill it with the largest value - for ( n = 0; n < count; ++n ) - { - // don't touch hidden rows - if ( array[n] != -1 ) - array[n] = largest; - } - } -} - - -void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz, const wxSize& minsz, - int nrows, int ncols) -{ - // what to do with the rows? by default, resize them proportionally - if ( sz.y > minsz.y && ( (m_flexDirection & wxVERTICAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) ) - { - int sum_proportions = 0; - int growable_space = 0; - int num = 0; - size_t idx; - for (idx = 0; idx < m_growableRows.GetCount(); idx++) - { - // Since the number of rows/columns can change as items are - // inserted/deleted, we need to verify at runtime that the - // requested growable rows/columns are still valid. - if (m_growableRows[idx] >= nrows) - continue; - - // If all items in a row/column are hidden, that row/column will - // have a dimension of -1. This causes the row/column to be - // hidden completely. - if (m_rowHeights[ m_growableRows[idx] ] == -1) - continue; - sum_proportions += m_growableRowsProportions[idx]; - growable_space += m_rowHeights[ m_growableRows[idx] ]; - num++; - } - - if (num > 0) - { - for (idx = 0; idx < m_growableRows.GetCount(); idx++) - { - if (m_growableRows[idx] >= nrows ) - continue; - if (m_rowHeights[ m_growableRows[idx] ] != -1) - { - int delta = (sz.y - minsz.y); - if (sum_proportions == 0) - delta = (delta/num) + m_rowHeights[ m_growableRows[idx] ]; - else - delta = ((delta+growable_space)*m_growableRowsProportions[idx]) / sum_proportions; - m_rowHeights[ m_growableRows[idx] ] = delta; - } - } - } - } - else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) ) - { - // rounding problem? - for ( int row = 0; row < nrows; ++row ) - m_rowHeights[ row ] = sz.y / nrows; - } - - // the same logic as above but for the columns - if ( sz.x > minsz.x && ( (m_flexDirection & wxHORIZONTAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) ) - { - int sum_proportions = 0; - int growable_space = 0; - int num = 0; - size_t idx; - for (idx = 0; idx < m_growableCols.GetCount(); idx++) - { - // Since the number of rows/columns can change as items are - // inserted/deleted, we need to verify at runtime that the - // requested growable rows/columns are still valid. - if (m_growableCols[idx] >= ncols) - continue; - - // If all items in a row/column are hidden, that row/column will - // have a dimension of -1. This causes the column to be hidden - // completely. - if (m_colWidths[ m_growableCols[idx] ] == -1) - continue; - sum_proportions += m_growableColsProportions[idx]; - growable_space += m_colWidths[ m_growableCols[idx] ]; - num++; - } - - if (num > 0) - { - for (idx = 0; idx < m_growableCols.GetCount(); idx++) - { - if (m_growableCols[idx] >= ncols ) - continue; - if (m_colWidths[ m_growableCols[idx] ] != -1) - { - int delta = (sz.x - minsz.x); - if (sum_proportions == 0) - delta = (delta/num) + m_colWidths[ m_growableCols[idx] ]; - else - delta = ((delta+growable_space)*m_growableColsProportions[idx])/sum_proportions; - m_colWidths[ m_growableCols[idx] ] = delta; - } - } - } - } - else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) ) - { - for ( int col=0; col < ncols; ++col ) - m_colWidths[ col ] = sz.x / ncols; - } -} - - -void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion ) -{ - m_growableRows.Add( idx ); - m_growableRowsProportions.Add( proportion ); -} - -void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion ) -{ - m_growableCols.Add( idx ); - m_growableColsProportions.Add( proportion ); -} - -// helper function for RemoveGrowableCol/Row() -static void -DoRemoveFromArrays(size_t idx, wxArrayInt& items, wxArrayInt& proportions) -{ - const size_t count = items.size(); - for ( size_t n = 0; n < count; n++ ) - { - if ( (size_t)items[n] == idx ) - { - items.RemoveAt(n); - proportions.RemoveAt(n); - return; - } - } - - wxFAIL_MSG( _T("column/row is already not growable") ); -} - -void wxFlexGridSizer::RemoveGrowableCol( size_t idx ) -{ - DoRemoveFromArrays(idx, m_growableCols, m_growableColsProportions); -} - -void wxFlexGridSizer::RemoveGrowableRow( size_t idx ) -{ - DoRemoveFromArrays(idx, m_growableRows, m_growableRowsProportions); -} - -//--------------------------------------------------------------------------- -// wxBoxSizer -//--------------------------------------------------------------------------- - -wxBoxSizer::wxBoxSizer( int orient ) - : m_orient( orient ) -{ -} - -void wxBoxSizer::RecalcSizes() -{ - if (m_children.GetCount() == 0) - return; - - int delta = 0; - if (m_stretchable) - { - if (m_orient == wxHORIZONTAL) - delta = m_size.x - m_fixedWidth; - else - delta = m_size.y - m_fixedHeight; - } - - wxPoint pt( m_position ); - - int stretchable = m_stretchable; - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->ShouldAccountFor()) - { - wxSize size( item->GetMinSizeWithBorder() ); - - if (m_orient == wxVERTICAL) - { - wxCoord height = size.y; - if (item->GetProportion()) - { - // Because of at least one visible item has non-zero - // proportion then m_stretchable is not zero - height = (delta * item->GetProportion()) / stretchable; - delta -= height; - stretchable -= item->GetProportion(); - } - - wxPoint child_pos( pt ); - wxSize child_size( size.x, height ); - - if (item->GetFlag() & (wxEXPAND | wxSHAPED)) - child_size.x = m_size.x; - else if (item->GetFlag() & wxALIGN_RIGHT) - child_pos.x += m_size.x - size.x; - else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL)) - // XXX wxCENTER is added for backward compatibility; - // wxALIGN_CENTER should be used in new code - child_pos.x += (m_size.x - size.x) / 2; - - item->SetDimension( child_pos, child_size ); - - pt.y += height; - } - else - { - wxCoord width = size.x; - if (item->GetProportion()) - { - // Because of at least one visible item has non-zero - // proportion then m_stretchable is not zero - width = (delta * item->GetProportion()) / stretchable; - delta -= width; - stretchable -= item->GetProportion(); - } - - wxPoint child_pos( pt ); - wxSize child_size( width, size.y ); - - if (item->GetFlag() & (wxEXPAND | wxSHAPED)) - child_size.y = m_size.y; - else if (item->GetFlag() & wxALIGN_BOTTOM) - child_pos.y += m_size.y - size.y; - else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL)) - // XXX wxCENTER is added for backward compatibility; - // wxALIGN_CENTER should be used in new code - child_pos.y += (m_size.y - size.y) / 2; - - if ( m_containingWindow ) - { - child_pos.x = m_containingWindow->AdjustForLayoutDirection - ( - child_pos.x, - width, - m_size.x - ); - } - - item->SetDimension( child_pos, child_size ); - - pt.x += width; - } - } - - node = node->GetNext(); - } -} - -wxSize wxBoxSizer::CalcMin() -{ - if (m_children.GetCount() == 0) - return wxSize(); - - m_stretchable = 0; - m_minWidth = 0; - m_minHeight = 0; - m_fixedWidth = 0; - m_fixedHeight = 0; - - // precalc item minsizes and count proportions - wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if ( item->ShouldAccountFor() ) - { - item->CalcMin(); // result is stored in the item - - m_stretchable += item->GetProportion(); - } - - node = node->GetNext(); - } - - // Total minimum size (width or height) of sizer - int maxMinSize = 0; - - node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->ShouldAccountFor() && item->GetProportion() != 0) - { - int stretch = item->GetProportion(); - wxSize size( item->GetMinSizeWithBorder() ); - int minSize; - - // Integer division rounded up is (a + b - 1) / b - // Round up needed in order to guarantee that all - // all items will have size not less then their min size - if (m_orient == wxHORIZONTAL) - minSize = ( size.x*m_stretchable + stretch - 1)/stretch; - else - minSize = ( size.y*m_stretchable + stretch - 1)/stretch; - - if (minSize > maxMinSize) - maxMinSize = minSize; - } - node = node->GetNext(); - } - - // Calculate overall minimum size - node = m_children.GetFirst(); - while (node) - { - wxSizerItem *item = node->GetData(); - - if (item->ShouldAccountFor()) - { - wxSize size( item->GetMinSizeWithBorder() ); - if (item->GetProportion() != 0) - { - if (m_orient == wxHORIZONTAL) - size.x = (maxMinSize*item->GetProportion())/m_stretchable; - else - size.y = (maxMinSize*item->GetProportion())/m_stretchable; - } - else - { - if (m_orient == wxVERTICAL) - { - m_fixedHeight += size.y; - m_fixedWidth = wxMax( m_fixedWidth, size.x ); - } - else - { - m_fixedWidth += size.x; - m_fixedHeight = wxMax( m_fixedHeight, size.y ); - } - } - - if (m_orient == wxHORIZONTAL) - { - m_minWidth += size.x; - m_minHeight = wxMax( m_minHeight, size.y ); - } - else - { - m_minHeight += size.y; - m_minWidth = wxMax( m_minWidth, size.x ); - } - } - node = node->GetNext(); - } - - return wxSize( m_minWidth, m_minHeight ); -} - -//--------------------------------------------------------------------------- -// wxStaticBoxSizer -//--------------------------------------------------------------------------- - -#if wxUSE_STATBOX - -wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient ) - : wxBoxSizer( orient ), - m_staticBox( box ) -{ - wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") ); - - // do this so that our Detach() is called if the static box is destroyed - // before we are - m_staticBox->SetContainingSizer(this); -} - -wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s) - : wxBoxSizer(orient), - m_staticBox(new wxStaticBox(win, wxID_ANY, s)) -{ - // same as above - m_staticBox->SetContainingSizer(this); -} - -wxStaticBoxSizer::~wxStaticBoxSizer() -{ - delete m_staticBox; -} - -static void GetStaticBoxBorders( wxStaticBox *box, - int *borderTop, - int *borderOther) -{ - // this has to be done platform by platform as there is no way to - // guess the thickness of a wxStaticBox border - box->GetBordersForSizer(borderTop, borderOther); -} - -void wxStaticBoxSizer::RecalcSizes() -{ - int top_border, other_border; - GetStaticBoxBorders(m_staticBox, &top_border, &other_border); - - m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y ); - - wxPoint old_pos( m_position ); - m_position.x += other_border; - m_position.y += top_border; - wxSize old_size( m_size ); - m_size.x -= 2*other_border; - m_size.y -= top_border + other_border; - - wxBoxSizer::RecalcSizes(); - - m_position = old_pos; - m_size = old_size; -} - -wxSize wxStaticBoxSizer::CalcMin() -{ - int top_border, other_border; - GetStaticBoxBorders(m_staticBox, &top_border, &other_border); - - wxSize ret( wxBoxSizer::CalcMin() ); - ret.x += 2*other_border; - ret.y += other_border + top_border; - - return ret; -} - -void wxStaticBoxSizer::ShowItems( bool show ) -{ - m_staticBox->Show( show ); - wxBoxSizer::ShowItems( show ); -} - -bool wxStaticBoxSizer::Detach( wxWindow *window ) -{ - // avoid deleting m_staticBox in our dtor if it's being detached from the - // sizer (which can happen because it's being already destroyed for - // example) - if ( window == m_staticBox ) - { - m_staticBox = NULL; - return true; - } - - return wxSizer::Detach( window ); -} - -#endif // wxUSE_STATBOX - -#if wxUSE_BUTTON - -wxStdDialogButtonSizer::wxStdDialogButtonSizer() - : wxBoxSizer(wxHORIZONTAL) -{ - // Vertical buttons with lots of space on either side - // looks rubbish on WinCE, so let's not do this for now. - // If we are going to use vertical buttons, we should - // put the sizer to the right of other controls in the dialog, - // and that's beyond the scope of this sizer. -#ifndef __WXWINCE__ - bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); - // If we have a PDA screen, put yes/no button over - // all other buttons, otherwise on the left side. - if (is_pda) - m_orient = wxVERTICAL; -#endif - - m_buttonAffirmative = NULL; - m_buttonApply = NULL; - m_buttonNegative = NULL; - m_buttonCancel = NULL; - m_buttonHelp = NULL; -} - -void wxStdDialogButtonSizer::AddButton(wxButton *mybutton) -{ - switch (mybutton->GetId()) - { - case wxID_OK: - case wxID_YES: - case wxID_SAVE: - m_buttonAffirmative = mybutton; - break; - case wxID_APPLY: - m_buttonApply = mybutton; - break; - case wxID_NO: - m_buttonNegative = mybutton; - break; - case wxID_CANCEL: - m_buttonCancel = mybutton; - break; - case wxID_HELP: - case wxID_CONTEXT_HELP: - m_buttonHelp = mybutton; - break; - default: - break; - } -} - -void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button ) -{ - m_buttonAffirmative = button; -} - -void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button ) -{ - m_buttonNegative = button; -} - -void wxStdDialogButtonSizer::SetCancelButton( wxButton *button ) -{ - m_buttonCancel = button; -} - -void wxStdDialogButtonSizer::Realize() -{ -#ifdef __WXMAC__ - Add(0, 0, 0, wxLEFT, 6); - if (m_buttonHelp) - Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6); - - if (m_buttonNegative){ - // HIG POLICE BULLETIN - destructive buttons need extra padding - // 24 pixels on either side - Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12); - } - - // extra whitespace between help/negative and cancel/ok buttons - Add(0, 0, 1, wxEXPAND, 0); - - if (m_buttonCancel){ - Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6); - // Cancel or help should be default - // m_buttonCancel->SetDefaultButton(); - } - - // Ugh, Mac doesn't really have apply dialogs, so I'll just - // figure the best place is between Cancel and OK - if (m_buttonApply) - Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6); - - if (m_buttonAffirmative){ - Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6); - - if (m_buttonAffirmative->GetId() == wxID_SAVE){ - // these buttons have set labels under Mac so we should use them - m_buttonAffirmative->SetLabel(_("Save")); - if (m_buttonNegative) - m_buttonNegative->SetLabel(_("Don't Save")); - } - } - - // Extra space around and at the right - Add(12, 24); -#elif defined(__WXGTK20__) - Add(0, 0, 0, wxLEFT, 9); - if (m_buttonHelp) - Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); - - // extra whitespace between help and cancel/ok buttons - Add(0, 0, 1, wxEXPAND, 0); - - if (m_buttonNegative){ - Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); - } - - if (m_buttonCancel){ - Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); - // Cancel or help should be default - // m_buttonCancel->SetDefaultButton(); - } - - if (m_buttonApply) - Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); - - if (m_buttonAffirmative) - Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6); -#elif defined(__WXMSW__) - // Windows - - // right-justify buttons - Add(0, 0, 1, wxEXPAND, 0); - - if (m_buttonAffirmative){ - Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x); - } - - if (m_buttonNegative){ - Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x); - } - - if (m_buttonCancel){ - Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x); - } - if (m_buttonApply) - Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x); - - if (m_buttonHelp) - Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x); -#else - // GTK+1 and any other platform - - // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog - if (m_buttonHelp) - Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x); - - // extra whitespace between help and cancel/ok buttons - Add(0, 0, 1, wxEXPAND, 0); - - if (m_buttonApply) - Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x); - - if (m_buttonAffirmative){ - Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x); - } - - if (m_buttonNegative){ - Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x); - } - - if (m_buttonCancel){ - Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x); - // Cancel or help should be default - // m_buttonCancel->SetDefaultButton(); - } - -#endif -} - -#endif // wxUSE_BUTTON - -#if WXWIN_COMPATIBILITY_2_4 - -// ---------------------------------------------------------------------------- -// wxNotebookSizer -// ---------------------------------------------------------------------------- - -#if wxUSE_BOOKCTRL -IMPLEMENT_CLASS(wxBookCtrlSizer, wxSizer) -#if wxUSE_NOTEBOOK -IMPLEMENT_CLASS(wxNotebookSizer, wxBookCtrlSizer) -#endif // wxUSE_NOTEBOOK -#endif // wxUSE_BOOKCTRL - -#if wxUSE_BOOKCTRL - -#if WXWIN_COMPATIBILITY_2_6 - -wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrlBase *bookctrl) - : m_bookctrl(bookctrl) -{ - wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") ); -} - -#endif // WXWIN_COMPATIBILITY_2_6 - -void wxBookCtrlSizer::RecalcSizes() -{ - m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y ); -} - -wxSize wxBookCtrlSizer::CalcMin() -{ - wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0,0)); - - sizeBorder.x += 5; - sizeBorder.y += 5; - - if ( m_bookctrl->GetPageCount() == 0 ) - { - return wxSize(sizeBorder.x + 10, sizeBorder.y + 10); - } - - int maxX = 0; - int maxY = 0; - - wxWindowList::compatibility_iterator - node = m_bookctrl->GetChildren().GetFirst(); - while (node) - { - wxWindow *item = node->GetData(); - wxSizer *itemsizer = item->GetSizer(); - - if (itemsizer) - { - wxSize subsize( itemsizer->CalcMin() ); - - if (subsize.x > maxX) - maxX = subsize.x; - if (subsize.y > maxY) - maxY = subsize.y; - } - - node = node->GetNext(); - } - - return wxSize( maxX, maxY ) + sizeBorder; -} - -#if wxUSE_NOTEBOOK - -#if WXWIN_COMPATIBILITY_2_6 - -wxNotebookSizer::wxNotebookSizer(wxNotebook *nb) -{ - wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a control") ); - m_bookctrl = nb; -} - -#endif // WXWIN_COMPATIBILITY_2_6 - -#endif // wxUSE_NOTEBOOOK -#endif // wxUSE_BOOKCTRL - -#endif // WXWIN_COMPATIBILITY_2_4 +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/sizer.cpp +// Purpose: provide new wxSizer class for layout +// Author: Robert Roebling and Robin Dunn, contributions by +// Dirk Holtwick, Ron Lee +// Modified by: Ron Lee +// Created: +// RCS-ID: $Id: sizer.cpp 66936 2011-02-17 09:52:57Z JS $ +// Copyright: (c) Robin Dunn, Robert Roebling +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/display.h" +#include "wx/sizer.h" + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/math.h" + #include "wx/utils.h" + #include "wx/settings.h" + #include "wx/button.h" + #include "wx/statbox.h" + #include "wx/toplevel.h" +#endif // WX_PRECOMP + +#include "wx/listimpl.cpp" + +#if WXWIN_COMPATIBILITY_2_4 + #include "wx/notebook.h" +#endif + +//--------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxSizerItem, wxObject) +IMPLEMENT_CLASS(wxSizer, wxObject) +IMPLEMENT_CLASS(wxGridSizer, wxSizer) +IMPLEMENT_CLASS(wxFlexGridSizer, wxGridSizer) +IMPLEMENT_CLASS(wxBoxSizer, wxSizer) +#if wxUSE_STATBOX +IMPLEMENT_CLASS(wxStaticBoxSizer, wxBoxSizer) +#endif +#if wxUSE_BUTTON +IMPLEMENT_CLASS(wxStdDialogButtonSizer, wxBoxSizer) +#endif + +WX_DEFINE_EXPORTED_LIST( wxSizerItemList ) + +/* + TODO PROPERTIES + sizeritem + object + object_ref + minsize + option + flag + border + spacer + option + flag + borfder + boxsizer + orient + staticboxsizer + orient + label + gridsizer + rows + cols + vgap + hgap + flexgridsizer + rows + cols + vgap + hgap + growablerows + growablecols + minsize +*/ + + +// ---------------------------------------------------------------------------- +// wxSizerFlags +// ---------------------------------------------------------------------------- + +wxSizerFlags& wxSizerFlags::ReserveSpaceEvenIfHidden() +{ + m_flags |= wxRESERVE_SPACE_EVEN_IF_HIDDEN; + return *this; +} + +// ---------------------------------------------------------------------------- +// wxSizerItem +// ---------------------------------------------------------------------------- + +void wxSizerItem::Init(const wxSizerFlags& flags) +{ + Init(); + + m_proportion = flags.GetProportion(); + m_flag = flags.GetFlags(); + m_border = flags.GetBorderInPixels(); +} + +wxSizerItem::wxSizerItem() +{ + Init(); + + m_proportion = 0; + m_border = 0; + m_flag = 0; + + m_kind = Item_None; +} + +// window item +void wxSizerItem::SetWindow(wxWindow *window) +{ + wxCHECK_RET( window, _T("NULL window in wxSizerItem::SetWindow()") ); + + m_kind = Item_Window; + m_window = window; + + // window doesn't become smaller than its initial size, whatever happens + m_minSize = window->GetSize(); + + if ( m_flag & wxFIXED_MINSIZE ) + window->SetMinSize(m_minSize); + + // aspect ratio calculated from initial size + SetRatio(m_minSize); +} + +wxSizerItem::wxSizerItem(wxWindow *window, + int proportion, + int flag, + int border, + wxObject* userData) + : m_proportion(proportion), + m_border(border), + m_flag(flag), + m_userData(userData) +{ + SetWindow(window); +} + +// sizer item +void wxSizerItem::SetSizer(wxSizer *sizer) +{ + m_kind = Item_Sizer; + m_sizer = sizer; +} + +wxSizerItem::wxSizerItem(wxSizer *sizer, + int proportion, + int flag, + int border, + wxObject* userData) + : m_proportion(proportion), + m_border(border), + m_flag(flag), + m_ratio(0.0), + m_userData(userData) +{ + SetSizer(sizer); + + // m_minSize is set later +} + +// spacer item +void wxSizerItem::SetSpacer(const wxSize& size) +{ + m_kind = Item_Spacer; + m_spacer = new wxSizerSpacer(size); + m_minSize = size; + SetRatio(size); +} + +wxSizerItem::wxSizerItem(int width, + int height, + int proportion, + int flag, + int border, + wxObject* userData) + : m_minSize(width, height), // minimal size is the initial size + m_proportion(proportion), + m_border(border), + m_flag(flag), + m_userData(userData) +{ + SetSpacer(width, height); +} + +wxSizerItem::~wxSizerItem() +{ + delete m_userData; + + switch ( m_kind ) + { + case Item_None: + break; + + case Item_Window: + m_window->SetContainingSizer(NULL); + break; + + case Item_Sizer: + delete m_sizer; + break; + + case Item_Spacer: + delete m_spacer; + break; + + case Item_Max: + default: + wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); + } +} + +wxSize wxSizerItem::GetSpacer() const +{ + wxSize size; + if ( m_kind == Item_Spacer ) + size = m_spacer->GetSize(); + + return size; +} + + +wxSize wxSizerItem::GetSize() const +{ + wxSize ret; + switch ( m_kind ) + { + case Item_None: + break; + + case Item_Window: + ret = m_window->GetSize(); + break; + + case Item_Sizer: + ret = m_sizer->GetSize(); + break; + + case Item_Spacer: + ret = m_spacer->GetSize(); + break; + + case Item_Max: + default: + wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); + } + + if (m_flag & wxWEST) + ret.x += m_border; + if (m_flag & wxEAST) + ret.x += m_border; + if (m_flag & wxNORTH) + ret.y += m_border; + if (m_flag & wxSOUTH) + ret.y += m_border; + + return ret; +} + +wxSize wxSizerItem::CalcMin() +{ + if (IsSizer()) + { + m_minSize = m_sizer->GetMinSize(); + + // if we have to preserve aspect ratio _AND_ this is + // the first-time calculation, consider ret to be initial size + if ( (m_flag & wxSHAPED) && wxIsNullDouble(m_ratio) ) + SetRatio(m_minSize); + } + else if ( IsWindow() ) + { + // Since the size of the window may change during runtime, we + // should use the current minimal/best size. + m_minSize = m_window->GetEffectiveMinSize(); + } + + return GetMinSizeWithBorder(); +} + +wxSize wxSizerItem::GetMinSizeWithBorder() const +{ + wxSize ret = m_minSize; + + if (m_flag & wxWEST) + ret.x += m_border; + if (m_flag & wxEAST) + ret.x += m_border; + if (m_flag & wxNORTH) + ret.y += m_border; + if (m_flag & wxSOUTH) + ret.y += m_border; + + return ret; +} + + +void wxSizerItem::SetDimension( const wxPoint& pos_, const wxSize& size_ ) +{ + wxPoint pos = pos_; + wxSize size = size_; + if (m_flag & wxSHAPED) + { + // adjust aspect ratio + int rwidth = (int) (size.y * m_ratio); + if (rwidth > size.x) + { + // fit horizontally + int rheight = (int) (size.x / m_ratio); + // add vertical space + if (m_flag & wxALIGN_CENTER_VERTICAL) + pos.y += (size.y - rheight) / 2; + else if (m_flag & wxALIGN_BOTTOM) + pos.y += (size.y - rheight); + // use reduced dimensions + size.y =rheight; + } + else if (rwidth < size.x) + { + // add horizontal space + if (m_flag & wxALIGN_CENTER_HORIZONTAL) + pos.x += (size.x - rwidth) / 2; + else if (m_flag & wxALIGN_RIGHT) + pos.x += (size.x - rwidth); + size.x = rwidth; + } + } + + // This is what GetPosition() returns. Since we calculate + // borders afterwards, GetPosition() will be the left/top + // corner of the surrounding border. + m_pos = pos; + + if (m_flag & wxWEST) + { + pos.x += m_border; + size.x -= m_border; + } + if (m_flag & wxEAST) + { + size.x -= m_border; + } + if (m_flag & wxNORTH) + { + pos.y += m_border; + size.y -= m_border; + } + if (m_flag & wxSOUTH) + { + size.y -= m_border; + } + + if (size.x < 0) + size.x = 0; + if (size.y < 0) + size.y = 0; + + m_rect = wxRect(pos, size); + + switch ( m_kind ) + { + case Item_None: + wxFAIL_MSG( _T("can't set size of uninitialized sizer item") ); + break; + + case Item_Window: + m_window->SetSize(pos.x, pos.y, size.x, size.y, + wxSIZE_ALLOW_MINUS_ONE); + break; + + case Item_Sizer: + m_sizer->SetDimension(pos.x, pos.y, size.x, size.y); + break; + + case Item_Spacer: + m_spacer->SetSize(size); + break; + + case Item_Max: + default: + wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); + } +} + +void wxSizerItem::DeleteWindows() +{ + switch ( m_kind ) + { + case Item_None: + case Item_Spacer: + break; + + case Item_Window: + //We are deleting the window from this sizer - normally + //the window destroys the sizer associated with it, + //which might destroy this, which we don't want + m_window->SetContainingSizer(NULL); + m_window->Destroy(); + //Putting this after the switch will result in a spacer + //not being deleted properly on destruction + m_kind = Item_None; + break; + + case Item_Sizer: + m_sizer->DeleteWindows(); + break; + + case Item_Max: + default: + wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); + } + +} + +void wxSizerItem::Show( bool show ) +{ + switch ( m_kind ) + { + case Item_None: + wxFAIL_MSG( _T("can't show uninitialized sizer item") ); + break; + + case Item_Window: + m_window->Show(show); + break; + + case Item_Sizer: + m_sizer->Show(show); + break; + + case Item_Spacer: + m_spacer->Show(show); + break; + + case Item_Max: + default: + wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); + } +} + +bool wxSizerItem::IsShown() const +{ + switch ( m_kind ) + { + case Item_None: + // we may be called from CalcMin(), just return false so that we're + // not used + break; + + case Item_Window: + return m_window->IsShown(); + + case Item_Sizer: + // arbitrarily decide that if at least one of our elements is + // shown, so are we (this arbitrariness is the reason for + // deprecating this function) + { + // Some apps (such as dialog editors) depend on an empty sizer still + // being laid out correctly and reporting the correct size and position. + if (m_sizer->GetChildren().GetCount() == 0) + return true; + + for ( wxSizerItemList::compatibility_iterator + node = m_sizer->GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + if ( node->GetData()->IsShown() ) + return true; + } + } + return false; + + case Item_Spacer: + return m_spacer->IsShown(); + + case Item_Max: + default: + wxFAIL_MSG( _T("unexpected wxSizerItem::m_kind") ); + } + + return false; +} + +// This is a helper to support wxRESERVE_SPACE_EVEN_IF_HIDDEN. In wx 2.9+, +// this flag is respected by IsShown(), but not in wx 2.8. +bool wxSizerItem::ShouldAccountFor() const +{ + if ( m_flag & wxRESERVE_SPACE_EVEN_IF_HIDDEN ) + return true; + + if ( IsSizer() ) + { + // this mirrors wxSizerItem::IsShown() code above + const wxSizerItemList& children = m_sizer->GetChildren(); + if ( children.GetCount() == 0 ) + return true; + + for ( wxSizerItemList::compatibility_iterator + node = children.GetFirst(); + node; + node = node->GetNext() ) + { + if ( node->GetData()->ShouldAccountFor() ) + return true; + } + return false; + } + else + { + return IsShown(); + } +} + + +#if WXWIN_COMPATIBILITY_2_6 +void wxSizerItem::SetOption( int option ) +{ + SetProportion( option ); +} + +int wxSizerItem::GetOption() const +{ + return GetProportion(); +} +#endif // WXWIN_COMPATIBILITY_2_6 + + +//--------------------------------------------------------------------------- +// wxSizer +//--------------------------------------------------------------------------- + +wxSizer::~wxSizer() +{ + WX_CLEAR_LIST(wxSizerItemList, m_children); +} + +wxSizerItem* wxSizer::Insert( size_t index, wxSizerItem *item ) +{ + m_children.Insert( index, item ); + + if ( item->GetWindow() ) + item->GetWindow()->SetContainingSizer( this ); + + if ( item->GetSizer() ) + item->GetSizer()->SetContainingWindow( m_containingWindow ); + + return item; +} + +void wxSizer::SetContainingWindow(wxWindow *win) +{ + if ( win == m_containingWindow ) + return; + + m_containingWindow = win; + + // set the same window for all nested sizers as well, they also are in the + // same window + for ( wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + node; + node = node->GetNext() ) + { + wxSizerItem *const item = node->GetData(); + wxSizer *const sizer = item->GetSizer(); + + if ( sizer ) + { + sizer->SetContainingWindow(win); + } + } +} + +#if WXWIN_COMPATIBILITY_2_6 +bool wxSizer::Remove( wxWindow *window ) +{ + return Detach( window ); +} +#endif // WXWIN_COMPATIBILITY_2_6 + +bool wxSizer::Remove( wxSizer *sizer ) +{ + wxASSERT_MSG( sizer, _T("Removing NULL sizer") ); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetSizer() == sizer) + { + delete item; + m_children.Erase( node ); + return true; + } + + node = node->GetNext(); + } + + return false; +} + +bool wxSizer::Remove( int index ) +{ + wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(), + false, + _T("Remove index is out of range") ); + + wxSizerItemList::compatibility_iterator node = m_children.Item( index ); + + wxCHECK_MSG( node, false, _T("Failed to find child node") ); + + wxSizerItem *item = node->GetData(); + + if ( item->IsWindow() ) + item->GetWindow()->SetContainingSizer( NULL ); + + delete item; + m_children.Erase( node ); + return true; +} + +bool wxSizer::Detach( wxSizer *sizer ) +{ + wxASSERT_MSG( sizer, _T("Detaching NULL sizer") ); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetSizer() == sizer) + { + item->DetachSizer(); + delete item; + m_children.Erase( node ); + return true; + } + node = node->GetNext(); + } + + return false; +} + +bool wxSizer::Detach( wxWindow *window ) +{ + wxASSERT_MSG( window, _T("Detaching NULL window") ); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetWindow() == window) + { + item->GetWindow()->SetContainingSizer( NULL ); + delete item; + m_children.Erase( node ); + return true; + } + node = node->GetNext(); + } + + return false; +} + +bool wxSizer::Detach( int index ) +{ + wxCHECK_MSG( index >= 0 && (size_t)index < m_children.GetCount(), + false, + _T("Detach index is out of range") ); + + wxSizerItemList::compatibility_iterator node = m_children.Item( index ); + + wxCHECK_MSG( node, false, _T("Failed to find child node") ); + + wxSizerItem *item = node->GetData(); + + if ( item->IsSizer() ) + item->DetachSizer(); + else if ( item->IsWindow() ) + item->GetWindow()->SetContainingSizer( NULL ); + + delete item; + m_children.Erase( node ); + return true; +} + +bool wxSizer::Replace( wxWindow *oldwin, wxWindow *newwin, bool recursive ) +{ + wxASSERT_MSG( oldwin, _T("Replacing NULL window") ); + wxASSERT_MSG( newwin, _T("Replacing with NULL window") ); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetWindow() == oldwin) + { + item->GetWindow()->SetContainingSizer( NULL ); + item->SetWindow(newwin); + newwin->SetContainingSizer( this ); + return true; + } + else if (recursive && item->IsSizer()) + { + if (item->GetSizer()->Replace( oldwin, newwin, true )) + return true; + } + + node = node->GetNext(); + } + + return false; +} + +bool wxSizer::Replace( wxSizer *oldsz, wxSizer *newsz, bool recursive ) +{ + wxASSERT_MSG( oldsz, _T("Replacing NULL sizer") ); + wxASSERT_MSG( newsz, _T("Replacing with NULL sizer") ); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetSizer() == oldsz) + { + wxSizer *old = item->GetSizer(); + item->SetSizer(newsz); + delete old; + return true; + } + else if (recursive && item->IsSizer()) + { + if (item->GetSizer()->Replace( oldsz, newsz, true )) + return true; + } + + node = node->GetNext(); + } + + return false; +} + +bool wxSizer::Replace( size_t old, wxSizerItem *newitem ) +{ + wxCHECK_MSG( old < m_children.GetCount(), false, _T("Replace index is out of range") ); + wxASSERT_MSG( newitem, _T("Replacing with NULL item") ); + + wxSizerItemList::compatibility_iterator node = m_children.Item( old ); + + wxCHECK_MSG( node, false, _T("Failed to find child node") ); + + wxSizerItem *item = node->GetData(); + node->SetData(newitem); + + if (item->IsWindow() && item->GetWindow()) + item->GetWindow()->SetContainingSizer(NULL); + + delete item; + + return true; +} + +void wxSizer::Clear( bool delete_windows ) +{ + // First clear the ContainingSizer pointers + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->IsWindow()) + item->GetWindow()->SetContainingSizer( NULL ); + node = node->GetNext(); + } + + // Destroy the windows if needed + if (delete_windows) + DeleteWindows(); + + // Now empty the list + WX_CLEAR_LIST(wxSizerItemList, m_children); +} + +void wxSizer::DeleteWindows() +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + item->DeleteWindows(); + node = node->GetNext(); + } +} + +wxSize wxSizer::ComputeFittingWindowSize(wxWindow *window) +{ + // take the min size by default and limit it by max size + wxSize size = GetMinWindowSize(window); + wxSize sizeMax = GetMaxWindowSize(window); + + wxTopLevelWindow *tlw = wxDynamicCast(window, wxTopLevelWindow); + if ( tlw ) + { + // hack for small screen devices where TLWs are always full screen + if ( tlw->IsAlwaysMaximized() ) + { + size = tlw->GetSize(); + } + else // normal situation + { + // limit the window to the size of the display it is on + int disp = wxDisplay::GetFromWindow(window); + if ( disp == wxNOT_FOUND ) + { + // or, if we don't know which one it is, of the main one + disp = 0; + } + + sizeMax = wxDisplay(disp).GetClientArea().GetSize(); + } + } + + if ( sizeMax.x != wxDefaultCoord && size.x > sizeMax.x ) + size.x = sizeMax.x; + if ( sizeMax.y != wxDefaultCoord && size.y > sizeMax.y ) + size.y = sizeMax.y; + + return size; +} + +wxSize wxSizer::ComputeFittingClientSize(wxWindow *window) +{ + wxCHECK_MSG( window, wxDefaultSize, _T("window can't be NULL") ); + + return window->WindowToClientSize(ComputeFittingWindowSize(window)); +} + +wxSize wxSizer::Fit( wxWindow *window ) +{ + wxSize size = ComputeFittingWindowSize(window); + window->SetSize(size); + return size; +} + +void wxSizer::FitInside( wxWindow *window ) +{ + wxSize size; + if (window->IsTopLevel()) + size = VirtualFitSize( window ); + else + size = GetMinClientSize( window ); + + window->SetVirtualSize( size ); +} + +void wxSizer::Layout() +{ + // (re)calculates minimums needed for each item and other preparations + // for layout + CalcMin(); + + // Applies the layout and repositions/resizes the items + RecalcSizes(); +} + +void wxSizer::SetSizeHints( wxWindow *window ) +{ + // Preserve the window's max size hints, but set the + // lower bound according to the sizer calculations. + + // This is equivalent to calling Fit(), except that we need to set + // the size hints _in between_ the two steps performed by Fit + // (1. ComputeFittingWindowSize, 2. SetSize). That's because + // otherwise SetSize() could have no effect if there already are + // size hints in effect that forbid requested size. + const wxSize size = ComputeFittingWindowSize(window); + + window->SetSizeHints( size.x, + size.y, + window->GetMaxWidth(), + window->GetMaxHeight() ); + + window->SetSize(size); +} + +void wxSizer::SetVirtualSizeHints( wxWindow *window ) +{ + // Preserve the window's max size hints, but set the + // lower bound according to the sizer calculations. + + FitInside( window ); + wxSize size( window->GetVirtualSize() ); + window->SetVirtualSizeHints( size.x, + size.y, + window->GetMaxWidth(), + window->GetMaxHeight() ); +} + +wxSize wxSizer::GetMaxWindowSize( wxWindow *window ) const +{ + return window->GetMaxSize(); +} + +wxSize wxSizer::GetMinWindowSize( wxWindow *window ) +{ + wxSize minSize( GetMinSize() ); + wxSize size( window->GetSize() ); + wxSize client_size( window->GetClientSize() ); + + return wxSize( minSize.x+size.x-client_size.x, + minSize.y+size.y-client_size.y ); +} + +// TODO on mac we need a function that determines how much free space this +// min size contains, in order to make sure that we have 20 pixels of free +// space around the controls +wxSize wxSizer::GetMaxClientSize( wxWindow *window ) const +{ + wxSize maxSize( window->GetMaxSize() ); + + if ( maxSize != wxDefaultSize ) + { + wxSize size( window->GetSize() ); + wxSize client_size( window->GetClientSize() ); + + return wxSize( maxSize.x + client_size.x - size.x, + maxSize.y + client_size.y - size.y ); + } + else + return wxDefaultSize; +} + +wxSize wxSizer::GetMinClientSize( wxWindow *WXUNUSED(window) ) +{ + return GetMinSize(); // Already returns client size. +} + +wxSize wxSizer::VirtualFitSize( wxWindow *window ) +{ + wxSize size = GetMinClientSize( window ); + wxSize sizeMax = GetMaxClientSize( window ); + + // Limit the size if sizeMax != wxDefaultSize + + if ( size.x > sizeMax.x && sizeMax.x != wxDefaultCoord ) + size.x = sizeMax.x; + if ( size.y > sizeMax.y && sizeMax.y != wxDefaultCoord ) + size.y = sizeMax.y; + + return size; +} + +void wxSizer::SetDimension( int x, int y, int width, int height ) +{ + m_position.x = x; + m_position.y = y; + m_size.x = width; + m_size.y = height; + Layout(); +} + +wxSize wxSizer::GetMinSize() +{ + wxSize ret( CalcMin() ); + if (ret.x < m_minSize.x) ret.x = m_minSize.x; + if (ret.y < m_minSize.y) ret.y = m_minSize.y; + return ret; +} + +void wxSizer::DoSetMinSize( int width, int height ) +{ + m_minSize.x = width; + m_minSize.y = height; +} + +bool wxSizer::DoSetItemMinSize( wxWindow *window, int width, int height ) +{ + wxASSERT_MSG( window, _T("SetMinSize for NULL window") ); + + // Is it our immediate child? + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetWindow() == window) + { + item->SetMinSize( width, height ); + return true; + } + node = node->GetNext(); + } + + // No? Search any subsizers we own then + + node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if ( item->GetSizer() && + item->GetSizer()->DoSetItemMinSize( window, width, height ) ) + { + // A child sizer found the requested windw, exit. + return true; + } + node = node->GetNext(); + } + + return false; +} + +bool wxSizer::DoSetItemMinSize( wxSizer *sizer, int width, int height ) +{ + wxASSERT_MSG( sizer, _T("SetMinSize for NULL sizer") ); + + // Is it our immediate child? + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetSizer() == sizer) + { + item->GetSizer()->DoSetMinSize( width, height ); + return true; + } + node = node->GetNext(); + } + + // No? Search any subsizers we own then + + node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if ( item->GetSizer() && + item->GetSizer()->DoSetItemMinSize( sizer, width, height ) ) + { + // A child found the requested sizer, exit. + return true; + } + node = node->GetNext(); + } + + return false; +} + +bool wxSizer::DoSetItemMinSize( size_t index, int width, int height ) +{ + wxSizerItemList::compatibility_iterator node = m_children.Item( index ); + + wxCHECK_MSG( node, false, _T("Failed to find child node") ); + + wxSizerItem *item = node->GetData(); + + if (item->GetSizer()) + { + // Sizers contains the minimal size in them, if not calculated ... + item->GetSizer()->DoSetMinSize( width, height ); + } + else + { + // ... but the minimal size of spacers and windows is stored via the item + item->SetMinSize( width, height ); + } + + return true; +} + +wxSizerItem* wxSizer::GetItem( wxWindow *window, bool recursive ) +{ + wxASSERT_MSG( window, _T("GetItem for NULL window") ); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetWindow() == window) + { + return item; + } + else if (recursive && item->IsSizer()) + { + wxSizerItem *subitem = item->GetSizer()->GetItem( window, true ); + if (subitem) + return subitem; + } + + node = node->GetNext(); + } + + return NULL; +} + +wxSizerItem* wxSizer::GetItem( wxSizer *sizer, bool recursive ) +{ + wxASSERT_MSG( sizer, _T("GetItem for NULL sizer") ); + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetSizer() == sizer) + { + return item; + } + else if (recursive && item->IsSizer()) + { + wxSizerItem *subitem = item->GetSizer()->GetItem( sizer, true ); + if (subitem) + return subitem; + } + + node = node->GetNext(); + } + + return NULL; +} + +wxSizerItem* wxSizer::GetItem( size_t index ) +{ + wxCHECK_MSG( index < m_children.GetCount(), + NULL, + _T("GetItem index is out of range") ); + + return m_children.Item( index )->GetData(); +} + +bool wxSizer::Show( wxWindow *window, bool show, bool recursive ) +{ + wxSizerItem *item = GetItem( window, recursive ); + + if ( item ) + { + item->Show( show ); + return true; + } + + return false; +} + +bool wxSizer::Show( wxSizer *sizer, bool show, bool recursive ) +{ + wxSizerItem *item = GetItem( sizer, recursive ); + + if ( item ) + { + item->Show( show ); + return true; + } + + return false; +} + +bool wxSizer::Show( size_t index, bool show) +{ + wxSizerItem *item = GetItem( index ); + + if ( item ) + { + item->Show( show ); + return true; + } + + return false; +} + +void wxSizer::ShowItems( bool show ) +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + node->GetData()->Show( show ); + node = node->GetNext(); + } +} + +bool wxSizer::IsShown( wxWindow *window ) const +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetWindow() == window) + { + return item->IsShown(); + } + node = node->GetNext(); + } + + wxFAIL_MSG( _T("IsShown failed to find sizer item") ); + + return false; +} + +bool wxSizer::IsShown( wxSizer *sizer ) const +{ + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->GetSizer() == sizer) + { + return item->IsShown(); + } + node = node->GetNext(); + } + + wxFAIL_MSG( _T("IsShown failed to find sizer item") ); + + return false; +} + +bool wxSizer::IsShown( size_t index ) const +{ + wxCHECK_MSG( index < m_children.GetCount(), + false, + _T("IsShown index is out of range") ); + + return m_children.Item( index )->GetData()->IsShown(); +} + + +//--------------------------------------------------------------------------- +// wxGridSizer +//--------------------------------------------------------------------------- + +wxGridSizer::wxGridSizer( int rows, int cols, int vgap, int hgap ) + : m_rows( ( cols == 0 && rows == 0 ) ? 1 : rows ) + , m_cols( cols ) + , m_vgap( vgap ) + , m_hgap( hgap ) +{ +} + +wxGridSizer::wxGridSizer( int cols, int vgap, int hgap ) + : m_rows( cols == 0 ? 1 : 0 ) + , m_cols( cols ) + , m_vgap( vgap ) + , m_hgap( hgap ) +{ +} + +int wxGridSizer::CalcRowsCols(int& nrows, int& ncols) const +{ + int nitems = m_children.GetCount(); + if ( nitems) + { + if ( m_cols ) + { + ncols = m_cols; + nrows = (nitems + m_cols - 1) / m_cols; + } + else if ( m_rows ) + { + ncols = (nitems + m_rows - 1) / m_rows; + nrows = m_rows; + } + else // 0 columns, 0 rows? + { + wxFAIL_MSG( _T("grid sizer must have either rows or columns fixed") ); + + nrows = ncols = 0; + } + } + + return nitems; +} + +void wxGridSizer::RecalcSizes() +{ + int nitems, nrows, ncols; + if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 ) + return; + + wxSize sz( GetSize() ); + wxPoint pt( GetPosition() ); + + int w = (sz.x - (ncols - 1) * m_hgap) / ncols; + int h = (sz.y - (nrows - 1) * m_vgap) / nrows; + + int x = pt.x; + for (int c = 0; c < ncols; c++) + { + int y = pt.y; + for (int r = 0; r < nrows; r++) + { + int i = r * ncols + c; + if (i < nitems) + { + wxSizerItemList::compatibility_iterator node = m_children.Item( i ); + + wxASSERT_MSG( node, _T("Failed to find SizerItemList node") ); + + SetItemBounds( node->GetData(), x, y, w, h); + } + y = y + h + m_vgap; + } + x = x + w + m_hgap; + } +} + +wxSize wxGridSizer::CalcMin() +{ + int nrows, ncols; + if ( CalcRowsCols(nrows, ncols) == 0 ) + return wxSize(); + + // Find the max width and height for any component + int w = 0; + int h = 0; + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + wxSize sz( item->CalcMin() ); + + w = wxMax( w, sz.x ); + h = wxMax( h, sz.y ); + + node = node->GetNext(); + } + + return wxSize( ncols * w + (ncols-1) * m_hgap, + nrows * h + (nrows-1) * m_vgap ); +} + +void wxGridSizer::SetItemBounds( wxSizerItem *item, int x, int y, int w, int h ) +{ + wxPoint pt( x,y ); + wxSize sz( item->GetMinSizeWithBorder() ); + int flag = item->GetFlag(); + + if ((flag & wxEXPAND) || (flag & wxSHAPED)) + { + sz = wxSize(w, h); + } + else + { + if (flag & wxALIGN_CENTER_HORIZONTAL) + { + pt.x = x + (w - sz.x) / 2; + } + else if (flag & wxALIGN_RIGHT) + { + pt.x = x + (w - sz.x); + } + + if (flag & wxALIGN_CENTER_VERTICAL) + { + pt.y = y + (h - sz.y) / 2; + } + else if (flag & wxALIGN_BOTTOM) + { + pt.y = y + (h - sz.y); + } + } + + item->SetDimension(pt, sz); +} + +//--------------------------------------------------------------------------- +// wxFlexGridSizer +//--------------------------------------------------------------------------- + +wxFlexGridSizer::wxFlexGridSizer( int rows, int cols, int vgap, int hgap ) + : wxGridSizer( rows, cols, vgap, hgap ), + m_flexDirection(wxBOTH), + m_growMode(wxFLEX_GROWMODE_SPECIFIED) +{ +} + +wxFlexGridSizer::wxFlexGridSizer( int cols, int vgap, int hgap ) + : wxGridSizer( cols, vgap, hgap ), + m_flexDirection(wxBOTH), + m_growMode(wxFLEX_GROWMODE_SPECIFIED) +{ +} + +wxFlexGridSizer::~wxFlexGridSizer() +{ +} + +void wxFlexGridSizer::RecalcSizes() +{ + int nitems, nrows, ncols; + if ( (nitems = CalcRowsCols(nrows, ncols)) == 0 ) + return; + + wxPoint pt( GetPosition() ); + wxSize sz( GetSize() ); + + AdjustForGrowables(sz, m_calculatedMinSize, nrows, ncols); + + sz = wxSize( pt.x + sz.x, pt.y + sz.y ); + + int x = pt.x; + for (int c = 0; c < ncols; c++) + { + int y = pt.y; + for (int r = 0; r < nrows; r++) + { + int i = r * ncols + c; + if (i < nitems) + { + wxSizerItemList::compatibility_iterator node = m_children.Item( i ); + + wxASSERT_MSG( node, _T("Failed to find node") ); + + int w = wxMax( 0, wxMin( m_colWidths[c], sz.x - x ) ); + int h = wxMax( 0, wxMin( m_rowHeights[r], sz.y - y ) ); + + SetItemBounds( node->GetData(), x, y, w, h); + } + if (m_rowHeights[r] != -1) + y = y + m_rowHeights[r] + m_vgap; + } + if (m_colWidths[c] != -1) + x = x + m_colWidths[c] + m_hgap; + } +} + +wxSize wxFlexGridSizer::CalcMin() +{ + int nrows, + ncols; + size_t i, s; + + // Number of rows/columns can change as items are added or removed. + if ( !CalcRowsCols(nrows, ncols) ) + return wxSize(); + + m_rowHeights.SetCount(nrows); + m_colWidths.SetCount(ncols); + + // We have to recalcuate the sizes in case the item minimum size has + // changed since the previous layout, or the item has been hidden using + // wxSizer::Show(). If all the items in a row/column are hidden, the final + // dimension of the row/column will be -1, indicating that the column + // itself is hidden. + for( s = m_rowHeights.GetCount(), i = 0; i < s; ++i ) + m_rowHeights[ i ] = -1; + for( s = m_colWidths.GetCount(), i = 0; i < s; ++i ) + m_colWidths[ i ] = -1; + + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + + i = 0; + while (node) + { + wxSizerItem *item = node->GetData(); + if ( item->ShouldAccountFor() ) + { + wxSize sz( item->CalcMin() ); + int row = i / ncols; + int col = i % ncols; + + m_rowHeights[ row ] = wxMax( wxMax( 0, sz.y ), m_rowHeights[ row ] ); + m_colWidths[ col ] = wxMax( wxMax( 0, sz.x ), m_colWidths[ col ] ); + } + + node = node->GetNext(); + i++; + } + + AdjustForFlexDirection(); + + // Sum total minimum size, including gaps between rows/columns. + // -1 is used as a magic number meaning empty column. + int width = 0; + for (int col = 0; col < ncols; col++) + if ( m_colWidths[ col ] != -1 ) + width += m_colWidths[ col ] + m_hgap; + if (width > 0) + width -= m_hgap; + + int height = 0; + for (int row = 0; row < nrows; row++) + if ( m_rowHeights[ row ] != -1 ) + height += m_rowHeights[ row ] + m_vgap; + if (height > 0) + height -= m_vgap; + + m_calculatedMinSize = wxSize( width, height ); + return m_calculatedMinSize; +} + +void wxFlexGridSizer::AdjustForFlexDirection() +{ + // the logic in CalcMin works when we resize flexibly in both directions + // but maybe this is not the case + if ( m_flexDirection != wxBOTH ) + { + // select the array corresponding to the direction in which we do *not* + // resize flexibly + wxArrayInt& array = m_flexDirection == wxVERTICAL ? m_colWidths + : m_rowHeights; + + const size_t count = array.GetCount(); + + // find the largest value in this array + size_t n; + int largest = 0; + + for ( n = 0; n < count; ++n ) + { + if ( array[n] > largest ) + largest = array[n]; + } + + // and now fill it with the largest value + for ( n = 0; n < count; ++n ) + { + // don't touch hidden rows + if ( array[n] != -1 ) + array[n] = largest; + } + } +} + + +void wxFlexGridSizer::AdjustForGrowables(const wxSize& sz, const wxSize& minsz, + int nrows, int ncols) +{ + // what to do with the rows? by default, resize them proportionally + if ( sz.y > minsz.y && ( (m_flexDirection & wxVERTICAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) ) + { + int sum_proportions = 0; + int growable_space = 0; + int num = 0; + size_t idx; + for (idx = 0; idx < m_growableRows.GetCount(); idx++) + { + // Since the number of rows/columns can change as items are + // inserted/deleted, we need to verify at runtime that the + // requested growable rows/columns are still valid. + if (m_growableRows[idx] >= nrows) + continue; + + // If all items in a row/column are hidden, that row/column will + // have a dimension of -1. This causes the row/column to be + // hidden completely. + if (m_rowHeights[ m_growableRows[idx] ] == -1) + continue; + sum_proportions += m_growableRowsProportions[idx]; + growable_space += m_rowHeights[ m_growableRows[idx] ]; + num++; + } + + if (num > 0) + { + for (idx = 0; idx < m_growableRows.GetCount(); idx++) + { + if (m_growableRows[idx] >= nrows ) + continue; + if (m_rowHeights[ m_growableRows[idx] ] != -1) + { + int delta = (sz.y - minsz.y); + if (sum_proportions == 0) + delta = (delta/num) + m_rowHeights[ m_growableRows[idx] ]; + else + delta = ((delta+growable_space)*m_growableRowsProportions[idx]) / sum_proportions; + m_rowHeights[ m_growableRows[idx] ] = delta; + } + } + } + } + else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.y > minsz.y) ) + { + // rounding problem? + for ( int row = 0; row < nrows; ++row ) + m_rowHeights[ row ] = sz.y / nrows; + } + + // the same logic as above but for the columns + if ( sz.x > minsz.x && ( (m_flexDirection & wxHORIZONTAL) || (m_growMode == wxFLEX_GROWMODE_SPECIFIED) ) ) + { + int sum_proportions = 0; + int growable_space = 0; + int num = 0; + size_t idx; + for (idx = 0; idx < m_growableCols.GetCount(); idx++) + { + // Since the number of rows/columns can change as items are + // inserted/deleted, we need to verify at runtime that the + // requested growable rows/columns are still valid. + if (m_growableCols[idx] >= ncols) + continue; + + // If all items in a row/column are hidden, that row/column will + // have a dimension of -1. This causes the column to be hidden + // completely. + if (m_colWidths[ m_growableCols[idx] ] == -1) + continue; + sum_proportions += m_growableColsProportions[idx]; + growable_space += m_colWidths[ m_growableCols[idx] ]; + num++; + } + + if (num > 0) + { + for (idx = 0; idx < m_growableCols.GetCount(); idx++) + { + if (m_growableCols[idx] >= ncols ) + continue; + if (m_colWidths[ m_growableCols[idx] ] != -1) + { + int delta = (sz.x - minsz.x); + if (sum_proportions == 0) + delta = (delta/num) + m_colWidths[ m_growableCols[idx] ]; + else + delta = ((delta+growable_space)*m_growableColsProportions[idx])/sum_proportions; + m_colWidths[ m_growableCols[idx] ] = delta; + } + } + } + } + else if ( (m_growMode == wxFLEX_GROWMODE_ALL) && (sz.x > minsz.x) ) + { + for ( int col=0; col < ncols; ++col ) + m_colWidths[ col ] = sz.x / ncols; + } +} + + +void wxFlexGridSizer::AddGrowableRow( size_t idx, int proportion ) +{ + m_growableRows.Add( idx ); + m_growableRowsProportions.Add( proportion ); +} + +void wxFlexGridSizer::AddGrowableCol( size_t idx, int proportion ) +{ + m_growableCols.Add( idx ); + m_growableColsProportions.Add( proportion ); +} + +// helper function for RemoveGrowableCol/Row() +static void +DoRemoveFromArrays(size_t idx, wxArrayInt& items, wxArrayInt& proportions) +{ + const size_t count = items.size(); + for ( size_t n = 0; n < count; n++ ) + { + if ( (size_t)items[n] == idx ) + { + items.RemoveAt(n); + proportions.RemoveAt(n); + return; + } + } + + wxFAIL_MSG( _T("column/row is already not growable") ); +} + +void wxFlexGridSizer::RemoveGrowableCol( size_t idx ) +{ + DoRemoveFromArrays(idx, m_growableCols, m_growableColsProportions); +} + +void wxFlexGridSizer::RemoveGrowableRow( size_t idx ) +{ + DoRemoveFromArrays(idx, m_growableRows, m_growableRowsProportions); +} + +//--------------------------------------------------------------------------- +// wxBoxSizer +//--------------------------------------------------------------------------- + +wxBoxSizer::wxBoxSizer( int orient ) + : m_orient( orient ) +{ +} + +void wxBoxSizer::RecalcSizes() +{ + if (m_children.GetCount() == 0) + return; + + int delta = 0; + if (m_stretchable) + { + if (m_orient == wxHORIZONTAL) + delta = m_size.x - m_fixedWidth; + else + delta = m_size.y - m_fixedHeight; + } + + wxPoint pt( m_position ); + + int stretchable = m_stretchable; + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->ShouldAccountFor()) + { + wxSize size( item->GetMinSizeWithBorder() ); + + if (m_orient == wxVERTICAL) + { + wxCoord height = size.y; + if (item->GetProportion()) + { + // Because of at least one visible item has non-zero + // proportion then m_stretchable is not zero + height = (delta * item->GetProportion()) / stretchable; + delta -= height; + stretchable -= item->GetProportion(); + } + + wxPoint child_pos( pt ); + wxSize child_size( size.x, height ); + + if (item->GetFlag() & (wxEXPAND | wxSHAPED)) + child_size.x = m_size.x; + else if (item->GetFlag() & wxALIGN_RIGHT) + child_pos.x += m_size.x - size.x; + else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL)) + // XXX wxCENTER is added for backward compatibility; + // wxALIGN_CENTER should be used in new code + child_pos.x += (m_size.x - size.x) / 2; + + item->SetDimension( child_pos, child_size ); + + pt.y += height; + } + else + { + wxCoord width = size.x; + if (item->GetProportion()) + { + // Because of at least one visible item has non-zero + // proportion then m_stretchable is not zero + width = (delta * item->GetProportion()) / stretchable; + delta -= width; + stretchable -= item->GetProportion(); + } + + wxPoint child_pos( pt ); + wxSize child_size( width, size.y ); + + if (item->GetFlag() & (wxEXPAND | wxSHAPED)) + child_size.y = m_size.y; + else if (item->GetFlag() & wxALIGN_BOTTOM) + child_pos.y += m_size.y - size.y; + else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL)) + // XXX wxCENTER is added for backward compatibility; + // wxALIGN_CENTER should be used in new code + child_pos.y += (m_size.y - size.y) / 2; + + if ( m_containingWindow ) + { + child_pos.x = m_containingWindow->AdjustForLayoutDirection + ( + child_pos.x, + width, + m_size.x + ); + } + + item->SetDimension( child_pos, child_size ); + + pt.x += width; + } + } + + node = node->GetNext(); + } +} + +wxSize wxBoxSizer::CalcMin() +{ + if (m_children.GetCount() == 0) + return wxSize(); + + m_stretchable = 0; + m_minWidth = 0; + m_minHeight = 0; + m_fixedWidth = 0; + m_fixedHeight = 0; + + // precalc item minsizes and count proportions + wxSizerItemList::compatibility_iterator node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if ( item->ShouldAccountFor() ) + { + item->CalcMin(); // result is stored in the item + + m_stretchable += item->GetProportion(); + } + + node = node->GetNext(); + } + + // Total minimum size (width or height) of sizer + int maxMinSize = 0; + + node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->ShouldAccountFor() && item->GetProportion() != 0) + { + int stretch = item->GetProportion(); + wxSize size( item->GetMinSizeWithBorder() ); + int minSize; + + // Integer division rounded up is (a + b - 1) / b + // Round up needed in order to guarantee that all + // all items will have size not less then their min size + if (m_orient == wxHORIZONTAL) + minSize = ( size.x*m_stretchable + stretch - 1)/stretch; + else + minSize = ( size.y*m_stretchable + stretch - 1)/stretch; + + if (minSize > maxMinSize) + maxMinSize = minSize; + } + node = node->GetNext(); + } + + // Calculate overall minimum size + node = m_children.GetFirst(); + while (node) + { + wxSizerItem *item = node->GetData(); + + if (item->ShouldAccountFor()) + { + wxSize size( item->GetMinSizeWithBorder() ); + if (item->GetProportion() != 0) + { + if (m_orient == wxHORIZONTAL) + size.x = (maxMinSize*item->GetProportion())/m_stretchable; + else + size.y = (maxMinSize*item->GetProportion())/m_stretchable; + } + else + { + if (m_orient == wxVERTICAL) + { + m_fixedHeight += size.y; + m_fixedWidth = wxMax( m_fixedWidth, size.x ); + } + else + { + m_fixedWidth += size.x; + m_fixedHeight = wxMax( m_fixedHeight, size.y ); + } + } + + if (m_orient == wxHORIZONTAL) + { + m_minWidth += size.x; + m_minHeight = wxMax( m_minHeight, size.y ); + } + else + { + m_minHeight += size.y; + m_minWidth = wxMax( m_minWidth, size.x ); + } + } + node = node->GetNext(); + } + + return wxSize( m_minWidth, m_minHeight ); +} + +//--------------------------------------------------------------------------- +// wxStaticBoxSizer +//--------------------------------------------------------------------------- + +#if wxUSE_STATBOX + +wxStaticBoxSizer::wxStaticBoxSizer( wxStaticBox *box, int orient ) + : wxBoxSizer( orient ), + m_staticBox( box ) +{ + wxASSERT_MSG( box, wxT("wxStaticBoxSizer needs a static box") ); + + // do this so that our Detach() is called if the static box is destroyed + // before we are + m_staticBox->SetContainingSizer(this); +} + +wxStaticBoxSizer::wxStaticBoxSizer(int orient, wxWindow *win, const wxString& s) + : wxBoxSizer(orient), + m_staticBox(new wxStaticBox(win, wxID_ANY, s)) +{ + // same as above + m_staticBox->SetContainingSizer(this); +} + +wxStaticBoxSizer::~wxStaticBoxSizer() +{ + delete m_staticBox; +} + +static void GetStaticBoxBorders( wxStaticBox *box, + int *borderTop, + int *borderOther) +{ + // this has to be done platform by platform as there is no way to + // guess the thickness of a wxStaticBox border + box->GetBordersForSizer(borderTop, borderOther); +} + +void wxStaticBoxSizer::RecalcSizes() +{ + int top_border, other_border; + GetStaticBoxBorders(m_staticBox, &top_border, &other_border); + + m_staticBox->SetSize( m_position.x, m_position.y, m_size.x, m_size.y ); + + wxPoint old_pos( m_position ); + m_position.x += other_border; + m_position.y += top_border; + wxSize old_size( m_size ); + m_size.x -= 2*other_border; + m_size.y -= top_border + other_border; + + wxBoxSizer::RecalcSizes(); + + m_position = old_pos; + m_size = old_size; +} + +wxSize wxStaticBoxSizer::CalcMin() +{ + int top_border, other_border; + GetStaticBoxBorders(m_staticBox, &top_border, &other_border); + + wxSize ret( wxBoxSizer::CalcMin() ); + ret.x += 2*other_border; + ret.y += other_border + top_border; + + return ret; +} + +void wxStaticBoxSizer::ShowItems( bool show ) +{ + m_staticBox->Show( show ); + wxBoxSizer::ShowItems( show ); +} + +bool wxStaticBoxSizer::Detach( wxWindow *window ) +{ + // avoid deleting m_staticBox in our dtor if it's being detached from the + // sizer (which can happen because it's being already destroyed for + // example) + if ( window == m_staticBox ) + { + m_staticBox = NULL; + return true; + } + + return wxSizer::Detach( window ); +} + +#endif // wxUSE_STATBOX + +#if wxUSE_BUTTON + +wxStdDialogButtonSizer::wxStdDialogButtonSizer() + : wxBoxSizer(wxHORIZONTAL) +{ + // Vertical buttons with lots of space on either side + // looks rubbish on WinCE, so let's not do this for now. + // If we are going to use vertical buttons, we should + // put the sizer to the right of other controls in the dialog, + // and that's beyond the scope of this sizer. +#ifndef __WXWINCE__ + bool is_pda = (wxSystemSettings::GetScreenType() <= wxSYS_SCREEN_PDA); + // If we have a PDA screen, put yes/no button over + // all other buttons, otherwise on the left side. + if (is_pda) + m_orient = wxVERTICAL; +#endif + + m_buttonAffirmative = NULL; + m_buttonApply = NULL; + m_buttonNegative = NULL; + m_buttonCancel = NULL; + m_buttonHelp = NULL; +} + +void wxStdDialogButtonSizer::AddButton(wxButton *mybutton) +{ + switch (mybutton->GetId()) + { + case wxID_OK: + case wxID_YES: + case wxID_SAVE: + m_buttonAffirmative = mybutton; + break; + case wxID_APPLY: + m_buttonApply = mybutton; + break; + case wxID_NO: + m_buttonNegative = mybutton; + break; + case wxID_CANCEL: + m_buttonCancel = mybutton; + break; + case wxID_HELP: + case wxID_CONTEXT_HELP: + m_buttonHelp = mybutton; + break; + default: + break; + } +} + +void wxStdDialogButtonSizer::SetAffirmativeButton( wxButton *button ) +{ + m_buttonAffirmative = button; +} + +void wxStdDialogButtonSizer::SetNegativeButton( wxButton *button ) +{ + m_buttonNegative = button; +} + +void wxStdDialogButtonSizer::SetCancelButton( wxButton *button ) +{ + m_buttonCancel = button; +} + +void wxStdDialogButtonSizer::Realize() +{ +#ifdef __WXMAC__ + Add(0, 0, 0, wxLEFT, 6); + if (m_buttonHelp) + Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6); + + if (m_buttonNegative){ + // HIG POLICE BULLETIN - destructive buttons need extra padding + // 24 pixels on either side + Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 12); + } + + // extra whitespace between help/negative and cancel/ok buttons + Add(0, 0, 1, wxEXPAND, 0); + + if (m_buttonCancel){ + Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6); + // Cancel or help should be default + // m_buttonCancel->SetDefaultButton(); + } + + // Ugh, Mac doesn't really have apply dialogs, so I'll just + // figure the best place is between Cancel and OK + if (m_buttonApply) + Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 6); + + if (m_buttonAffirmative){ + Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6); + + if (m_buttonAffirmative->GetId() == wxID_SAVE){ + // these buttons have set labels under Mac so we should use them + m_buttonAffirmative->SetLabel(_("Save")); + if (m_buttonNegative) + m_buttonNegative->SetLabel(_("Don't Save")); + } + } + + // Extra space around and at the right + Add(12, 24); +#elif defined(__WXGTK20__) + Add(0, 0, 0, wxLEFT, 9); + if (m_buttonHelp) + Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); + + // extra whitespace between help and cancel/ok buttons + Add(0, 0, 1, wxEXPAND, 0); + + if (m_buttonNegative){ + Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); + } + + if (m_buttonCancel){ + Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); + // Cancel or help should be default + // m_buttonCancel->SetDefaultButton(); + } + + if (m_buttonApply) + Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, 3); + + if (m_buttonAffirmative) + Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT, 6); +#elif defined(__WXMSW__) + // Windows + + // right-justify buttons + Add(0, 0, 1, wxEXPAND, 0); + + if (m_buttonAffirmative){ + Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(2, 0)).x); + } + + if (m_buttonNegative){ + Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(2, 0)).x); + } + + if (m_buttonCancel){ + Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(2, 0)).x); + } + if (m_buttonApply) + Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(2, 0)).x); + + if (m_buttonHelp) + Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(2, 0)).x); +#else + // GTK+1 and any other platform + + // Add(0, 0, 0, wxLEFT, 5); // Not sure what this was for but it unbalances the dialog + if (m_buttonHelp) + Add((wxWindow*)m_buttonHelp, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonHelp->ConvertDialogToPixels(wxSize(4, 0)).x); + + // extra whitespace between help and cancel/ok buttons + Add(0, 0, 1, wxEXPAND, 0); + + if (m_buttonApply) + Add((wxWindow*)m_buttonApply, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonApply->ConvertDialogToPixels(wxSize(4, 0)).x); + + if (m_buttonAffirmative){ + Add((wxWindow*)m_buttonAffirmative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonAffirmative->ConvertDialogToPixels(wxSize(4, 0)).x); + } + + if (m_buttonNegative){ + Add((wxWindow*)m_buttonNegative, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonNegative->ConvertDialogToPixels(wxSize(4, 0)).x); + } + + if (m_buttonCancel){ + Add((wxWindow*)m_buttonCancel, 0, wxALIGN_CENTRE | wxLEFT | wxRIGHT, m_buttonCancel->ConvertDialogToPixels(wxSize(4, 0)).x); + // Cancel or help should be default + // m_buttonCancel->SetDefaultButton(); + } + +#endif +} + +#endif // wxUSE_BUTTON + +#if WXWIN_COMPATIBILITY_2_4 + +// ---------------------------------------------------------------------------- +// wxNotebookSizer +// ---------------------------------------------------------------------------- + +#if wxUSE_BOOKCTRL +IMPLEMENT_CLASS(wxBookCtrlSizer, wxSizer) +#if wxUSE_NOTEBOOK +IMPLEMENT_CLASS(wxNotebookSizer, wxBookCtrlSizer) +#endif // wxUSE_NOTEBOOK +#endif // wxUSE_BOOKCTRL + +#if wxUSE_BOOKCTRL + +#if WXWIN_COMPATIBILITY_2_6 + +wxBookCtrlSizer::wxBookCtrlSizer(wxBookCtrlBase *bookctrl) + : m_bookctrl(bookctrl) +{ + wxASSERT_MSG( bookctrl, wxT("wxBookCtrlSizer needs a control") ); +} + +#endif // WXWIN_COMPATIBILITY_2_6 + +void wxBookCtrlSizer::RecalcSizes() +{ + m_bookctrl->SetSize( m_position.x, m_position.y, m_size.x, m_size.y ); +} + +wxSize wxBookCtrlSizer::CalcMin() +{ + wxSize sizeBorder = m_bookctrl->CalcSizeFromPage(wxSize(0,0)); + + sizeBorder.x += 5; + sizeBorder.y += 5; + + if ( m_bookctrl->GetPageCount() == 0 ) + { + return wxSize(sizeBorder.x + 10, sizeBorder.y + 10); + } + + int maxX = 0; + int maxY = 0; + + wxWindowList::compatibility_iterator + node = m_bookctrl->GetChildren().GetFirst(); + while (node) + { + wxWindow *item = node->GetData(); + wxSizer *itemsizer = item->GetSizer(); + + if (itemsizer) + { + wxSize subsize( itemsizer->CalcMin() ); + + if (subsize.x > maxX) + maxX = subsize.x; + if (subsize.y > maxY) + maxY = subsize.y; + } + + node = node->GetNext(); + } + + return wxSize( maxX, maxY ) + sizeBorder; +} + +#if wxUSE_NOTEBOOK + +#if WXWIN_COMPATIBILITY_2_6 + +wxNotebookSizer::wxNotebookSizer(wxNotebook *nb) +{ + wxASSERT_MSG( nb, wxT("wxNotebookSizer needs a control") ); + m_bookctrl = nb; +} + +#endif // WXWIN_COMPATIBILITY_2_6 + +#endif // wxUSE_NOTEBOOOK +#endif // wxUSE_BOOKCTRL + +#endif // WXWIN_COMPATIBILITY_2_4 diff --git a/Source/3rd Party/wx/src/common/srchcmn.cpp b/Source/3rd Party/wx/src/common/srchcmn.cpp index 3c05e828c..093577f5c 100644 --- a/Source/3rd Party/wx/src/common/srchcmn.cpp +++ b/Source/3rd Party/wx/src/common/srchcmn.cpp @@ -1,42 +1,42 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/srchcmn.cpp -// Purpose: common (to all ports) bits of wxSearchCtrl -// Author: Robin Dunn -// Modified by: -// Created: 19-Dec-2006 -// RCS-ID: $Id: srchcmn.cpp 43939 2006-12-11 20:32:16Z KO $ -// Copyright: (c) 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_SEARCHCTRL - -#include "wx/srchctrl.h" - -#ifndef WX_PRECOMP -#endif - -// ---------------------------------------------------------------------------- - -const wxChar wxSearchCtrlNameStr[] = wxT("searchCtrl"); - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SEARCHCTRL_CANCEL_BTN) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_SEARCHCTRL_SEARCH_BTN) - - -#endif // wxUSE_SEARCHCTRL +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/srchcmn.cpp +// Purpose: common (to all ports) bits of wxSearchCtrl +// Author: Robin Dunn +// Modified by: +// Created: 19-Dec-2006 +// RCS-ID: $Id: srchcmn.cpp 43939 2006-12-11 20:32:16Z KO $ +// Copyright: (c) 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_SEARCHCTRL + +#include "wx/srchctrl.h" + +#ifndef WX_PRECOMP +#endif + +// ---------------------------------------------------------------------------- + +const wxChar wxSearchCtrlNameStr[] = wxT("searchCtrl"); + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SEARCHCTRL_CANCEL_BTN) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_SEARCHCTRL_SEARCH_BTN) + + +#endif // wxUSE_SEARCHCTRL diff --git a/Source/3rd Party/wx/src/common/sstream.cpp b/Source/3rd Party/wx/src/common/sstream.cpp index 80129c50f..3d792b174 100644 --- a/Source/3rd Party/wx/src/common/sstream.cpp +++ b/Source/3rd Party/wx/src/common/sstream.cpp @@ -1,235 +1,235 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: common/sstream.cpp -// Purpose: string-based streams implementation -// Author: Vadim Zeitlin -// Modified by: Ryan Norton (UTF8 UNICODE) -// Created: 2004-09-19 -// RCS-ID: $Id: sstream.cpp 45772 2007-05-03 02:19:16Z VZ $ -// Copyright: (c) 2004 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#include "wx/sstream.h" - -#if wxUSE_UNICODE - #include "wx/hashmap.h" -#endif - -// ============================================================================ -// wxStringInputStream implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// construction/destruction -// ---------------------------------------------------------------------------- - -// TODO: Do we want to include the null char in the stream? If so then -// just add +1 to m_len in the ctor -wxStringInputStream::wxStringInputStream(const wxString& s) -#if wxUSE_UNICODE - : m_str(s), m_buf(wxMBConvUTF8().cWX2MB(s).release()), m_len(strlen(m_buf)) -#else - : m_str(s), m_buf((char*)s.c_str()), m_len(s.length()) -#endif -{ -#if wxUSE_UNICODE - wxASSERT_MSG(m_buf != NULL, _T("Could not convert string to UTF8!")); -#endif - m_pos = 0; -} - -wxStringInputStream::~wxStringInputStream() -{ -#if wxUSE_UNICODE - // Note: wx[W]CharBuffer uses malloc()/free() - free(m_buf); -#endif -} - -// ---------------------------------------------------------------------------- -// getlength -// ---------------------------------------------------------------------------- - -wxFileOffset wxStringInputStream::GetLength() const -{ - return m_len; -} - -// ---------------------------------------------------------------------------- -// seek/tell -// ---------------------------------------------------------------------------- - -wxFileOffset wxStringInputStream::OnSysSeek(wxFileOffset ofs, wxSeekMode mode) -{ - switch ( mode ) - { - case wxFromStart: - // nothing to do, ofs already ok - break; - - case wxFromEnd: - ofs += m_len; - break; - - case wxFromCurrent: - ofs += m_pos; - break; - - default: - wxFAIL_MSG( _T("invalid seek mode") ); - return wxInvalidOffset; - } - - if ( ofs < 0 || ofs > wx_static_cast(wxFileOffset, m_len) ) - return wxInvalidOffset; - - // FIXME: this can't be right - m_pos = wx_truncate_cast(size_t, ofs); - - return ofs; -} - -wxFileOffset wxStringInputStream::OnSysTell() const -{ - return wx_static_cast(wxFileOffset, m_pos); -} - -// ---------------------------------------------------------------------------- -// actual IO -// ---------------------------------------------------------------------------- - -size_t wxStringInputStream::OnSysRead(void *buffer, size_t size) -{ - const size_t sizeMax = m_len - m_pos; - - if ( size >= sizeMax ) - { - if ( sizeMax == 0 ) - { - m_lasterror = wxSTREAM_EOF; - return 0; - } - - size = sizeMax; - } - - memcpy(buffer, m_buf + m_pos, size); - m_pos += size; - - return size; -} - -// ============================================================================ -// wxStringOutputStream implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// seek/tell -// ---------------------------------------------------------------------------- - -wxFileOffset wxStringOutputStream::OnSysTell() const -{ - return wx_static_cast(wxFileOffset, m_pos); -} - -// ---------------------------------------------------------------------------- -// actual IO -// ---------------------------------------------------------------------------- - -#if wxUSE_UNICODE - -// we can't add a member to wxStringOutputStream in 2.8 branch without breaking -// backwards binary compatibility, so we emulate it by using a hash indexed by -// wxStringOutputStream pointers - -// can't use wxCharBuffer as it has incorrect copying semantics and doesn't -// store the length which we need here -WX_DECLARE_VOIDPTR_HASH_MAP(wxMemoryBuffer, wxStringStreamUnconvBuffers); - -static wxStringStreamUnconvBuffers gs_unconverted; - -wxStringOutputStream::~wxStringOutputStream() -{ - // TODO: check that nothing remains (i.e. the unconverted buffer is empty)? - gs_unconverted.erase(this); -} - -#endif // wxUSE_UNICODE - -size_t wxStringOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - const char *p = wx_static_cast(const char *, buffer); - -#if wxUSE_UNICODE - // the part of the string we have here may be incomplete, i.e. it can stop - // in the middle of an UTF-8 character and so converting it would fail; if - // this is the case, accumulate the part which we failed to convert until - // we get the rest (and also take into account the part which we might have - // left unconverted before) - const char *src; - size_t srcLen; - wxMemoryBuffer& unconv = gs_unconverted[this]; - if ( unconv.GetDataLen() ) - { - // append the new data to the data remaining since the last time - unconv.AppendData(p, size); - src = unconv; - srcLen = unconv.GetDataLen(); - } - else // no unconverted data left, avoid extra copy - { - src = p; - srcLen = size; - } - - wxWCharBuffer wbuf(m_conv.cMB2WC(src, srcLen, NULL /* out len */)); - if ( wbuf ) - { - // conversion succeeded, clear the unconverted buffer - unconv = wxMemoryBuffer(0); - - *m_str += wbuf; - } - else // conversion failed - { - // remember unconverted data if there had been none before (otherwise - // we've already got it in the buffer) - if ( src == p ) - unconv.AppendData(src, srcLen); - - // pretend that we wrote the data anyhow, otherwise the caller would - // believe there was an error and this might not be the case, but do - // not update m_pos as m_str hasn't changed - return size; - } -#else // !wxUSE_UNICODE - // append directly, no conversion necessary - m_str->Append(wxString(p, size)); -#endif // wxUSE_UNICODE/!wxUSE_UNICODE - - // update position - m_pos += size; - - // return number of bytes actually written - return size; -} - -#endif // wxUSE_STREAMS - +/////////////////////////////////////////////////////////////////////////////// +// Name: common/sstream.cpp +// Purpose: string-based streams implementation +// Author: Vadim Zeitlin +// Modified by: Ryan Norton (UTF8 UNICODE) +// Created: 2004-09-19 +// RCS-ID: $Id: sstream.cpp 45772 2007-05-03 02:19:16Z VZ $ +// Copyright: (c) 2004 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#include "wx/sstream.h" + +#if wxUSE_UNICODE + #include "wx/hashmap.h" +#endif + +// ============================================================================ +// wxStringInputStream implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// construction/destruction +// ---------------------------------------------------------------------------- + +// TODO: Do we want to include the null char in the stream? If so then +// just add +1 to m_len in the ctor +wxStringInputStream::wxStringInputStream(const wxString& s) +#if wxUSE_UNICODE + : m_str(s), m_buf(wxMBConvUTF8().cWX2MB(s).release()), m_len(strlen(m_buf)) +#else + : m_str(s), m_buf((char*)s.c_str()), m_len(s.length()) +#endif +{ +#if wxUSE_UNICODE + wxASSERT_MSG(m_buf != NULL, _T("Could not convert string to UTF8!")); +#endif + m_pos = 0; +} + +wxStringInputStream::~wxStringInputStream() +{ +#if wxUSE_UNICODE + // Note: wx[W]CharBuffer uses malloc()/free() + free(m_buf); +#endif +} + +// ---------------------------------------------------------------------------- +// getlength +// ---------------------------------------------------------------------------- + +wxFileOffset wxStringInputStream::GetLength() const +{ + return m_len; +} + +// ---------------------------------------------------------------------------- +// seek/tell +// ---------------------------------------------------------------------------- + +wxFileOffset wxStringInputStream::OnSysSeek(wxFileOffset ofs, wxSeekMode mode) +{ + switch ( mode ) + { + case wxFromStart: + // nothing to do, ofs already ok + break; + + case wxFromEnd: + ofs += m_len; + break; + + case wxFromCurrent: + ofs += m_pos; + break; + + default: + wxFAIL_MSG( _T("invalid seek mode") ); + return wxInvalidOffset; + } + + if ( ofs < 0 || ofs > wx_static_cast(wxFileOffset, m_len) ) + return wxInvalidOffset; + + // FIXME: this can't be right + m_pos = wx_truncate_cast(size_t, ofs); + + return ofs; +} + +wxFileOffset wxStringInputStream::OnSysTell() const +{ + return wx_static_cast(wxFileOffset, m_pos); +} + +// ---------------------------------------------------------------------------- +// actual IO +// ---------------------------------------------------------------------------- + +size_t wxStringInputStream::OnSysRead(void *buffer, size_t size) +{ + const size_t sizeMax = m_len - m_pos; + + if ( size >= sizeMax ) + { + if ( sizeMax == 0 ) + { + m_lasterror = wxSTREAM_EOF; + return 0; + } + + size = sizeMax; + } + + memcpy(buffer, m_buf + m_pos, size); + m_pos += size; + + return size; +} + +// ============================================================================ +// wxStringOutputStream implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// seek/tell +// ---------------------------------------------------------------------------- + +wxFileOffset wxStringOutputStream::OnSysTell() const +{ + return wx_static_cast(wxFileOffset, m_pos); +} + +// ---------------------------------------------------------------------------- +// actual IO +// ---------------------------------------------------------------------------- + +#if wxUSE_UNICODE + +// we can't add a member to wxStringOutputStream in 2.8 branch without breaking +// backwards binary compatibility, so we emulate it by using a hash indexed by +// wxStringOutputStream pointers + +// can't use wxCharBuffer as it has incorrect copying semantics and doesn't +// store the length which we need here +WX_DECLARE_VOIDPTR_HASH_MAP(wxMemoryBuffer, wxStringStreamUnconvBuffers); + +static wxStringStreamUnconvBuffers gs_unconverted; + +wxStringOutputStream::~wxStringOutputStream() +{ + // TODO: check that nothing remains (i.e. the unconverted buffer is empty)? + gs_unconverted.erase(this); +} + +#endif // wxUSE_UNICODE + +size_t wxStringOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + const char *p = wx_static_cast(const char *, buffer); + +#if wxUSE_UNICODE + // the part of the string we have here may be incomplete, i.e. it can stop + // in the middle of an UTF-8 character and so converting it would fail; if + // this is the case, accumulate the part which we failed to convert until + // we get the rest (and also take into account the part which we might have + // left unconverted before) + const char *src; + size_t srcLen; + wxMemoryBuffer& unconv = gs_unconverted[this]; + if ( unconv.GetDataLen() ) + { + // append the new data to the data remaining since the last time + unconv.AppendData(p, size); + src = unconv; + srcLen = unconv.GetDataLen(); + } + else // no unconverted data left, avoid extra copy + { + src = p; + srcLen = size; + } + + wxWCharBuffer wbuf(m_conv.cMB2WC(src, srcLen, NULL /* out len */)); + if ( wbuf ) + { + // conversion succeeded, clear the unconverted buffer + unconv = wxMemoryBuffer(0); + + *m_str += wbuf; + } + else // conversion failed + { + // remember unconverted data if there had been none before (otherwise + // we've already got it in the buffer) + if ( src == p ) + unconv.AppendData(src, srcLen); + + // pretend that we wrote the data anyhow, otherwise the caller would + // believe there was an error and this might not be the case, but do + // not update m_pos as m_str hasn't changed + return size; + } +#else // !wxUSE_UNICODE + // append directly, no conversion necessary + m_str->Append(wxString(p, size)); +#endif // wxUSE_UNICODE/!wxUSE_UNICODE + + // update position + m_pos += size; + + // return number of bytes actually written + return size; +} + +#endif // wxUSE_STREAMS + diff --git a/Source/3rd Party/wx/src/common/statbar.cpp b/Source/3rd Party/wx/src/common/statbar.cpp index 69a32456c..82de44f33 100644 --- a/Source/3rd Party/wx/src/common/statbar.cpp +++ b/Source/3rd Party/wx/src/common/statbar.cpp @@ -1,368 +1,368 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/statbar.cpp -// Purpose: wxStatusBarBase implementation -// Author: Vadim Zeitlin -// Modified by: -// Created: 14.10.01 -// RCS-ID: $Id: statbar.cpp 42171 2006-10-20 14:54:14Z VS $ -// Copyright: (c) 2001 Vadim Zeitlin -// License: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STATUSBAR - -#include "wx/statusbr.h" - -#ifndef WX_PRECOMP - #include "wx/frame.h" -#endif //WX_PRECOMP - -#include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxListString) - -const wxChar wxStatusBarNameStr[] = wxT("statusBar"); - -// ============================================================================ -// wxStatusBarBase implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxStatusBar, wxWindow) - -// ---------------------------------------------------------------------------- -// ctor/dtor -// ---------------------------------------------------------------------------- - -wxStatusBarBase::wxStatusBarBase() -{ - m_nFields = 0; - - InitWidths(); - InitStacks(); - InitStyles(); -} - -wxStatusBarBase::~wxStatusBarBase() -{ - FreeWidths(); - FreeStacks(); - FreeStyles(); - - // notify the frame that it doesn't have a status bar any longer to avoid - // dangling pointers - wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); - if ( frame && frame->GetStatusBar() == this ) - { - frame->SetStatusBar(NULL); - } -} - -// ---------------------------------------------------------------------------- -// widths array handling -// ---------------------------------------------------------------------------- - -void wxStatusBarBase::InitWidths() -{ - m_statusWidths = NULL; -} - -void wxStatusBarBase::FreeWidths() -{ - delete [] m_statusWidths; -} - -// ---------------------------------------------------------------------------- -// styles array handling -// ---------------------------------------------------------------------------- - -void wxStatusBarBase::InitStyles() -{ - m_statusStyles = NULL; -} - -void wxStatusBarBase::FreeStyles() -{ - delete [] m_statusStyles; -} - -// ---------------------------------------------------------------------------- -// field widths -// ---------------------------------------------------------------------------- - -void wxStatusBarBase::SetFieldsCount(int number, const int *widths) -{ - wxCHECK_RET( number > 0, _T("invalid field number in SetFieldsCount") ); - - bool refresh = false; - - if ( number != m_nFields ) - { - // copy stacks if present - if(m_statusTextStacks) - { - wxListString **newStacks = new wxListString*[number]; - size_t i, j, max = wxMin(number, m_nFields); - - // copy old stacks - for(i = 0; i < max; ++i) - newStacks[i] = m_statusTextStacks[i]; - // free old stacks in excess - for(j = i; j < (size_t)m_nFields; ++j) - { - if(m_statusTextStacks[j]) - { - m_statusTextStacks[j]->Clear(); - delete m_statusTextStacks[j]; - } - } - // initialize new stacks to NULL - for(j = i; j < (size_t)number; ++j) - newStacks[j] = 0; - - m_statusTextStacks = newStacks; - } - - // Resize styles array - if (m_statusStyles) - { - int *oldStyles = m_statusStyles; - m_statusStyles = new int[number]; - int i, max = wxMin(number, m_nFields); - - // copy old styles - for (i = 0; i < max; ++i) - m_statusStyles[i] = oldStyles[i]; - - // initialize new styles to wxSB_NORMAL - for (i = max; i < number; ++i) - m_statusStyles[i] = wxSB_NORMAL; - - // free old styles - delete [] oldStyles; - } - - - m_nFields = number; - - ReinitWidths(); - - refresh = true; - } - //else: keep the old m_statusWidths if we had them - - if ( widths ) - { - SetStatusWidths(number, widths); - - // already done from SetStatusWidths() - refresh = false; - } - - if ( refresh ) - Refresh(); -} - -void wxStatusBarBase::SetStatusWidths(int WXUNUSED_UNLESS_DEBUG(n), - const int widths[]) -{ - wxCHECK_RET( widths, _T("NULL pointer in SetStatusWidths") ); - - wxASSERT_MSG( n == m_nFields, _T("field number mismatch") ); - - if ( !m_statusWidths ) - m_statusWidths = new int[m_nFields]; - - for ( int i = 0; i < m_nFields; i++ ) - { - m_statusWidths[i] = widths[i]; - } - - // update the display after the widths changed - Refresh(); -} - -void wxStatusBarBase::SetStatusStyles(int WXUNUSED_UNLESS_DEBUG(n), - const int styles[]) -{ - wxCHECK_RET( styles, _T("NULL pointer in SetStatusStyles") ); - - wxASSERT_MSG( n == m_nFields, _T("field number mismatch") ); - - if ( !m_statusStyles ) - m_statusStyles = new int[m_nFields]; - - for ( int i = 0; i < m_nFields; i++ ) - { - m_statusStyles[i] = styles[i]; - } - - // update the display after the widths changed - Refresh(); -} - -wxArrayInt wxStatusBarBase::CalculateAbsWidths(wxCoord widthTotal) const -{ - wxArrayInt widths; - - if ( m_statusWidths == NULL ) - { - if ( m_nFields ) - { - // Default: all fields have the same width. This is not always - // possible to do exactly (if widthTotal is not divisible by - // m_nFields) - if that happens, we distribute the extra pixels - // among all fields: - int widthToUse = widthTotal; - - for ( int i = m_nFields; i > 0; i-- ) - { - // divide the unassigned width evently between the - // not yet processed fields: - int w = widthToUse / i; - widths.Add(w); - widthToUse -= w; - } - - } - //else: we're empty anyhow - } - else // have explicit status widths - { - // calculate the total width of all the fixed width fields and the - // total number of var field widths counting with multiplicity - int nTotalWidth = 0, - nVarCount = 0, - i; - for ( i = 0; i < m_nFields; i++ ) - { - if ( m_statusWidths[i] >= 0 ) - { - nTotalWidth += m_statusWidths[i]; - } - else - { - nVarCount += -m_statusWidths[i]; - } - } - - // the amount of extra width we have per each var width field - int widthExtra = widthTotal - nTotalWidth; - - // do fill the array - for ( i = 0; i < m_nFields; i++ ) - { - if ( m_statusWidths[i] >= 0 ) - { - widths.Add(m_statusWidths[i]); - } - else - { - int nVarWidth = widthExtra > 0 ? (widthExtra * -m_statusWidths[i]) / nVarCount : 0; - nVarCount += m_statusWidths[i]; - widthExtra -= nVarWidth; - widths.Add(nVarWidth); - } - } - } - - return widths; -} - -// ---------------------------------------------------------------------------- -// text stacks handling -// ---------------------------------------------------------------------------- - -void wxStatusBarBase::InitStacks() -{ - m_statusTextStacks = NULL; -} - -void wxStatusBarBase::FreeStacks() -{ - if ( !m_statusTextStacks ) - return; - - for ( size_t i = 0; i < (size_t)m_nFields; ++i ) - { - if ( m_statusTextStacks[i] ) - { - wxListString& t = *m_statusTextStacks[i]; - WX_CLEAR_LIST(wxListString, t); - delete m_statusTextStacks[i]; - } - } - - delete[] m_statusTextStacks; -} - -// ---------------------------------------------------------------------------- -// text stacks -// ---------------------------------------------------------------------------- - -void wxStatusBarBase::PushStatusText(const wxString& text, int number) -{ - wxListString* st = GetOrCreateStatusStack(number); - // This long-winded way around avoids an internal compiler error - // in VC++ 6 with RTTI enabled - wxString tmp1(GetStatusText(number)); - wxString* tmp = new wxString(tmp1); - st->Insert(tmp); - SetStatusText(text, number); -} - -void wxStatusBarBase::PopStatusText(int number) -{ - wxListString *st = GetStatusStack(number); - wxCHECK_RET( st, _T("Unbalanced PushStatusText/PopStatusText") ); - wxListString::compatibility_iterator top = st->GetFirst(); - - SetStatusText(*top->GetData(), number); - delete top->GetData(); - st->Erase(top); - if(st->GetCount() == 0) - { - delete st; - m_statusTextStacks[number] = 0; - } -} - -wxListString *wxStatusBarBase::GetStatusStack(int i) const -{ - if(!m_statusTextStacks) - return 0; - return m_statusTextStacks[i]; -} - -wxListString *wxStatusBarBase::GetOrCreateStatusStack(int i) -{ - if(!m_statusTextStacks) - { - m_statusTextStacks = new wxListString*[m_nFields]; - - size_t j; - for(j = 0; j < (size_t)m_nFields; ++j) m_statusTextStacks[j] = 0; - } - - if(!m_statusTextStacks[i]) - { - m_statusTextStacks[i] = new wxListString(); - } - - return m_statusTextStacks[i]; -} - -#endif // wxUSE_STATUSBAR +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/statbar.cpp +// Purpose: wxStatusBarBase implementation +// Author: Vadim Zeitlin +// Modified by: +// Created: 14.10.01 +// RCS-ID: $Id: statbar.cpp 42171 2006-10-20 14:54:14Z VS $ +// Copyright: (c) 2001 Vadim Zeitlin +// License: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STATUSBAR + +#include "wx/statusbr.h" + +#ifndef WX_PRECOMP + #include "wx/frame.h" +#endif //WX_PRECOMP + +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wxListString) + +const wxChar wxStatusBarNameStr[] = wxT("statusBar"); + +// ============================================================================ +// wxStatusBarBase implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxStatusBar, wxWindow) + +// ---------------------------------------------------------------------------- +// ctor/dtor +// ---------------------------------------------------------------------------- + +wxStatusBarBase::wxStatusBarBase() +{ + m_nFields = 0; + + InitWidths(); + InitStacks(); + InitStyles(); +} + +wxStatusBarBase::~wxStatusBarBase() +{ + FreeWidths(); + FreeStacks(); + FreeStyles(); + + // notify the frame that it doesn't have a status bar any longer to avoid + // dangling pointers + wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); + if ( frame && frame->GetStatusBar() == this ) + { + frame->SetStatusBar(NULL); + } +} + +// ---------------------------------------------------------------------------- +// widths array handling +// ---------------------------------------------------------------------------- + +void wxStatusBarBase::InitWidths() +{ + m_statusWidths = NULL; +} + +void wxStatusBarBase::FreeWidths() +{ + delete [] m_statusWidths; +} + +// ---------------------------------------------------------------------------- +// styles array handling +// ---------------------------------------------------------------------------- + +void wxStatusBarBase::InitStyles() +{ + m_statusStyles = NULL; +} + +void wxStatusBarBase::FreeStyles() +{ + delete [] m_statusStyles; +} + +// ---------------------------------------------------------------------------- +// field widths +// ---------------------------------------------------------------------------- + +void wxStatusBarBase::SetFieldsCount(int number, const int *widths) +{ + wxCHECK_RET( number > 0, _T("invalid field number in SetFieldsCount") ); + + bool refresh = false; + + if ( number != m_nFields ) + { + // copy stacks if present + if(m_statusTextStacks) + { + wxListString **newStacks = new wxListString*[number]; + size_t i, j, max = wxMin(number, m_nFields); + + // copy old stacks + for(i = 0; i < max; ++i) + newStacks[i] = m_statusTextStacks[i]; + // free old stacks in excess + for(j = i; j < (size_t)m_nFields; ++j) + { + if(m_statusTextStacks[j]) + { + m_statusTextStacks[j]->Clear(); + delete m_statusTextStacks[j]; + } + } + // initialize new stacks to NULL + for(j = i; j < (size_t)number; ++j) + newStacks[j] = 0; + + m_statusTextStacks = newStacks; + } + + // Resize styles array + if (m_statusStyles) + { + int *oldStyles = m_statusStyles; + m_statusStyles = new int[number]; + int i, max = wxMin(number, m_nFields); + + // copy old styles + for (i = 0; i < max; ++i) + m_statusStyles[i] = oldStyles[i]; + + // initialize new styles to wxSB_NORMAL + for (i = max; i < number; ++i) + m_statusStyles[i] = wxSB_NORMAL; + + // free old styles + delete [] oldStyles; + } + + + m_nFields = number; + + ReinitWidths(); + + refresh = true; + } + //else: keep the old m_statusWidths if we had them + + if ( widths ) + { + SetStatusWidths(number, widths); + + // already done from SetStatusWidths() + refresh = false; + } + + if ( refresh ) + Refresh(); +} + +void wxStatusBarBase::SetStatusWidths(int WXUNUSED_UNLESS_DEBUG(n), + const int widths[]) +{ + wxCHECK_RET( widths, _T("NULL pointer in SetStatusWidths") ); + + wxASSERT_MSG( n == m_nFields, _T("field number mismatch") ); + + if ( !m_statusWidths ) + m_statusWidths = new int[m_nFields]; + + for ( int i = 0; i < m_nFields; i++ ) + { + m_statusWidths[i] = widths[i]; + } + + // update the display after the widths changed + Refresh(); +} + +void wxStatusBarBase::SetStatusStyles(int WXUNUSED_UNLESS_DEBUG(n), + const int styles[]) +{ + wxCHECK_RET( styles, _T("NULL pointer in SetStatusStyles") ); + + wxASSERT_MSG( n == m_nFields, _T("field number mismatch") ); + + if ( !m_statusStyles ) + m_statusStyles = new int[m_nFields]; + + for ( int i = 0; i < m_nFields; i++ ) + { + m_statusStyles[i] = styles[i]; + } + + // update the display after the widths changed + Refresh(); +} + +wxArrayInt wxStatusBarBase::CalculateAbsWidths(wxCoord widthTotal) const +{ + wxArrayInt widths; + + if ( m_statusWidths == NULL ) + { + if ( m_nFields ) + { + // Default: all fields have the same width. This is not always + // possible to do exactly (if widthTotal is not divisible by + // m_nFields) - if that happens, we distribute the extra pixels + // among all fields: + int widthToUse = widthTotal; + + for ( int i = m_nFields; i > 0; i-- ) + { + // divide the unassigned width evently between the + // not yet processed fields: + int w = widthToUse / i; + widths.Add(w); + widthToUse -= w; + } + + } + //else: we're empty anyhow + } + else // have explicit status widths + { + // calculate the total width of all the fixed width fields and the + // total number of var field widths counting with multiplicity + int nTotalWidth = 0, + nVarCount = 0, + i; + for ( i = 0; i < m_nFields; i++ ) + { + if ( m_statusWidths[i] >= 0 ) + { + nTotalWidth += m_statusWidths[i]; + } + else + { + nVarCount += -m_statusWidths[i]; + } + } + + // the amount of extra width we have per each var width field + int widthExtra = widthTotal - nTotalWidth; + + // do fill the array + for ( i = 0; i < m_nFields; i++ ) + { + if ( m_statusWidths[i] >= 0 ) + { + widths.Add(m_statusWidths[i]); + } + else + { + int nVarWidth = widthExtra > 0 ? (widthExtra * -m_statusWidths[i]) / nVarCount : 0; + nVarCount += m_statusWidths[i]; + widthExtra -= nVarWidth; + widths.Add(nVarWidth); + } + } + } + + return widths; +} + +// ---------------------------------------------------------------------------- +// text stacks handling +// ---------------------------------------------------------------------------- + +void wxStatusBarBase::InitStacks() +{ + m_statusTextStacks = NULL; +} + +void wxStatusBarBase::FreeStacks() +{ + if ( !m_statusTextStacks ) + return; + + for ( size_t i = 0; i < (size_t)m_nFields; ++i ) + { + if ( m_statusTextStacks[i] ) + { + wxListString& t = *m_statusTextStacks[i]; + WX_CLEAR_LIST(wxListString, t); + delete m_statusTextStacks[i]; + } + } + + delete[] m_statusTextStacks; +} + +// ---------------------------------------------------------------------------- +// text stacks +// ---------------------------------------------------------------------------- + +void wxStatusBarBase::PushStatusText(const wxString& text, int number) +{ + wxListString* st = GetOrCreateStatusStack(number); + // This long-winded way around avoids an internal compiler error + // in VC++ 6 with RTTI enabled + wxString tmp1(GetStatusText(number)); + wxString* tmp = new wxString(tmp1); + st->Insert(tmp); + SetStatusText(text, number); +} + +void wxStatusBarBase::PopStatusText(int number) +{ + wxListString *st = GetStatusStack(number); + wxCHECK_RET( st, _T("Unbalanced PushStatusText/PopStatusText") ); + wxListString::compatibility_iterator top = st->GetFirst(); + + SetStatusText(*top->GetData(), number); + delete top->GetData(); + st->Erase(top); + if(st->GetCount() == 0) + { + delete st; + m_statusTextStacks[number] = 0; + } +} + +wxListString *wxStatusBarBase::GetStatusStack(int i) const +{ + if(!m_statusTextStacks) + return 0; + return m_statusTextStacks[i]; +} + +wxListString *wxStatusBarBase::GetOrCreateStatusStack(int i) +{ + if(!m_statusTextStacks) + { + m_statusTextStacks = new wxListString*[m_nFields]; + + size_t j; + for(j = 0; j < (size_t)m_nFields; ++j) m_statusTextStacks[j] = 0; + } + + if(!m_statusTextStacks[i]) + { + m_statusTextStacks[i] = new wxListString(); + } + + return m_statusTextStacks[i]; +} + +#endif // wxUSE_STATUSBAR diff --git a/Source/3rd Party/wx/src/common/stdpbase.cpp b/Source/3rd Party/wx/src/common/stdpbase.cpp index a8212c90f..f2d4ff6b0 100644 --- a/Source/3rd Party/wx/src/common/stdpbase.cpp +++ b/Source/3rd Party/wx/src/common/stdpbase.cpp @@ -1,172 +1,172 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: common/stdpbase.cpp -// Purpose: wxStandardPathsBase methods common to all ports -// Author: Vadim Zeitlin -// Modified by: -// Created: 2004-10-19 -// RCS-ID: $Id: stdpbase.cpp 53093 2008-04-08 13:51:17Z JS $ -// Copyright: (c) 2004 Vadim Zeitlin -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STDPATHS - -#ifndef WX_PRECOMP - #include "wx/app.h" -#endif //WX_PRECOMP -#include "wx/apptrait.h" - -#include "wx/filename.h" -#include "wx/stdpaths.h" - -#if defined(__UNIX__) && !defined(__WXMAC__) -#include "wx/log.h" -#include "wx/textfile.h" -#endif - -// ---------------------------------------------------------------------------- -// module globals -// ---------------------------------------------------------------------------- - -static wxStandardPaths gs_stdPaths; - -// ============================================================================ -// implementation -// ============================================================================ - -/* static */ -wxStandardPathsBase& wxStandardPathsBase::Get() -{ - wxAppTraits * const traits = wxTheApp ? wxTheApp->GetTraits() : NULL; - wxCHECK_MSG( traits, gs_stdPaths, _T("create wxApp before calling this") ); - - return traits->GetStandardPaths(); -} - -wxString wxStandardPathsBase::GetExecutablePath() const -{ - if ( !wxTheApp || !wxTheApp->argv ) - return wxEmptyString; - - wxString argv0 = wxTheApp->argv[0]; - if (wxIsAbsolutePath(argv0)) - return argv0; - - // Search PATH.environment variable... - wxPathList pathlist; - pathlist.AddEnvList(wxT("PATH")); - wxString path = pathlist.FindAbsoluteValidPath(argv0); - if ( path.empty() ) - return argv0; // better than nothing - - wxFileName filename(path); - filename.Normalize(); - return filename.GetFullPath(); -} - -wxStandardPathsBase& wxAppTraitsBase::GetStandardPaths() -{ - return gs_stdPaths; -} - -wxStandardPathsBase::~wxStandardPathsBase() -{ - // nothing to do here -} - -wxString wxStandardPathsBase::GetLocalDataDir() const -{ - return GetDataDir(); -} - -wxString wxStandardPathsBase::GetUserLocalDataDir() const -{ - return GetUserDataDir(); -} - -wxString wxStandardPathsBase::GetDocumentsDir() const -{ -#if defined(__UNIX__) && !defined(__WXMAC__) - { - wxLogNull logNull; - wxString homeDir = wxFileName::GetHomeDir(); - wxString configPath; - if (wxGetenv(wxT("XDG_CONFIG_HOME"))) - configPath = wxGetenv(wxT("XDG_CONFIG_HOME")); - else - configPath = homeDir + wxT("/.config"); - wxString dirsFile = configPath + wxT("/user-dirs.dirs"); - if (wxFileExists(dirsFile)) - { - wxTextFile textFile; - if (textFile.Open(dirsFile)) - { - size_t i; - for (i = 0; i < textFile.GetLineCount(); i++) - { - wxString line(textFile[i]); - int pos = line.Find(wxT("XDG_DOCUMENTS_DIR")); - if (pos != wxNOT_FOUND) - { - wxString value = line.AfterFirst(wxT('=')); - value.Replace(wxT("$HOME"), homeDir); - value.Trim(true); - value.Trim(false); - if (!value.IsEmpty() && wxDirExists(value)) - return value; - else - break; - } - } - } - } - } -#endif - - return wxFileName::GetHomeDir(); -} - -// return the temporary directory for the current user -wxString wxStandardPathsBase::GetTempDir() const -{ - return wxFileName::GetTempDir(); -} - -/* static */ -wxString wxStandardPathsBase::AppendAppName(const wxString& dir) -{ - wxString subdir(dir); - - // empty string indicates that an error has occurred, don't touch it then - if ( !subdir.empty() ) - { - const wxString appname = wxTheApp->GetAppName(); - if ( !appname.empty() ) - { - const wxChar ch = *(subdir.end() - 1); - if ( !wxFileName::IsPathSeparator(ch) && ch != _T('.') ) - subdir += wxFileName::GetPathSeparator(); - - subdir += appname; - } - } - - return subdir; -} - -#endif // wxUSE_STDPATHS +/////////////////////////////////////////////////////////////////////////////// +// Name: common/stdpbase.cpp +// Purpose: wxStandardPathsBase methods common to all ports +// Author: Vadim Zeitlin +// Modified by: +// Created: 2004-10-19 +// RCS-ID: $Id: stdpbase.cpp 53093 2008-04-08 13:51:17Z JS $ +// Copyright: (c) 2004 Vadim Zeitlin +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STDPATHS + +#ifndef WX_PRECOMP + #include "wx/app.h" +#endif //WX_PRECOMP +#include "wx/apptrait.h" + +#include "wx/filename.h" +#include "wx/stdpaths.h" + +#if defined(__UNIX__) && !defined(__WXMAC__) +#include "wx/log.h" +#include "wx/textfile.h" +#endif + +// ---------------------------------------------------------------------------- +// module globals +// ---------------------------------------------------------------------------- + +static wxStandardPaths gs_stdPaths; + +// ============================================================================ +// implementation +// ============================================================================ + +/* static */ +wxStandardPathsBase& wxStandardPathsBase::Get() +{ + wxAppTraits * const traits = wxTheApp ? wxTheApp->GetTraits() : NULL; + wxCHECK_MSG( traits, gs_stdPaths, _T("create wxApp before calling this") ); + + return traits->GetStandardPaths(); +} + +wxString wxStandardPathsBase::GetExecutablePath() const +{ + if ( !wxTheApp || !wxTheApp->argv ) + return wxEmptyString; + + wxString argv0 = wxTheApp->argv[0]; + if (wxIsAbsolutePath(argv0)) + return argv0; + + // Search PATH.environment variable... + wxPathList pathlist; + pathlist.AddEnvList(wxT("PATH")); + wxString path = pathlist.FindAbsoluteValidPath(argv0); + if ( path.empty() ) + return argv0; // better than nothing + + wxFileName filename(path); + filename.Normalize(); + return filename.GetFullPath(); +} + +wxStandardPathsBase& wxAppTraitsBase::GetStandardPaths() +{ + return gs_stdPaths; +} + +wxStandardPathsBase::~wxStandardPathsBase() +{ + // nothing to do here +} + +wxString wxStandardPathsBase::GetLocalDataDir() const +{ + return GetDataDir(); +} + +wxString wxStandardPathsBase::GetUserLocalDataDir() const +{ + return GetUserDataDir(); +} + +wxString wxStandardPathsBase::GetDocumentsDir() const +{ +#if defined(__UNIX__) && !defined(__WXMAC__) + { + wxLogNull logNull; + wxString homeDir = wxFileName::GetHomeDir(); + wxString configPath; + if (wxGetenv(wxT("XDG_CONFIG_HOME"))) + configPath = wxGetenv(wxT("XDG_CONFIG_HOME")); + else + configPath = homeDir + wxT("/.config"); + wxString dirsFile = configPath + wxT("/user-dirs.dirs"); + if (wxFileExists(dirsFile)) + { + wxTextFile textFile; + if (textFile.Open(dirsFile)) + { + size_t i; + for (i = 0; i < textFile.GetLineCount(); i++) + { + wxString line(textFile[i]); + int pos = line.Find(wxT("XDG_DOCUMENTS_DIR")); + if (pos != wxNOT_FOUND) + { + wxString value = line.AfterFirst(wxT('=')); + value.Replace(wxT("$HOME"), homeDir); + value.Trim(true); + value.Trim(false); + if (!value.IsEmpty() && wxDirExists(value)) + return value; + else + break; + } + } + } + } + } +#endif + + return wxFileName::GetHomeDir(); +} + +// return the temporary directory for the current user +wxString wxStandardPathsBase::GetTempDir() const +{ + return wxFileName::GetTempDir(); +} + +/* static */ +wxString wxStandardPathsBase::AppendAppName(const wxString& dir) +{ + wxString subdir(dir); + + // empty string indicates that an error has occurred, don't touch it then + if ( !subdir.empty() ) + { + const wxString appname = wxTheApp->GetAppName(); + if ( !appname.empty() ) + { + const wxChar ch = *(subdir.end() - 1); + if ( !wxFileName::IsPathSeparator(ch) && ch != _T('.') ) + subdir += wxFileName::GetPathSeparator(); + + subdir += appname; + } + } + + return subdir; +} + +#endif // wxUSE_STDPATHS diff --git a/Source/3rd Party/wx/src/common/stockitem.cpp b/Source/3rd Party/wx/src/common/stockitem.cpp index ff61d5792..8c1cd480b 100644 --- a/Source/3rd Party/wx/src/common/stockitem.cpp +++ b/Source/3rd Party/wx/src/common/stockitem.cpp @@ -1,278 +1,278 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/stockitem.cpp -// Purpose: Stock buttons, menu and toolbar items labels -// Author: Vaclav Slavik -// Modified by: -// Created: 2004-08-15 -// RCS-ID: $Id: stockitem.cpp 58617 2009-02-02 05:12:43Z SC $ -// Copyright: (c) Vaclav Slavik, 2004 -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/stockitem.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/utils.h" // for wxStripMenuCodes() -#endif - -bool wxIsStockID(wxWindowID id) -{ - switch (id) - { - case wxID_ABOUT: - case wxID_ADD: - case wxID_APPLY: - case wxID_BOLD: - case wxID_CANCEL: - case wxID_CLEAR: - case wxID_CLOSE: - case wxID_COPY: - case wxID_CUT: - case wxID_DELETE: - case wxID_EDIT: - case wxID_FIND: - case wxID_FILE: - case wxID_REPLACE: - case wxID_BACKWARD: - case wxID_DOWN: - case wxID_FORWARD: - case wxID_UP: - case wxID_HELP: - case wxID_HOME: - case wxID_INDENT: - case wxID_INDEX: - case wxID_ITALIC: - case wxID_JUSTIFY_CENTER: - case wxID_JUSTIFY_FILL: - case wxID_JUSTIFY_LEFT: - case wxID_JUSTIFY_RIGHT: - case wxID_NEW: - case wxID_NO: - case wxID_OK: - case wxID_OPEN: - case wxID_PASTE: - case wxID_PREFERENCES: - case wxID_PRINT: - case wxID_PREVIEW: - case wxID_PROPERTIES: - case wxID_EXIT: - case wxID_REDO: - case wxID_REFRESH: - case wxID_REMOVE: - case wxID_REVERT_TO_SAVED: - case wxID_SAVE: - case wxID_SAVEAS: - case wxID_SELECTALL: - case wxID_STOP: - case wxID_UNDELETE: - case wxID_UNDERLINE: - case wxID_UNDO: - case wxID_UNINDENT: - case wxID_YES: - case wxID_ZOOM_100: - case wxID_ZOOM_FIT: - case wxID_ZOOM_IN: - case wxID_ZOOM_OUT: - return true; - - default: - return false; - } -} - -wxString wxGetStockLabel(wxWindowID id, long flags) -{ - wxString stockLabel; - - #define STOCKITEM(stockid, label) \ - case stockid: \ - stockLabel = label; \ - break; - - switch (id) - { - STOCKITEM(wxID_ABOUT, _("&About")) - STOCKITEM(wxID_ADD, _("Add")) - STOCKITEM(wxID_APPLY, _("&Apply")) - STOCKITEM(wxID_BOLD, _("&Bold")) - STOCKITEM(wxID_CANCEL, _("&Cancel")) - STOCKITEM(wxID_CLEAR, _("&Clear")) - STOCKITEM(wxID_CLOSE, _("&Close")) - STOCKITEM(wxID_COPY, _("&Copy")) - STOCKITEM(wxID_CUT, _("Cu&t")) - STOCKITEM(wxID_DELETE, _("&Delete")) - STOCKITEM(wxID_EDIT, _("&Edit")) - STOCKITEM(wxID_FIND, _("&Find")) - STOCKITEM(wxID_FILE, _("&File")) - STOCKITEM(wxID_REPLACE, _("Rep&lace")) - STOCKITEM(wxID_BACKWARD, _("&Back")) - STOCKITEM(wxID_DOWN, _("&Down")) - STOCKITEM(wxID_FORWARD, _("&Forward")) - STOCKITEM(wxID_UP, _("&Up")) - STOCKITEM(wxID_HELP, _("&Help")) - STOCKITEM(wxID_HOME, _("&Home")) - STOCKITEM(wxID_INDENT, _("Indent")) - STOCKITEM(wxID_INDEX, _("&Index")) - STOCKITEM(wxID_ITALIC, _("&Italic")) - STOCKITEM(wxID_JUSTIFY_CENTER, _("Centered")) - STOCKITEM(wxID_JUSTIFY_FILL, _("Justified")) - STOCKITEM(wxID_JUSTIFY_LEFT, _("Align Left")) - STOCKITEM(wxID_JUSTIFY_RIGHT, _("Align Right")) - STOCKITEM(wxID_NEW, _("&New")) - STOCKITEM(wxID_NO, _("&No")) - STOCKITEM(wxID_OK, _("&OK")) - STOCKITEM(wxID_OPEN, _("&Open")) - STOCKITEM(wxID_PASTE, _("&Paste")) - STOCKITEM(wxID_PREFERENCES, _("&Preferences")) - STOCKITEM(wxID_PRINT, _("&Print")) - STOCKITEM(wxID_PREVIEW, _("Print previe&w")) - STOCKITEM(wxID_PROPERTIES, _("&Properties")) - STOCKITEM(wxID_EXIT, _("&Quit")) - STOCKITEM(wxID_REDO, _("&Redo")) - STOCKITEM(wxID_REFRESH, _("Refresh")) - STOCKITEM(wxID_REMOVE, _("Remove")) - STOCKITEM(wxID_REVERT_TO_SAVED, _("Revert to Saved")) - STOCKITEM(wxID_SAVE, _("&Save")) - STOCKITEM(wxID_SAVEAS, _("Save &As...")) - STOCKITEM(wxID_SELECTALL, _("Select all")) - STOCKITEM(wxID_STOP, _("&Stop")) - STOCKITEM(wxID_UNDELETE, _("Undelete")) - STOCKITEM(wxID_UNDERLINE, _("&Underline")) - STOCKITEM(wxID_UNDO, _("&Undo")) - STOCKITEM(wxID_UNINDENT, _("&Unindent")) - STOCKITEM(wxID_YES, _("&Yes")) - STOCKITEM(wxID_ZOOM_100, _("&Actual Size")) - STOCKITEM(wxID_ZOOM_FIT, _("Zoom to &Fit")) - STOCKITEM(wxID_ZOOM_IN, _("Zoom &In")) - STOCKITEM(wxID_ZOOM_OUT, _("Zoom &Out")) - - default: - wxFAIL_MSG( _T("invalid stock item ID") ); - break; - }; - - #undef STOCKITEM - - if ( !(flags & wxSTOCK_WITH_MNEMONIC) ) - { - stockLabel = wxStripMenuCodes(stockLabel); - } - -#if wxUSE_ACCEL - if ( !stockLabel.empty() && (flags & wxSTOCK_WITH_ACCELERATOR) ) - { - wxAcceleratorEntry accel = wxGetStockAccelerator(id); - if (accel.IsOk()) - stockLabel << _T('\t') << accel.ToString(); - } -#endif // wxUSE_ACCEL - - return stockLabel; -} - -wxString wxGetStockHelpString(wxWindowID id, wxStockHelpStringClient client) -{ - wxString stockHelp; - - #define STOCKITEM(stockid, ctx, helpstr) \ - case stockid: \ - if (client==ctx) stockHelp = helpstr; \ - break; - - switch (id) - { - // NB: these help string should be not too specific as they could be used - // in completely different programs! - STOCKITEM(wxID_ABOUT, wxSTOCK_MENU, _("Show about dialog")) - STOCKITEM(wxID_COPY, wxSTOCK_MENU, _("Copy selection")) - STOCKITEM(wxID_CUT, wxSTOCK_MENU, _("Cut selection")) - STOCKITEM(wxID_DELETE, wxSTOCK_MENU, _("Delete selection")) - STOCKITEM(wxID_REPLACE, wxSTOCK_MENU, _("Replace selection")) - STOCKITEM(wxID_PASTE, wxSTOCK_MENU, _("Paste selection")) - STOCKITEM(wxID_EXIT, wxSTOCK_MENU, _("Quit this program")) - STOCKITEM(wxID_REDO, wxSTOCK_MENU, _("Redo last action")) - STOCKITEM(wxID_UNDO, wxSTOCK_MENU, _("Undo last action")) - STOCKITEM(wxID_CLOSE, wxSTOCK_MENU, _("Close current document")) - STOCKITEM(wxID_SAVE, wxSTOCK_MENU, _("Save current document")) - STOCKITEM(wxID_SAVEAS, wxSTOCK_MENU, _("Save current document with a different filename")) - - default: - // there's no stock help string for this ID / client - return wxEmptyString; - } - - #undef STOCKITEM - - return stockHelp; -} - -#if wxUSE_ACCEL - -wxAcceleratorEntry wxGetStockAccelerator(wxWindowID id) -{ - wxAcceleratorEntry ret; - - #define STOCKITEM(stockid, flags, keycode) \ - case stockid: \ - ret.Set(flags, keycode, stockid); \ - break; - - switch (id) - { - STOCKITEM(wxID_COPY, wxACCEL_CMD,'C') - STOCKITEM(wxID_CUT, wxACCEL_CMD,'X') - STOCKITEM(wxID_FIND, wxACCEL_CMD,'F') - STOCKITEM(wxID_REPLACE, wxACCEL_CMD,'R') - STOCKITEM(wxID_HELP, wxACCEL_CMD,'H') - STOCKITEM(wxID_NEW, wxACCEL_CMD,'N') - STOCKITEM(wxID_OPEN, wxACCEL_CMD,'O') - STOCKITEM(wxID_PASTE, wxACCEL_CMD,'V') - STOCKITEM(wxID_SAVE, wxACCEL_CMD,'S') - - default: - // set the wxAcceleratorEntry to return into an invalid state: - // there's no stock accelerator for that. - ret.Set(0, 0, id); - break; - }; - - #undef STOCKITEM - - // always use wxAcceleratorEntry::IsOk on returned value ! - return ret; -} - -#endif // wxUSE_ACCEL - -bool wxIsStockLabel(wxWindowID id, const wxString& label) -{ - if (label.empty()) - return true; - - wxString stock = wxGetStockLabel(id); - - if (label == stock) - return true; - - stock.Replace(_T("&"), wxEmptyString); - if (label == stock) - return true; - - return false; -} +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/stockitem.cpp +// Purpose: Stock buttons, menu and toolbar items labels +// Author: Vaclav Slavik +// Modified by: +// Created: 2004-08-15 +// RCS-ID: $Id: stockitem.cpp 58617 2009-02-02 05:12:43Z SC $ +// Copyright: (c) Vaclav Slavik, 2004 +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/stockitem.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/utils.h" // for wxStripMenuCodes() +#endif + +bool wxIsStockID(wxWindowID id) +{ + switch (id) + { + case wxID_ABOUT: + case wxID_ADD: + case wxID_APPLY: + case wxID_BOLD: + case wxID_CANCEL: + case wxID_CLEAR: + case wxID_CLOSE: + case wxID_COPY: + case wxID_CUT: + case wxID_DELETE: + case wxID_EDIT: + case wxID_FIND: + case wxID_FILE: + case wxID_REPLACE: + case wxID_BACKWARD: + case wxID_DOWN: + case wxID_FORWARD: + case wxID_UP: + case wxID_HELP: + case wxID_HOME: + case wxID_INDENT: + case wxID_INDEX: + case wxID_ITALIC: + case wxID_JUSTIFY_CENTER: + case wxID_JUSTIFY_FILL: + case wxID_JUSTIFY_LEFT: + case wxID_JUSTIFY_RIGHT: + case wxID_NEW: + case wxID_NO: + case wxID_OK: + case wxID_OPEN: + case wxID_PASTE: + case wxID_PREFERENCES: + case wxID_PRINT: + case wxID_PREVIEW: + case wxID_PROPERTIES: + case wxID_EXIT: + case wxID_REDO: + case wxID_REFRESH: + case wxID_REMOVE: + case wxID_REVERT_TO_SAVED: + case wxID_SAVE: + case wxID_SAVEAS: + case wxID_SELECTALL: + case wxID_STOP: + case wxID_UNDELETE: + case wxID_UNDERLINE: + case wxID_UNDO: + case wxID_UNINDENT: + case wxID_YES: + case wxID_ZOOM_100: + case wxID_ZOOM_FIT: + case wxID_ZOOM_IN: + case wxID_ZOOM_OUT: + return true; + + default: + return false; + } +} + +wxString wxGetStockLabel(wxWindowID id, long flags) +{ + wxString stockLabel; + + #define STOCKITEM(stockid, label) \ + case stockid: \ + stockLabel = label; \ + break; + + switch (id) + { + STOCKITEM(wxID_ABOUT, _("&About")) + STOCKITEM(wxID_ADD, _("Add")) + STOCKITEM(wxID_APPLY, _("&Apply")) + STOCKITEM(wxID_BOLD, _("&Bold")) + STOCKITEM(wxID_CANCEL, _("&Cancel")) + STOCKITEM(wxID_CLEAR, _("&Clear")) + STOCKITEM(wxID_CLOSE, _("&Close")) + STOCKITEM(wxID_COPY, _("&Copy")) + STOCKITEM(wxID_CUT, _("Cu&t")) + STOCKITEM(wxID_DELETE, _("&Delete")) + STOCKITEM(wxID_EDIT, _("&Edit")) + STOCKITEM(wxID_FIND, _("&Find")) + STOCKITEM(wxID_FILE, _("&File")) + STOCKITEM(wxID_REPLACE, _("Rep&lace")) + STOCKITEM(wxID_BACKWARD, _("&Back")) + STOCKITEM(wxID_DOWN, _("&Down")) + STOCKITEM(wxID_FORWARD, _("&Forward")) + STOCKITEM(wxID_UP, _("&Up")) + STOCKITEM(wxID_HELP, _("&Help")) + STOCKITEM(wxID_HOME, _("&Home")) + STOCKITEM(wxID_INDENT, _("Indent")) + STOCKITEM(wxID_INDEX, _("&Index")) + STOCKITEM(wxID_ITALIC, _("&Italic")) + STOCKITEM(wxID_JUSTIFY_CENTER, _("Centered")) + STOCKITEM(wxID_JUSTIFY_FILL, _("Justified")) + STOCKITEM(wxID_JUSTIFY_LEFT, _("Align Left")) + STOCKITEM(wxID_JUSTIFY_RIGHT, _("Align Right")) + STOCKITEM(wxID_NEW, _("&New")) + STOCKITEM(wxID_NO, _("&No")) + STOCKITEM(wxID_OK, _("&OK")) + STOCKITEM(wxID_OPEN, _("&Open")) + STOCKITEM(wxID_PASTE, _("&Paste")) + STOCKITEM(wxID_PREFERENCES, _("&Preferences")) + STOCKITEM(wxID_PRINT, _("&Print")) + STOCKITEM(wxID_PREVIEW, _("Print previe&w")) + STOCKITEM(wxID_PROPERTIES, _("&Properties")) + STOCKITEM(wxID_EXIT, _("&Quit")) + STOCKITEM(wxID_REDO, _("&Redo")) + STOCKITEM(wxID_REFRESH, _("Refresh")) + STOCKITEM(wxID_REMOVE, _("Remove")) + STOCKITEM(wxID_REVERT_TO_SAVED, _("Revert to Saved")) + STOCKITEM(wxID_SAVE, _("&Save")) + STOCKITEM(wxID_SAVEAS, _("Save &As...")) + STOCKITEM(wxID_SELECTALL, _("Select all")) + STOCKITEM(wxID_STOP, _("&Stop")) + STOCKITEM(wxID_UNDELETE, _("Undelete")) + STOCKITEM(wxID_UNDERLINE, _("&Underline")) + STOCKITEM(wxID_UNDO, _("&Undo")) + STOCKITEM(wxID_UNINDENT, _("&Unindent")) + STOCKITEM(wxID_YES, _("&Yes")) + STOCKITEM(wxID_ZOOM_100, _("&Actual Size")) + STOCKITEM(wxID_ZOOM_FIT, _("Zoom to &Fit")) + STOCKITEM(wxID_ZOOM_IN, _("Zoom &In")) + STOCKITEM(wxID_ZOOM_OUT, _("Zoom &Out")) + + default: + wxFAIL_MSG( _T("invalid stock item ID") ); + break; + }; + + #undef STOCKITEM + + if ( !(flags & wxSTOCK_WITH_MNEMONIC) ) + { + stockLabel = wxStripMenuCodes(stockLabel); + } + +#if wxUSE_ACCEL + if ( !stockLabel.empty() && (flags & wxSTOCK_WITH_ACCELERATOR) ) + { + wxAcceleratorEntry accel = wxGetStockAccelerator(id); + if (accel.IsOk()) + stockLabel << _T('\t') << accel.ToString(); + } +#endif // wxUSE_ACCEL + + return stockLabel; +} + +wxString wxGetStockHelpString(wxWindowID id, wxStockHelpStringClient client) +{ + wxString stockHelp; + + #define STOCKITEM(stockid, ctx, helpstr) \ + case stockid: \ + if (client==ctx) stockHelp = helpstr; \ + break; + + switch (id) + { + // NB: these help string should be not too specific as they could be used + // in completely different programs! + STOCKITEM(wxID_ABOUT, wxSTOCK_MENU, _("Show about dialog")) + STOCKITEM(wxID_COPY, wxSTOCK_MENU, _("Copy selection")) + STOCKITEM(wxID_CUT, wxSTOCK_MENU, _("Cut selection")) + STOCKITEM(wxID_DELETE, wxSTOCK_MENU, _("Delete selection")) + STOCKITEM(wxID_REPLACE, wxSTOCK_MENU, _("Replace selection")) + STOCKITEM(wxID_PASTE, wxSTOCK_MENU, _("Paste selection")) + STOCKITEM(wxID_EXIT, wxSTOCK_MENU, _("Quit this program")) + STOCKITEM(wxID_REDO, wxSTOCK_MENU, _("Redo last action")) + STOCKITEM(wxID_UNDO, wxSTOCK_MENU, _("Undo last action")) + STOCKITEM(wxID_CLOSE, wxSTOCK_MENU, _("Close current document")) + STOCKITEM(wxID_SAVE, wxSTOCK_MENU, _("Save current document")) + STOCKITEM(wxID_SAVEAS, wxSTOCK_MENU, _("Save current document with a different filename")) + + default: + // there's no stock help string for this ID / client + return wxEmptyString; + } + + #undef STOCKITEM + + return stockHelp; +} + +#if wxUSE_ACCEL + +wxAcceleratorEntry wxGetStockAccelerator(wxWindowID id) +{ + wxAcceleratorEntry ret; + + #define STOCKITEM(stockid, flags, keycode) \ + case stockid: \ + ret.Set(flags, keycode, stockid); \ + break; + + switch (id) + { + STOCKITEM(wxID_COPY, wxACCEL_CMD,'C') + STOCKITEM(wxID_CUT, wxACCEL_CMD,'X') + STOCKITEM(wxID_FIND, wxACCEL_CMD,'F') + STOCKITEM(wxID_REPLACE, wxACCEL_CMD,'R') + STOCKITEM(wxID_HELP, wxACCEL_CMD,'H') + STOCKITEM(wxID_NEW, wxACCEL_CMD,'N') + STOCKITEM(wxID_OPEN, wxACCEL_CMD,'O') + STOCKITEM(wxID_PASTE, wxACCEL_CMD,'V') + STOCKITEM(wxID_SAVE, wxACCEL_CMD,'S') + + default: + // set the wxAcceleratorEntry to return into an invalid state: + // there's no stock accelerator for that. + ret.Set(0, 0, id); + break; + }; + + #undef STOCKITEM + + // always use wxAcceleratorEntry::IsOk on returned value ! + return ret; +} + +#endif // wxUSE_ACCEL + +bool wxIsStockLabel(wxWindowID id, const wxString& label) +{ + if (label.empty()) + return true; + + wxString stock = wxGetStockLabel(id); + + if (label == stock) + return true; + + stock.Replace(_T("&"), wxEmptyString); + if (label == stock) + return true; + + return false; +} diff --git a/Source/3rd Party/wx/src/common/stopwatch.cpp b/Source/3rd Party/wx/src/common/stopwatch.cpp index 1c8bbdaed..eefbae7e9 100644 --- a/Source/3rd Party/wx/src/common/stopwatch.cpp +++ b/Source/3rd Party/wx/src/common/stopwatch.cpp @@ -1,372 +1,372 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/stopwatch.cpp -// Purpose: wxStopWatch and other non-GUI stuff from wx/timer.h -// Author: -// Original version by Julian Smart -// Vadim Zeitlin got rid of all ifdefs (11.12.99) -// Sylvain Bougnoux added wxStopWatch class -// Guillermo Rodriguez rewrote from scratch (Dic/99) -// Modified by: -// Created: 20.06.2003 (extracted from common/timercmn.cpp) -// RCS-ID: $Id: stopwatch.cpp 41054 2006-09-07 19:01:45Z ABX $ -// Copyright: (c) 1998-2003 wxWidgets Team -// License: wxWindows license -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/stopwatch.h" - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/wrapwin.h" - #endif - #include "wx/intl.h" - #include "wx/log.h" -#endif //WX_PRECOMP - -// ---------------------------------------------------------------------------- -// System headers -// ---------------------------------------------------------------------------- - -#if defined(__WIN32__) && !defined(HAVE_FTIME) && !defined(__MWERKS__) && !defined(__WXWINCE__) - #define HAVE_FTIME -#endif - -#if defined(__VISAGECPP__) && !defined(HAVE_FTIME) - #define HAVE_FTIME -# if __IBMCPP__ >= 400 - # define ftime(x) _ftime(x) -# endif -#endif - -#if defined(__MWERKS__) && defined(__WXMSW__) -# undef HAVE_FTIME -# undef HAVE_GETTIMEOFDAY -#endif - -#ifndef __WXWINCE__ -#include -#else -#include "wx/msw/private.h" -#include "wx/msw/wince/time.h" -#endif - -#if !defined(__WXMAC__) && !defined(__WXWINCE__) - #include // for time_t -#endif - -#if defined(HAVE_GETTIMEOFDAY) - #include - #include -#elif defined(HAVE_FTIME) - #include -#endif - -#ifdef __WXMAC__ -#ifndef __DARWIN__ - #include - #include -#else - #include -#endif -#endif - -#ifdef __WXPALMOS__ - #include - #include - #include -#endif - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- - -// on some really old systems gettimeofday() doesn't have the second argument, -// define wxGetTimeOfDay() to hide this difference -#ifdef HAVE_GETTIMEOFDAY - #ifdef WX_GETTIMEOFDAY_NO_TZ - struct timezone; - #define wxGetTimeOfDay(tv, tz) gettimeofday(tv) - #else - #define wxGetTimeOfDay(tv, tz) gettimeofday((tv), (tz)) - #endif -#endif // HAVE_GETTIMEOFDAY - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxStopWatch -// ---------------------------------------------------------------------------- - -#if wxUSE_STOPWATCH - -void wxStopWatch::Start(long t) -{ -#if 0 -// __WXMSW__ - LARGE_INTEGER frequency_li; - ::QueryPerformanceFrequency( &frequency_li ); - m_frequency = frequency_li.QuadPart; - if (m_frequency == 0) - { - m_t0 = wxGetLocalTimeMillis() - t; - } - else - { - LARGE_INTEGER counter_li; - ::QueryPerformanceCounter( &counter_li ); - wxLongLong counter = counter_li.QuadPart; - m_t0 = (counter * 10000 / m_frequency) - t*10; - } -#else - m_t0 = wxGetLocalTimeMillis() - t; -#endif - m_pause = 0; - m_pauseCount = 0; -} - -long wxStopWatch::GetElapsedTime() const -{ -#if 0 -//__WXMSW__ - if (m_frequency == 0) - { - return (wxGetLocalTimeMillis() - m_t0).GetLo(); - } - else - { - LARGE_INTEGER counter_li; - ::QueryPerformanceCounter( &counter_li ); - wxLongLong counter = counter_li.QuadPart; - wxLongLong res = (counter * 10000 / m_frequency) - m_t0; - return res.GetLo() / 10; - } -#else - return (wxGetLocalTimeMillis() - m_t0).GetLo(); -#endif -} - -long wxStopWatch::Time() const -{ - return m_pauseCount ? m_pause : GetElapsedTime(); -} - -#endif // wxUSE_STOPWATCH - -// ---------------------------------------------------------------------------- -// old timer functions superceded by wxStopWatch -// ---------------------------------------------------------------------------- - -#if wxUSE_LONGLONG - -static wxLongLong wxStartTime = 0l; - -// starts the global timer -void wxStartTimer() -{ - wxStartTime = wxGetLocalTimeMillis(); -} - -// Returns elapsed time in milliseconds -long wxGetElapsedTime(bool resetTimer) -{ - wxLongLong oldTime = wxStartTime; - wxLongLong newTime = wxGetLocalTimeMillis(); - - if ( resetTimer ) - wxStartTime = newTime; - - return (newTime - oldTime).GetLo(); -} - -#endif // wxUSE_LONGLONG - -// ---------------------------------------------------------------------------- -// the functions to get the current time and timezone info -// ---------------------------------------------------------------------------- - -// Get local time as seconds since 00:00:00, Jan 1st 1970 -long wxGetLocalTime() -{ - struct tm tm; - time_t t0, t1; - - // This cannot be made static because mktime can overwrite it. - // - memset(&tm, 0, sizeof(tm)); - tm.tm_year = 70; - tm.tm_mon = 0; - tm.tm_mday = 5; // not Jan 1st 1970 due to mktime 'feature' - tm.tm_hour = 0; - tm.tm_min = 0; - tm.tm_sec = 0; - tm.tm_isdst = -1; // let mktime guess - - // Note that mktime assumes that the struct tm contains local time. - // - t1 = time(&t1); // now - t0 = mktime(&tm); // origin - - // Return the difference in seconds. - // - if (( t0 != (time_t)-1 ) && ( t1 != (time_t)-1 )) - return (long)difftime(t1, t0) + (60 * 60 * 24 * 4); - - wxLogSysError(_("Failed to get the local system time")); - return -1; -} - -// Get UTC time as seconds since 00:00:00, Jan 1st 1970 -long wxGetUTCTime() -{ - return (long)time(NULL); -} - -#if wxUSE_LONGLONG - -// Get local time as milliseconds since 00:00:00, Jan 1st 1970 -wxLongLong wxGetLocalTimeMillis() -{ - wxLongLong val = 1000l; - - // If possible, use a function which avoids conversions from - // broken-up time structures to milliseconds - -#if defined(__WXPALMOS__) - DateTimeType thenst; - thenst.second = 0; - thenst.minute = 0; - thenst.hour = 0; - thenst.day = 1; - thenst.month = 1; - thenst.year = 1970; - thenst.weekDay = 5; - uint32_t now = TimGetSeconds(); - uint32_t then = TimDateTimeToSeconds (&thenst); - return SysTimeToMilliSecs(SysTimeInSecs(now - then)); -#elif defined(__WXMSW__) && (defined(__WINE__) || defined(__MWERKS__)) - // This should probably be the way all WXMSW compilers should do it - // Go direct to the OS for time - - SYSTEMTIME thenst = { 1970, 1, 4, 1, 0, 0, 0, 0 }; // 00:00:00 Jan 1st 1970 - FILETIME thenft; - SystemTimeToFileTime( &thenst, &thenft ); - wxLongLong then( thenft.dwHighDateTime, thenft.dwLowDateTime ); // time in 100 nanoseconds - - SYSTEMTIME nowst; - GetLocalTime( &nowst ); - FILETIME nowft; - SystemTimeToFileTime( &nowst, &nowft ); - wxLongLong now( nowft.dwHighDateTime, nowft.dwLowDateTime ); // time in 100 nanoseconds - - return ( now - then ) / 10000.0; // time from 00:00:00 Jan 1st 1970 to now in milliseconds - -#elif defined(HAVE_GETTIMEOFDAY) - struct timeval tp; - if ( wxGetTimeOfDay(&tp, (struct timezone *)NULL) != -1 ) - { - val *= tp.tv_sec; - return (val + (tp.tv_usec / 1000)); - } - else - { - wxLogError(_("wxGetTimeOfDay failed.")); - return 0; - } -#elif defined(HAVE_FTIME) - struct timeb tp; - - // ftime() is void and not int in some mingw32 headers, so don't - // test the return code (well, it shouldn't fail anyhow...) - (void)::ftime(&tp); - val *= tp.time; - return (val + tp.millitm); -#elif defined(__WXMAC__) - - static UInt64 gMilliAtStart = 0; - - Nanoseconds upTime = AbsoluteToNanoseconds( UpTime() ); - - if ( gMilliAtStart == 0 ) - { - time_t start = time(NULL); - gMilliAtStart = ((UInt64) start) * 1000000L; - gMilliAtStart -= upTime.lo / 1000 ; - gMilliAtStart -= ( ( (UInt64) upTime.hi ) << 32 ) / (1000 * 1000); - } - - UInt64 millival = gMilliAtStart; - millival += upTime.lo / (1000 * 1000); - millival += ( ( (UInt64) upTime.hi ) << 32 ) / (1000 * 1000); - val = millival; - - return val; -#else // no gettimeofday() nor ftime() - // We use wxGetLocalTime() to get the seconds since - // 00:00:00 Jan 1st 1970 and then whatever is available - // to get millisecond resolution. - // - // NOTE that this might lead to a problem if the clocks - // use different sources, so this approach should be - // avoided where possible. - - val *= wxGetLocalTime(); - -// GRG: This will go soon as all WIN32 seem to have ftime -// JACS: unfortunately not. WinCE doesn't have it. -#if defined (__WIN32__) - // If your platform/compiler needs to use two different functions - // to get ms resolution, please do NOT just shut off these warnings, - // drop me a line instead at - - // FIXME -#ifndef __WXWINCE__ - #warning "Possible clock skew bug in wxGetLocalTimeMillis()!" -#endif - - SYSTEMTIME st; - ::GetLocalTime(&st); - val += st.wMilliseconds; -#else // !Win32 - // If your platform/compiler does not support ms resolution please - // do NOT just shut off these warnings, drop me a line instead at - // - - #if defined(__VISUALC__) || defined (__WATCOMC__) - #pragma message("wxStopWatch will be up to second resolution!") - #elif defined(__BORLANDC__) - #pragma message "wxStopWatch will be up to second resolution!" - #else - #warning "wxStopWatch will be up to second resolution!" - #endif // compiler -#endif - - return val; - -#endif // time functions -} - -#else // !wxUSE_LONGLONG - -double wxGetLocalTimeMillis(void) -{ - return (double(clock()) / double(CLOCKS_PER_SEC)) * 1000.0; -} - -#endif // wxUSE_LONGLONG/!wxUSE_LONGLONG +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/stopwatch.cpp +// Purpose: wxStopWatch and other non-GUI stuff from wx/timer.h +// Author: +// Original version by Julian Smart +// Vadim Zeitlin got rid of all ifdefs (11.12.99) +// Sylvain Bougnoux added wxStopWatch class +// Guillermo Rodriguez rewrote from scratch (Dic/99) +// Modified by: +// Created: 20.06.2003 (extracted from common/timercmn.cpp) +// RCS-ID: $Id: stopwatch.cpp 41054 2006-09-07 19:01:45Z ABX $ +// Copyright: (c) 1998-2003 wxWidgets Team +// License: wxWindows license +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/stopwatch.h" + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" + #endif + #include "wx/intl.h" + #include "wx/log.h" +#endif //WX_PRECOMP + +// ---------------------------------------------------------------------------- +// System headers +// ---------------------------------------------------------------------------- + +#if defined(__WIN32__) && !defined(HAVE_FTIME) && !defined(__MWERKS__) && !defined(__WXWINCE__) + #define HAVE_FTIME +#endif + +#if defined(__VISAGECPP__) && !defined(HAVE_FTIME) + #define HAVE_FTIME +# if __IBMCPP__ >= 400 + # define ftime(x) _ftime(x) +# endif +#endif + +#if defined(__MWERKS__) && defined(__WXMSW__) +# undef HAVE_FTIME +# undef HAVE_GETTIMEOFDAY +#endif + +#ifndef __WXWINCE__ +#include +#else +#include "wx/msw/private.h" +#include "wx/msw/wince/time.h" +#endif + +#if !defined(__WXMAC__) && !defined(__WXWINCE__) + #include // for time_t +#endif + +#if defined(HAVE_GETTIMEOFDAY) + #include + #include +#elif defined(HAVE_FTIME) + #include +#endif + +#ifdef __WXMAC__ +#ifndef __DARWIN__ + #include + #include +#else + #include +#endif +#endif + +#ifdef __WXPALMOS__ + #include + #include + #include +#endif + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +// on some really old systems gettimeofday() doesn't have the second argument, +// define wxGetTimeOfDay() to hide this difference +#ifdef HAVE_GETTIMEOFDAY + #ifdef WX_GETTIMEOFDAY_NO_TZ + struct timezone; + #define wxGetTimeOfDay(tv, tz) gettimeofday(tv) + #else + #define wxGetTimeOfDay(tv, tz) gettimeofday((tv), (tz)) + #endif +#endif // HAVE_GETTIMEOFDAY + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxStopWatch +// ---------------------------------------------------------------------------- + +#if wxUSE_STOPWATCH + +void wxStopWatch::Start(long t) +{ +#if 0 +// __WXMSW__ + LARGE_INTEGER frequency_li; + ::QueryPerformanceFrequency( &frequency_li ); + m_frequency = frequency_li.QuadPart; + if (m_frequency == 0) + { + m_t0 = wxGetLocalTimeMillis() - t; + } + else + { + LARGE_INTEGER counter_li; + ::QueryPerformanceCounter( &counter_li ); + wxLongLong counter = counter_li.QuadPart; + m_t0 = (counter * 10000 / m_frequency) - t*10; + } +#else + m_t0 = wxGetLocalTimeMillis() - t; +#endif + m_pause = 0; + m_pauseCount = 0; +} + +long wxStopWatch::GetElapsedTime() const +{ +#if 0 +//__WXMSW__ + if (m_frequency == 0) + { + return (wxGetLocalTimeMillis() - m_t0).GetLo(); + } + else + { + LARGE_INTEGER counter_li; + ::QueryPerformanceCounter( &counter_li ); + wxLongLong counter = counter_li.QuadPart; + wxLongLong res = (counter * 10000 / m_frequency) - m_t0; + return res.GetLo() / 10; + } +#else + return (wxGetLocalTimeMillis() - m_t0).GetLo(); +#endif +} + +long wxStopWatch::Time() const +{ + return m_pauseCount ? m_pause : GetElapsedTime(); +} + +#endif // wxUSE_STOPWATCH + +// ---------------------------------------------------------------------------- +// old timer functions superceded by wxStopWatch +// ---------------------------------------------------------------------------- + +#if wxUSE_LONGLONG + +static wxLongLong wxStartTime = 0l; + +// starts the global timer +void wxStartTimer() +{ + wxStartTime = wxGetLocalTimeMillis(); +} + +// Returns elapsed time in milliseconds +long wxGetElapsedTime(bool resetTimer) +{ + wxLongLong oldTime = wxStartTime; + wxLongLong newTime = wxGetLocalTimeMillis(); + + if ( resetTimer ) + wxStartTime = newTime; + + return (newTime - oldTime).GetLo(); +} + +#endif // wxUSE_LONGLONG + +// ---------------------------------------------------------------------------- +// the functions to get the current time and timezone info +// ---------------------------------------------------------------------------- + +// Get local time as seconds since 00:00:00, Jan 1st 1970 +long wxGetLocalTime() +{ + struct tm tm; + time_t t0, t1; + + // This cannot be made static because mktime can overwrite it. + // + memset(&tm, 0, sizeof(tm)); + tm.tm_year = 70; + tm.tm_mon = 0; + tm.tm_mday = 5; // not Jan 1st 1970 due to mktime 'feature' + tm.tm_hour = 0; + tm.tm_min = 0; + tm.tm_sec = 0; + tm.tm_isdst = -1; // let mktime guess + + // Note that mktime assumes that the struct tm contains local time. + // + t1 = time(&t1); // now + t0 = mktime(&tm); // origin + + // Return the difference in seconds. + // + if (( t0 != (time_t)-1 ) && ( t1 != (time_t)-1 )) + return (long)difftime(t1, t0) + (60 * 60 * 24 * 4); + + wxLogSysError(_("Failed to get the local system time")); + return -1; +} + +// Get UTC time as seconds since 00:00:00, Jan 1st 1970 +long wxGetUTCTime() +{ + return (long)time(NULL); +} + +#if wxUSE_LONGLONG + +// Get local time as milliseconds since 00:00:00, Jan 1st 1970 +wxLongLong wxGetLocalTimeMillis() +{ + wxLongLong val = 1000l; + + // If possible, use a function which avoids conversions from + // broken-up time structures to milliseconds + +#if defined(__WXPALMOS__) + DateTimeType thenst; + thenst.second = 0; + thenst.minute = 0; + thenst.hour = 0; + thenst.day = 1; + thenst.month = 1; + thenst.year = 1970; + thenst.weekDay = 5; + uint32_t now = TimGetSeconds(); + uint32_t then = TimDateTimeToSeconds (&thenst); + return SysTimeToMilliSecs(SysTimeInSecs(now - then)); +#elif defined(__WXMSW__) && (defined(__WINE__) || defined(__MWERKS__)) + // This should probably be the way all WXMSW compilers should do it + // Go direct to the OS for time + + SYSTEMTIME thenst = { 1970, 1, 4, 1, 0, 0, 0, 0 }; // 00:00:00 Jan 1st 1970 + FILETIME thenft; + SystemTimeToFileTime( &thenst, &thenft ); + wxLongLong then( thenft.dwHighDateTime, thenft.dwLowDateTime ); // time in 100 nanoseconds + + SYSTEMTIME nowst; + GetLocalTime( &nowst ); + FILETIME nowft; + SystemTimeToFileTime( &nowst, &nowft ); + wxLongLong now( nowft.dwHighDateTime, nowft.dwLowDateTime ); // time in 100 nanoseconds + + return ( now - then ) / 10000.0; // time from 00:00:00 Jan 1st 1970 to now in milliseconds + +#elif defined(HAVE_GETTIMEOFDAY) + struct timeval tp; + if ( wxGetTimeOfDay(&tp, (struct timezone *)NULL) != -1 ) + { + val *= tp.tv_sec; + return (val + (tp.tv_usec / 1000)); + } + else + { + wxLogError(_("wxGetTimeOfDay failed.")); + return 0; + } +#elif defined(HAVE_FTIME) + struct timeb tp; + + // ftime() is void and not int in some mingw32 headers, so don't + // test the return code (well, it shouldn't fail anyhow...) + (void)::ftime(&tp); + val *= tp.time; + return (val + tp.millitm); +#elif defined(__WXMAC__) + + static UInt64 gMilliAtStart = 0; + + Nanoseconds upTime = AbsoluteToNanoseconds( UpTime() ); + + if ( gMilliAtStart == 0 ) + { + time_t start = time(NULL); + gMilliAtStart = ((UInt64) start) * 1000000L; + gMilliAtStart -= upTime.lo / 1000 ; + gMilliAtStart -= ( ( (UInt64) upTime.hi ) << 32 ) / (1000 * 1000); + } + + UInt64 millival = gMilliAtStart; + millival += upTime.lo / (1000 * 1000); + millival += ( ( (UInt64) upTime.hi ) << 32 ) / (1000 * 1000); + val = millival; + + return val; +#else // no gettimeofday() nor ftime() + // We use wxGetLocalTime() to get the seconds since + // 00:00:00 Jan 1st 1970 and then whatever is available + // to get millisecond resolution. + // + // NOTE that this might lead to a problem if the clocks + // use different sources, so this approach should be + // avoided where possible. + + val *= wxGetLocalTime(); + +// GRG: This will go soon as all WIN32 seem to have ftime +// JACS: unfortunately not. WinCE doesn't have it. +#if defined (__WIN32__) + // If your platform/compiler needs to use two different functions + // to get ms resolution, please do NOT just shut off these warnings, + // drop me a line instead at + + // FIXME +#ifndef __WXWINCE__ + #warning "Possible clock skew bug in wxGetLocalTimeMillis()!" +#endif + + SYSTEMTIME st; + ::GetLocalTime(&st); + val += st.wMilliseconds; +#else // !Win32 + // If your platform/compiler does not support ms resolution please + // do NOT just shut off these warnings, drop me a line instead at + // + + #if defined(__VISUALC__) || defined (__WATCOMC__) + #pragma message("wxStopWatch will be up to second resolution!") + #elif defined(__BORLANDC__) + #pragma message "wxStopWatch will be up to second resolution!" + #else + #warning "wxStopWatch will be up to second resolution!" + #endif // compiler +#endif + + return val; + +#endif // time functions +} + +#else // !wxUSE_LONGLONG + +double wxGetLocalTimeMillis(void) +{ + return (double(clock()) / double(CLOCKS_PER_SEC)) * 1000.0; +} + +#endif // wxUSE_LONGLONG/!wxUSE_LONGLONG diff --git a/Source/3rd Party/wx/src/common/strconv.cpp b/Source/3rd Party/wx/src/common/strconv.cpp index 18b098f2e..102462916 100644 --- a/Source/3rd Party/wx/src/common/strconv.cpp +++ b/Source/3rd Party/wx/src/common/strconv.cpp @@ -1,3742 +1,3742 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/strconv.cpp -// Purpose: Unicode conversion classes -// Author: Ove Kaaven, Robert Roebling, Vadim Zeitlin, Vaclav Slavik, -// Ryan Norton, Fredrik Roubert (UTF7) -// Modified by: -// Created: 29/01/98 -// RCS-ID: $Id: strconv.cpp 64156 2010-04-27 08:52:30Z VZ $ -// Copyright: (c) 1999 Ove Kaaven, Robert Roebling, Vaclav Slavik -// (c) 2000-2003 Vadim Zeitlin -// (c) 2004 Ryan Norton, Fredrik Roubert -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifndef WX_PRECOMP - #ifdef __WXMSW__ - #include "wx/msw/missing.h" - #endif - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" - #include "wx/hashmap.h" -#endif - -#include "wx/strconv.h" - -#if wxUSE_WCHAR_T - -#ifdef __WINDOWS__ - #include "wx/msw/private.h" -#endif - -#ifndef __WXWINCE__ -#include -#endif - -#include -#include -#include - -#if defined(__WIN32__) && !defined(__WXMICROWIN__) - #define wxHAVE_WIN32_MB2WC -#endif - -#ifdef __SALFORDC__ - #include -#endif - -#ifdef HAVE_ICONV - #include - #include "wx/thread.h" -#endif - -#include "wx/encconv.h" -#include "wx/fontmap.h" - -#ifdef __WXMAC__ -#ifndef __DARWIN__ -#include -#include -#include -#endif - -// includes Mac headers -#include "wx/mac/private.h" -#include "wx/thread.h" - -#endif - - -#define TRACE_STRCONV _T("strconv") - -// WC_UTF16 is defined only if sizeof(wchar_t) == 2, otherwise it's supposed to -// be 4 bytes -#if SIZEOF_WCHAR_T == 2 - #define WC_UTF16 -#endif - - -// ============================================================================ -// implementation -// ============================================================================ - -// helper function of cMB2WC(): check if n bytes at this location are all NUL -static bool NotAllNULs(const char *p, size_t n) -{ - while ( n && *p++ == '\0' ) - n--; - - return n != 0; -} - -// ---------------------------------------------------------------------------- -// UTF-16 en/decoding to/from UCS-4 with surrogates handling -// ---------------------------------------------------------------------------- - -static size_t encode_utf16(wxUint32 input, wxUint16 *output) -{ - if (input <= 0xffff) - { - if (output) - *output = (wxUint16) input; - - return 1; - } - else if (input >= 0x110000) - { - return wxCONV_FAILED; - } - else - { - if (output) - { - *output++ = (wxUint16) ((input >> 10) + 0xd7c0); - *output = (wxUint16) ((input & 0x3ff) + 0xdc00); - } - - return 2; - } -} - -static size_t decode_utf16(const wxUint16* input, wxUint32& output) -{ - if ((*input < 0xd800) || (*input > 0xdfff)) - { - output = *input; - return 1; - } - else if ((input[1] < 0xdc00) || (input[1] > 0xdfff)) - { - output = *input; - return wxCONV_FAILED; - } - else - { - output = ((input[0] - 0xd7c0) << 10) + (input[1] - 0xdc00); - return 2; - } -} - -#ifdef WC_UTF16 - typedef wchar_t wxDecodeSurrogate_t; -#else // !WC_UTF16 - typedef wxUint16 wxDecodeSurrogate_t; -#endif // WC_UTF16/!WC_UTF16 - -// returns the next UTF-32 character from the wchar_t buffer and advances the -// pointer to the character after this one -// -// if an invalid character is found, *pSrc is set to NULL, the caller must -// check for this -static wxUint32 wxDecodeSurrogate(const wxDecodeSurrogate_t **pSrc) -{ - wxUint32 out; - const size_t - n = decode_utf16(wx_reinterpret_cast(const wxUint16 *, *pSrc), out); - if ( n == wxCONV_FAILED ) - *pSrc = NULL; - else - *pSrc += n; - - return out; -} - -// ---------------------------------------------------------------------------- -// wxMBConv -// ---------------------------------------------------------------------------- - -size_t -wxMBConv::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - // although new conversion classes are supposed to implement this function - // directly, the existins ones only implement the old MB2WC() and so, to - // avoid to have to rewrite all conversion classes at once, we provide a - // default (but not efficient) implementation of this one in terms of the - // old function by copying the input to ensure that it's NUL-terminated and - // then using MB2WC() to convert it - - // the number of chars [which would be] written to dst [if it were not NULL] - size_t dstWritten = 0; - - // the number of NULs terminating this string - size_t nulLen = 0; // not really needed, but just to avoid warnings - - // if we were not given the input size we just have to assume that the - // string is properly terminated as we have no way of knowing how long it - // is anyhow, but if we do have the size check whether there are enough - // NULs at the end - wxCharBuffer bufTmp; - const char *srcEnd; - if ( srcLen != wxNO_LEN ) - { - // we need to know how to find the end of this string - nulLen = GetMBNulLen(); - if ( nulLen == wxCONV_FAILED ) - return wxCONV_FAILED; - - // if there are enough NULs we can avoid the copy - if ( srcLen < nulLen || NotAllNULs(src + srcLen - nulLen, nulLen) ) - { - // make a copy in order to properly NUL-terminate the string - bufTmp = wxCharBuffer(srcLen + nulLen - 1 /* 1 will be added */); - char * const p = bufTmp.data(); - memcpy(p, src, srcLen); - for ( char *s = p + srcLen; s < p + srcLen + nulLen; s++ ) - *s = '\0'; - - src = bufTmp; - } - - srcEnd = src + srcLen; - } - else // quit after the first loop iteration - { - srcEnd = NULL; - } - - for ( ;; ) - { - // try to convert the current chunk - size_t lenChunk = MB2WC(NULL, src, 0); - if ( lenChunk == wxCONV_FAILED ) - return wxCONV_FAILED; - - lenChunk++; // for the L'\0' at the end of this chunk - - dstWritten += lenChunk; - - if ( lenChunk == 1 ) - { - // nothing left in the input string, conversion succeeded - break; - } - - if ( dst ) - { - if ( dstWritten > dstLen ) - return wxCONV_FAILED; - - if ( MB2WC(dst, src, lenChunk) == wxCONV_FAILED ) - return wxCONV_FAILED; - - dst += lenChunk; - } - - if ( !srcEnd ) - { - // we convert just one chunk in this case as this is the entire - // string anyhow - break; - } - - // advance the input pointer past the end of this chunk - while ( NotAllNULs(src, nulLen) ) - { - // notice that we must skip over multiple bytes here as we suppose - // that if NUL takes 2 or 4 bytes, then all the other characters do - // too and so if advanced by a single byte we might erroneously - // detect sequences of NUL bytes in the middle of the input - src += nulLen; - } - - src += nulLen; // skipping over its terminator as well - - // note that ">=" (and not just "==") is needed here as the terminator - // we skipped just above could be inside or just after the buffer - // delimited by inEnd - if ( src >= srcEnd ) - break; - } - - return dstWritten; -} - -size_t -wxMBConv::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - // the number of chars [which would be] written to dst [if it were not NULL] - size_t dstWritten = 0; - - // make a copy of the input string unless it is already properly - // NUL-terminated - // - // if we don't know its length we have no choice but to assume that it is, - // indeed, properly terminated - wxWCharBuffer bufTmp; - if ( srcLen == wxNO_LEN ) - { - srcLen = wxWcslen(src) + 1; - } - else if ( srcLen != 0 && src[srcLen - 1] != L'\0' ) - { - // make a copy in order to properly NUL-terminate the string - bufTmp = wxWCharBuffer(srcLen); - memcpy(bufTmp.data(), src, srcLen * sizeof(wchar_t)); - src = bufTmp; - } - - const size_t lenNul = GetMBNulLen(); - for ( const wchar_t * const srcEnd = src + srcLen; - src < srcEnd; - src += wxWcslen(src) + 1 /* skip L'\0' too */ ) - { - // try to convert the current chunk - size_t lenChunk = WC2MB(NULL, src, 0); - - if ( lenChunk == wxCONV_FAILED ) - return wxCONV_FAILED; - - lenChunk += lenNul; - dstWritten += lenChunk; - - if ( dst ) - { - if ( dstWritten > dstLen ) - return wxCONV_FAILED; - - if ( WC2MB(dst, src, lenChunk) == wxCONV_FAILED ) - return wxCONV_FAILED; - - dst += lenChunk; - } - } - - return dstWritten; -} - -size_t wxMBConv::MB2WC(wchar_t *outBuff, const char *inBuff, size_t outLen) const -{ - size_t rc = ToWChar(outBuff, outLen, inBuff); - if ( rc != wxCONV_FAILED ) - { - // ToWChar() returns the buffer length, i.e. including the trailing - // NUL, while this method doesn't take it into account - rc--; - } - - return rc; -} - -size_t wxMBConv::WC2MB(char *outBuff, const wchar_t *inBuff, size_t outLen) const -{ - size_t rc = FromWChar(outBuff, outLen, inBuff); - if ( rc != wxCONV_FAILED ) - { - rc -= GetMBNulLen(); - } - - return rc; -} - -wxMBConv::~wxMBConv() -{ - // nothing to do here (necessary for Darwin linking probably) -} - -const wxWCharBuffer wxMBConv::cMB2WC(const char *psz) const -{ - if ( psz ) - { - // calculate the length of the buffer needed first - const size_t nLen = MB2WC(NULL, psz, 0); - if ( nLen != wxCONV_FAILED ) - { - // now do the actual conversion - wxWCharBuffer buf(nLen /* +1 added implicitly */); - - // +1 for the trailing NULL - if ( MB2WC(buf.data(), psz, nLen + 1) != wxCONV_FAILED ) - return buf; - } - } - - return wxWCharBuffer(); -} - -const wxCharBuffer wxMBConv::cWC2MB(const wchar_t *pwz) const -{ - if ( pwz ) - { - const size_t nLen = WC2MB(NULL, pwz, 0); - if ( nLen != wxCONV_FAILED ) - { - // extra space for trailing NUL(s) - static const size_t extraLen = GetMaxMBNulLen(); - - wxCharBuffer buf(nLen + extraLen - 1); - if ( WC2MB(buf.data(), pwz, nLen + extraLen) != wxCONV_FAILED ) - return buf; - } - } - - return wxCharBuffer(); -} - -const wxWCharBuffer -wxMBConv::cMB2WC(const char *inBuff, size_t inLen, size_t *outLen) const -{ - const size_t dstLen = ToWChar(NULL, 0, inBuff, inLen); - if ( dstLen != wxCONV_FAILED ) - { - wxWCharBuffer wbuf(dstLen - 1); - if ( ToWChar(wbuf.data(), dstLen, inBuff, inLen) != wxCONV_FAILED ) - { - if ( outLen ) - { - *outLen = dstLen; - if ( wbuf[dstLen - 1] == L'\0' ) - (*outLen)--; - } - - return wbuf; - } - } - - if ( outLen ) - *outLen = 0; - - return wxWCharBuffer(); -} - -const wxCharBuffer -wxMBConv::cWC2MB(const wchar_t *inBuff, size_t inLen, size_t *outLen) const -{ - size_t dstLen = FromWChar(NULL, 0, inBuff, inLen); - if ( dstLen != wxCONV_FAILED ) - { - // special case of empty input: can't allocate 0 size buffer below as - // wxCharBuffer insists on NUL-terminating it - wxCharBuffer buf(dstLen ? dstLen - 1 : 1); - if ( FromWChar(buf.data(), dstLen, inBuff, inLen) != wxCONV_FAILED ) - { - if ( outLen ) - { - *outLen = dstLen; - - const size_t nulLen = GetMBNulLen(); - if ( dstLen >= nulLen && - !NotAllNULs(buf.data() + dstLen - nulLen, nulLen) ) - { - // in this case the output is NUL-terminated and we're not - // supposed to count NUL - *outLen -= nulLen; - } - } - - return buf; - } - } - - if ( outLen ) - *outLen = 0; - - return wxCharBuffer(); -} - -// ---------------------------------------------------------------------------- -// wxMBConvLibc -// ---------------------------------------------------------------------------- - -size_t wxMBConvLibc::MB2WC(wchar_t *buf, const char *psz, size_t n) const -{ - return wxMB2WC(buf, psz, n); -} - -size_t wxMBConvLibc::WC2MB(char *buf, const wchar_t *psz, size_t n) const -{ - return wxWC2MB(buf, psz, n); -} - -// ---------------------------------------------------------------------------- -// wxConvBrokenFileNames -// ---------------------------------------------------------------------------- - -#ifdef __UNIX__ - -wxConvBrokenFileNames::wxConvBrokenFileNames(const wxChar *charset) -{ - if ( !charset || wxStricmp(charset, _T("UTF-8")) == 0 - || wxStricmp(charset, _T("UTF8")) == 0 ) - m_conv = new wxMBConvUTF8(wxMBConvUTF8::MAP_INVALID_UTF8_TO_PUA); - else - m_conv = new wxCSConv(charset); -} - -#endif // __UNIX__ - -// ---------------------------------------------------------------------------- -// UTF-7 -// ---------------------------------------------------------------------------- - -// Implementation (C) 2004 Fredrik Roubert - -// -// BASE64 decoding table -// -static const unsigned char utf7unb64[] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, - 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, - 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, - 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, - 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, - 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, - 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, - 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -size_t wxMBConvUTF7::MB2WC(wchar_t *buf, const char *psz, size_t n) const -{ - size_t len = 0; - - while ( *psz && (!buf || (len < n)) ) - { - unsigned char cc = *psz++; - if (cc != '+') - { - // plain ASCII char - if (buf) - *buf++ = cc; - len++; - } - else if (*psz == '-') - { - // encoded plus sign - if (buf) - *buf++ = cc; - len++; - psz++; - } - else // start of BASE64 encoded string - { - bool lsb, ok; - unsigned int d, l; - for ( ok = lsb = false, d = 0, l = 0; - (cc = utf7unb64[(unsigned char)*psz]) != 0xff; - psz++ ) - { - d <<= 6; - d += cc; - for (l += 6; l >= 8; lsb = !lsb) - { - unsigned char c = (unsigned char)((d >> (l -= 8)) % 256); - if (lsb) - { - if (buf) - *buf++ |= c; - len ++; - } - else - { - if (buf) - *buf = (wchar_t)(c << 8); - } - - ok = true; - } - } - - if ( !ok ) - { - // in valid UTF7 we should have valid characters after '+' - return wxCONV_FAILED; - } - - if (*psz == '-') - psz++; - } - } - - if ( buf && (len < n) ) - *buf = '\0'; - - return len; -} - -// -// BASE64 encoding table -// -static const unsigned char utf7enb64[] = -{ - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', - 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', - 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', - 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', - 'w', 'x', 'y', 'z', '0', '1', '2', '3', - '4', '5', '6', '7', '8', '9', '+', '/' -}; - -// -// UTF-7 encoding table -// -// 0 - Set D (directly encoded characters) -// 1 - Set O (optional direct characters) -// 2 - whitespace characters (optional) -// 3 - special characters -// -static const unsigned char utf7encode[128] = -{ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 3, 0, 0, 0, 3, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1, 1, 1, - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 3, 3 -}; - -size_t wxMBConvUTF7::WC2MB(char *buf, const wchar_t *psz, size_t n) const -{ - size_t len = 0; - - while (*psz && ((!buf) || (len < n))) - { - wchar_t cc = *psz++; - if (cc < 0x80 && utf7encode[cc] < 1) - { - // plain ASCII char - if (buf) - *buf++ = (char)cc; - - len++; - } -#ifndef WC_UTF16 - else if (((wxUint32)cc) > 0xffff) - { - // no surrogate pair generation (yet?) - return wxCONV_FAILED; - } -#endif - else - { - if (buf) - *buf++ = '+'; - - len++; - if (cc != '+') - { - // BASE64 encode string - unsigned int lsb, d, l; - for (d = 0, l = 0; /*nothing*/; psz++) - { - for (lsb = 0; lsb < 2; lsb ++) - { - d <<= 8; - d += lsb ? cc & 0xff : (cc & 0xff00) >> 8; - - for (l += 8; l >= 6; ) - { - l -= 6; - if (buf) - *buf++ = utf7enb64[(d >> l) % 64]; - len++; - } - } - - cc = *psz; - if (!(cc) || (cc < 0x80 && utf7encode[cc] < 1)) - break; - } - - if (l != 0) - { - if (buf) - *buf++ = utf7enb64[((d % 16) << (6 - l)) % 64]; - - len++; - } - } - - if (buf) - *buf++ = '-'; - len++; - } - } - - if (buf && (len < n)) - *buf = 0; - - return len; -} - -// ---------------------------------------------------------------------------- -// UTF-8 -// ---------------------------------------------------------------------------- - -static wxUint32 utf8_max[]= - { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff, 0xffffffff }; - -// boundaries of the private use area we use to (temporarily) remap invalid -// characters invalid in a UTF-8 encoded string -const wxUint32 wxUnicodePUA = 0x100000; -const wxUint32 wxUnicodePUAEnd = wxUnicodePUA + 256; - -size_t wxMBConvUTF8::MB2WC(wchar_t *buf, const char *psz, size_t n) const -{ - size_t len = 0; - - while (*psz && ((!buf) || (len < n))) - { - const char *opsz = psz; - bool invalid = false; - unsigned char cc = *psz++, fc = cc; - unsigned cnt; - for (cnt = 0; fc & 0x80; cnt++) - fc <<= 1; - - if (!cnt) - { - // plain ASCII char - if (buf) - *buf++ = cc; - len++; - - // escape the escape character for octal escapes - if ((m_options & MAP_INVALID_UTF8_TO_OCTAL) - && cc == '\\' && (!buf || len < n)) - { - if (buf) - *buf++ = cc; - len++; - } - } - else - { - cnt--; - if (!cnt) - { - // invalid UTF-8 sequence - invalid = true; - } - else - { - unsigned ocnt = cnt - 1; - wxUint32 res = cc & (0x3f >> cnt); - while (cnt--) - { - cc = *psz; - if ((cc & 0xC0) != 0x80) - { - // invalid UTF-8 sequence - invalid = true; - break; - } - - psz++; - res = (res << 6) | (cc & 0x3f); - } - - if (invalid || res <= utf8_max[ocnt]) - { - // illegal UTF-8 encoding - invalid = true; - } - else if ((m_options & MAP_INVALID_UTF8_TO_PUA) && - res >= wxUnicodePUA && res < wxUnicodePUAEnd) - { - // if one of our PUA characters turns up externally - // it must also be treated as an illegal sequence - // (a bit like you have to escape an escape character) - invalid = true; - } - else - { -#ifdef WC_UTF16 - // cast is ok because wchar_t == wxUuint16 if WC_UTF16 - size_t pa = encode_utf16(res, (wxUint16 *)buf); - if (pa == wxCONV_FAILED) - { - invalid = true; - } - else - { - if (buf) - buf += pa; - len += pa; - } -#else // !WC_UTF16 - if (buf) - *buf++ = (wchar_t)res; - len++; -#endif // WC_UTF16/!WC_UTF16 - } - } - - if (invalid) - { - if (m_options & MAP_INVALID_UTF8_TO_PUA) - { - while (opsz < psz && (!buf || len < n)) - { -#ifdef WC_UTF16 - // cast is ok because wchar_t == wxUuint16 if WC_UTF16 - size_t pa = encode_utf16((unsigned char)*opsz + wxUnicodePUA, (wxUint16 *)buf); - wxASSERT(pa != wxCONV_FAILED); - if (buf) - buf += pa; - opsz++; - len += pa; -#else - if (buf) - *buf++ = (wchar_t)(wxUnicodePUA + (unsigned char)*opsz); - opsz++; - len++; -#endif - } - } - else if (m_options & MAP_INVALID_UTF8_TO_OCTAL) - { - while (opsz < psz && (!buf || len < n)) - { - if ( buf && len + 3 < n ) - { - unsigned char on = *opsz; - *buf++ = L'\\'; - *buf++ = (wchar_t)( L'0' + on / 0100 ); - *buf++ = (wchar_t)( L'0' + (on % 0100) / 010 ); - *buf++ = (wchar_t)( L'0' + on % 010 ); - } - - opsz++; - len += 4; - } - } - else // MAP_INVALID_UTF8_NOT - { - return wxCONV_FAILED; - } - } - } - } - - if (buf && (len < n)) - *buf = 0; - - return len; -} - -static inline bool isoctal(wchar_t wch) -{ - return L'0' <= wch && wch <= L'7'; -} - -size_t wxMBConvUTF8::WC2MB(char *buf, const wchar_t *psz, size_t n) const -{ - size_t len = 0; - - while (*psz && ((!buf) || (len < n))) - { - wxUint32 cc; - -#ifdef WC_UTF16 - // cast is ok for WC_UTF16 - size_t pa = decode_utf16((const wxUint16 *)psz, cc); - psz += (pa == wxCONV_FAILED) ? 1 : pa; -#else - cc = (*psz++) & 0x7fffffff; -#endif - - if ( (m_options & MAP_INVALID_UTF8_TO_PUA) - && cc >= wxUnicodePUA && cc < wxUnicodePUAEnd ) - { - if (buf) - *buf++ = (char)(cc - wxUnicodePUA); - len++; - } - else if ( (m_options & MAP_INVALID_UTF8_TO_OCTAL) - && cc == L'\\' && psz[0] == L'\\' ) - { - if (buf) - *buf++ = (char)cc; - psz++; - len++; - } - else if ( (m_options & MAP_INVALID_UTF8_TO_OCTAL) && - cc == L'\\' && - isoctal(psz[0]) && isoctal(psz[1]) && isoctal(psz[2]) ) - { - if (buf) - { - *buf++ = (char) ((psz[0] - L'0') * 0100 + - (psz[1] - L'0') * 010 + - (psz[2] - L'0')); - } - - psz += 3; - len++; - } - else - { - unsigned cnt; - for (cnt = 0; cc > utf8_max[cnt]; cnt++) - { - } - - if (!cnt) - { - // plain ASCII char - if (buf) - *buf++ = (char) cc; - len++; - } - else - { - len += cnt + 1; - if (buf) - { - *buf++ = (char) ((-128 >> cnt) | ((cc >> (cnt * 6)) & (0x3f >> cnt))); - while (cnt--) - *buf++ = (char) (0x80 | ((cc >> (cnt * 6)) & 0x3f)); - } - } - } - } - - if (buf && (len < n)) - *buf = 0; - - return len; -} - -// ============================================================================ -// UTF-16 -// ============================================================================ - -#ifdef WORDS_BIGENDIAN - #define wxMBConvUTF16straight wxMBConvUTF16BE - #define wxMBConvUTF16swap wxMBConvUTF16LE -#else - #define wxMBConvUTF16swap wxMBConvUTF16BE - #define wxMBConvUTF16straight wxMBConvUTF16LE -#endif - -/* static */ -size_t wxMBConvUTF16Base::GetLength(const char *src, size_t srcLen) -{ - if ( srcLen == wxNO_LEN ) - { - // count the number of bytes in input, including the trailing NULs - const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); - for ( srcLen = 1; *inBuff++; srcLen++ ) - ; - - srcLen *= BYTES_PER_CHAR; - } - else // we already have the length - { - // we can only convert an entire number of UTF-16 characters - if ( srcLen % BYTES_PER_CHAR ) - return wxCONV_FAILED; - } - - return srcLen; -} - -// case when in-memory representation is UTF-16 too -#ifdef WC_UTF16 - -// ---------------------------------------------------------------------------- -// conversions without endianness change -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF16straight::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - // set up the scene for using memcpy() (which is presumably more efficient - // than copying the bytes one by one) - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - const size_t inLen = srcLen / BYTES_PER_CHAR; - if ( dst ) - { - if ( dstLen < inLen ) - return wxCONV_FAILED; - - memcpy(dst, src, srcLen); - } - - return inLen; -} - -size_t -wxMBConvUTF16straight::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - srcLen *= BYTES_PER_CHAR; - - if ( dst ) - { - if ( dstLen < srcLen ) - return wxCONV_FAILED; - - memcpy(dst, src, srcLen); - } - - return srcLen; -} - -// ---------------------------------------------------------------------------- -// endian-reversing conversions -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF16swap::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - srcLen /= BYTES_PER_CHAR; - - if ( dst ) - { - if ( dstLen < srcLen ) - return wxCONV_FAILED; - - const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); - for ( size_t n = 0; n < srcLen; n++, inBuff++ ) - { - *dst++ = wxUINT16_SWAP_ALWAYS(*inBuff); - } - } - - return srcLen; -} - -size_t -wxMBConvUTF16swap::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - srcLen *= BYTES_PER_CHAR; - - if ( dst ) - { - if ( dstLen < srcLen ) - return wxCONV_FAILED; - - wxUint16 *outBuff = wx_reinterpret_cast(wxUint16 *, dst); - for ( size_t n = 0; n < srcLen; n += BYTES_PER_CHAR, src++ ) - { - *outBuff++ = wxUINT16_SWAP_ALWAYS(*src); - } - } - - return srcLen; -} - -#else // !WC_UTF16: wchar_t is UTF-32 - -// ---------------------------------------------------------------------------- -// conversions without endianness change -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF16straight::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - const size_t inLen = srcLen / BYTES_PER_CHAR; - if ( !dst ) - { - // optimization: return maximal space which could be needed for this - // string even if the real size could be smaller if the buffer contains - // any surrogates - return inLen; - } - - size_t outLen = 0; - const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); - for ( const wxUint16 * const inEnd = inBuff + inLen; inBuff < inEnd; ) - { - const wxUint32 ch = wxDecodeSurrogate(&inBuff); - if ( !inBuff ) - return wxCONV_FAILED; - - if ( ++outLen > dstLen ) - return wxCONV_FAILED; - - *dst++ = ch; - } - - - return outLen; -} - -size_t -wxMBConvUTF16straight::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - size_t outLen = 0; - wxUint16 *outBuff = wx_reinterpret_cast(wxUint16 *, dst); - for ( size_t n = 0; n < srcLen; n++ ) - { - wxUint16 cc[2]; - const size_t numChars = encode_utf16(*src++, cc); - if ( numChars == wxCONV_FAILED ) - return wxCONV_FAILED; - - outLen += numChars * BYTES_PER_CHAR; - if ( outBuff ) - { - if ( outLen > dstLen ) - return wxCONV_FAILED; - - *outBuff++ = cc[0]; - if ( numChars == 2 ) - { - // second character of a surrogate - *outBuff++ = cc[1]; - } - } - } - - return outLen; -} - -// ---------------------------------------------------------------------------- -// endian-reversing conversions -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF16swap::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - const size_t inLen = srcLen / BYTES_PER_CHAR; - if ( !dst ) - { - // optimization: return maximal space which could be needed for this - // string even if the real size could be smaller if the buffer contains - // any surrogates - return inLen; - } - - size_t outLen = 0; - const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); - for ( const wxUint16 * const inEnd = inBuff + inLen; inBuff < inEnd; ) - { - wxUint32 ch; - wxUint16 tmp[2]; - - tmp[0] = wxUINT16_SWAP_ALWAYS(*inBuff); - inBuff++; - tmp[1] = wxUINT16_SWAP_ALWAYS(*inBuff); - - const size_t numChars = decode_utf16(tmp, ch); - if ( numChars == wxCONV_FAILED ) - return wxCONV_FAILED; - - if ( numChars == 2 ) - inBuff++; - - if ( ++outLen > dstLen ) - return wxCONV_FAILED; - - *dst++ = ch; - } - - - return outLen; -} - -size_t -wxMBConvUTF16swap::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - size_t outLen = 0; - wxUint16 *outBuff = wx_reinterpret_cast(wxUint16 *, dst); - for ( const wchar_t *srcEnd = src + srcLen; src < srcEnd; src++ ) - { - wxUint16 cc[2]; - const size_t numChars = encode_utf16(*src, cc); - if ( numChars == wxCONV_FAILED ) - return wxCONV_FAILED; - - outLen += numChars * BYTES_PER_CHAR; - if ( outBuff ) - { - if ( outLen > dstLen ) - return wxCONV_FAILED; - - *outBuff++ = wxUINT16_SWAP_ALWAYS(cc[0]); - if ( numChars == 2 ) - { - // second character of a surrogate - *outBuff++ = wxUINT16_SWAP_ALWAYS(cc[1]); - } - } - } - - return outLen; -} - -#endif // WC_UTF16/!WC_UTF16 - - -// ============================================================================ -// UTF-32 -// ============================================================================ - -#ifdef WORDS_BIGENDIAN - #define wxMBConvUTF32straight wxMBConvUTF32BE - #define wxMBConvUTF32swap wxMBConvUTF32LE -#else - #define wxMBConvUTF32swap wxMBConvUTF32BE - #define wxMBConvUTF32straight wxMBConvUTF32LE -#endif - - -WXDLLIMPEXP_DATA_BASE(wxMBConvUTF32LE) wxConvUTF32LE; -WXDLLIMPEXP_DATA_BASE(wxMBConvUTF32BE) wxConvUTF32BE; - -/* static */ -size_t wxMBConvUTF32Base::GetLength(const char *src, size_t srcLen) -{ - if ( srcLen == wxNO_LEN ) - { - // count the number of bytes in input, including the trailing NULs - const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); - for ( srcLen = 1; *inBuff++; srcLen++ ) - ; - - srcLen *= BYTES_PER_CHAR; - } - else // we already have the length - { - // we can only convert an entire number of UTF-32 characters - if ( srcLen % BYTES_PER_CHAR ) - return wxCONV_FAILED; - } - - return srcLen; -} - -// case when in-memory representation is UTF-16 -#ifdef WC_UTF16 - -// ---------------------------------------------------------------------------- -// conversions without endianness change -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF32straight::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); - const size_t inLen = srcLen / BYTES_PER_CHAR; - size_t outLen = 0; - for ( size_t n = 0; n < inLen; n++ ) - { - wxUint16 cc[2]; - const size_t numChars = encode_utf16(*inBuff++, cc); - if ( numChars == wxCONV_FAILED ) - return wxCONV_FAILED; - - outLen += numChars; - if ( dst ) - { - if ( outLen > dstLen ) - return wxCONV_FAILED; - - *dst++ = cc[0]; - if ( numChars == 2 ) - { - // second character of a surrogate - *dst++ = cc[1]; - } - } - } - - return outLen; -} - -size_t -wxMBConvUTF32straight::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - if ( !dst ) - { - // optimization: return maximal space which could be needed for this - // string instead of the exact amount which could be less if there are - // any surrogates in the input - // - // we consider that surrogates are rare enough to make it worthwhile to - // avoid running the loop below at the cost of slightly extra memory - // consumption - return srcLen * BYTES_PER_CHAR; - } - - wxUint32 *outBuff = wx_reinterpret_cast(wxUint32 *, dst); - size_t outLen = 0; - for ( const wchar_t * const srcEnd = src + srcLen; src < srcEnd; ) - { - const wxUint32 ch = wxDecodeSurrogate(&src); - if ( !src ) - return wxCONV_FAILED; - - outLen += BYTES_PER_CHAR; - - if ( outLen > dstLen ) - return wxCONV_FAILED; - - *outBuff++ = ch; - } - - return outLen; -} - -// ---------------------------------------------------------------------------- -// endian-reversing conversions -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF32swap::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); - const size_t inLen = srcLen / BYTES_PER_CHAR; - size_t outLen = 0; - for ( size_t n = 0; n < inLen; n++, inBuff++ ) - { - wxUint16 cc[2]; - const size_t numChars = encode_utf16(wxUINT32_SWAP_ALWAYS(*inBuff), cc); - if ( numChars == wxCONV_FAILED ) - return wxCONV_FAILED; - - outLen += numChars; - if ( dst ) - { - if ( outLen > dstLen ) - return wxCONV_FAILED; - - *dst++ = cc[0]; - if ( numChars == 2 ) - { - // second character of a surrogate - *dst++ = cc[1]; - } - } - } - - return outLen; -} - -size_t -wxMBConvUTF32swap::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - if ( !dst ) - { - // optimization: return maximal space which could be needed for this - // string instead of the exact amount which could be less if there are - // any surrogates in the input - // - // we consider that surrogates are rare enough to make it worthwhile to - // avoid running the loop below at the cost of slightly extra memory - // consumption - return srcLen*BYTES_PER_CHAR; - } - - wxUint32 *outBuff = wx_reinterpret_cast(wxUint32 *, dst); - size_t outLen = 0; - for ( const wchar_t * const srcEnd = src + srcLen; src < srcEnd; ) - { - const wxUint32 ch = wxDecodeSurrogate(&src); - if ( !src ) - return wxCONV_FAILED; - - outLen += BYTES_PER_CHAR; - - if ( outLen > dstLen ) - return wxCONV_FAILED; - - *outBuff++ = wxUINT32_SWAP_ALWAYS(ch); - } - - return outLen; -} - -#else // !WC_UTF16: wchar_t is UTF-32 - -// ---------------------------------------------------------------------------- -// conversions without endianness change -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF32straight::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - // use memcpy() as it should be much faster than hand-written loop - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - const size_t inLen = srcLen/BYTES_PER_CHAR; - if ( dst ) - { - if ( dstLen < inLen ) - return wxCONV_FAILED; - - memcpy(dst, src, srcLen); - } - - return inLen; -} - -size_t -wxMBConvUTF32straight::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - srcLen *= BYTES_PER_CHAR; - - if ( dst ) - { - if ( dstLen < srcLen ) - return wxCONV_FAILED; - - memcpy(dst, src, srcLen); - } - - return srcLen; -} - -// ---------------------------------------------------------------------------- -// endian-reversing conversions -// ---------------------------------------------------------------------------- - -size_t -wxMBConvUTF32swap::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - srcLen = GetLength(src, srcLen); - if ( srcLen == wxNO_LEN ) - return wxCONV_FAILED; - - srcLen /= BYTES_PER_CHAR; - - if ( dst ) - { - if ( dstLen < srcLen ) - return wxCONV_FAILED; - - const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); - for ( size_t n = 0; n < srcLen; n++, inBuff++ ) - { - *dst++ = wxUINT32_SWAP_ALWAYS(*inBuff); - } - } - - return srcLen; -} - -size_t -wxMBConvUTF32swap::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - srcLen *= BYTES_PER_CHAR; - - if ( dst ) - { - if ( dstLen < srcLen ) - return wxCONV_FAILED; - - wxUint32 *outBuff = wx_reinterpret_cast(wxUint32 *, dst); - for ( size_t n = 0; n < srcLen; n += BYTES_PER_CHAR, src++ ) - { - *outBuff++ = wxUINT32_SWAP_ALWAYS(*src); - } - } - - return srcLen; -} - -#endif // WC_UTF16/!WC_UTF16 - - -// ============================================================================ -// The classes doing conversion using the iconv_xxx() functions -// ============================================================================ - -#ifdef HAVE_ICONV - -// VS: glibc 2.1.3 is broken in that iconv() conversion to/from UCS4 fails with -// E2BIG if output buffer is _exactly_ as big as needed. Such case is -// (unless there's yet another bug in glibc) the only case when iconv() -// returns with (size_t)-1 (which means error) and says there are 0 bytes -// left in the input buffer -- when _real_ error occurs, -// bytes-left-in-input buffer is non-zero. Hence, this alternative test for -// iconv() failure. -// [This bug does not appear in glibc 2.2.] -#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ <= 1 -#define ICONV_FAILED(cres, bufLeft) ((cres == (size_t)-1) && \ - (errno != E2BIG || bufLeft != 0)) -#else -#define ICONV_FAILED(cres, bufLeft) (cres == (size_t)-1) -#endif - -#define ICONV_CHAR_CAST(x) ((ICONV_CONST char **)(x)) - -#define ICONV_T_INVALID ((iconv_t)-1) - -#if SIZEOF_WCHAR_T == 4 - #define WC_BSWAP wxUINT32_SWAP_ALWAYS - #define WC_ENC wxFONTENCODING_UTF32 -#elif SIZEOF_WCHAR_T == 2 - #define WC_BSWAP wxUINT16_SWAP_ALWAYS - #define WC_ENC wxFONTENCODING_UTF16 -#else // sizeof(wchar_t) != 2 nor 4 - // does this ever happen? - #error "Unknown sizeof(wchar_t): please report this to wx-dev@lists.wxwindows.org" -#endif - -// ---------------------------------------------------------------------------- -// wxMBConv_iconv: encapsulates an iconv character set -// ---------------------------------------------------------------------------- - -class wxMBConv_iconv : public wxMBConv -{ -public: - wxMBConv_iconv(const wxChar *name); - virtual ~wxMBConv_iconv(); - - virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const; - virtual size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const; - - // classify this encoding as explained in wxMBConv::GetMBNulLen() comment - virtual size_t GetMBNulLen() const; - - virtual wxMBConv *Clone() const - { - wxMBConv_iconv *p = new wxMBConv_iconv(m_name); - p->m_minMBCharWidth = m_minMBCharWidth; - return p; - } - - bool IsOk() const - { return (m2w != ICONV_T_INVALID) && (w2m != ICONV_T_INVALID); } - -protected: - // the iconv handlers used to translate from multibyte - // to wide char and in the other direction - iconv_t m2w, - w2m; - -#if wxUSE_THREADS - // guards access to m2w and w2m objects - wxMutex m_iconvMutex; -#endif - -private: - // the name (for iconv_open()) of a wide char charset -- if none is - // available on this machine, it will remain NULL - static wxString ms_wcCharsetName; - - // true if the wide char encoding we use (i.e. ms_wcCharsetName) has - // different endian-ness than the native one - static bool ms_wcNeedsSwap; - - - // name of the encoding handled by this conversion - wxString m_name; - - // cached result of GetMBNulLen(); set to 0 meaning "unknown" - // initially - size_t m_minMBCharWidth; -}; - -// make the constructor available for unit testing -WXDLLIMPEXP_BASE wxMBConv* new_wxMBConv_iconv( const wxChar* name ) -{ - wxMBConv_iconv* result = new wxMBConv_iconv( name ); - if ( !result->IsOk() ) - { - delete result; - return 0; - } - - return result; -} - -wxString wxMBConv_iconv::ms_wcCharsetName; -bool wxMBConv_iconv::ms_wcNeedsSwap = false; - -wxMBConv_iconv::wxMBConv_iconv(const wxChar *name) - : m_name(name) -{ - m_minMBCharWidth = 0; - - // iconv operates with chars, not wxChars, but luckily it uses only ASCII - // names for the charsets - const wxCharBuffer cname(wxString(name).ToAscii()); - - // check for charset that represents wchar_t: - if ( ms_wcCharsetName.empty() ) - { - wxLogTrace(TRACE_STRCONV, _T("Looking for wide char codeset:")); - -#if wxUSE_FONTMAP - const wxChar **names = wxFontMapperBase::GetAllEncodingNames(WC_ENC); -#else // !wxUSE_FONTMAP - static const wxChar *names_static[] = - { -#if SIZEOF_WCHAR_T == 4 - _T("UCS-4"), -#elif SIZEOF_WCHAR_T == 2 - _T("UCS-2"), -#endif - NULL - }; - const wxChar **names = names_static; -#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP - - for ( ; *names && ms_wcCharsetName.empty(); ++names ) - { - const wxString nameCS(*names); - - // first try charset with explicit bytesex info (e.g. "UCS-4LE"): - wxString nameXE(nameCS); - -#ifdef WORDS_BIGENDIAN - nameXE += _T("BE"); -#else // little endian - nameXE += _T("LE"); -#endif - - wxLogTrace(TRACE_STRCONV, _T(" trying charset \"%s\""), - nameXE.c_str()); - - m2w = iconv_open(nameXE.ToAscii(), cname); - if ( m2w == ICONV_T_INVALID ) - { - // try charset w/o bytesex info (e.g. "UCS4") - wxLogTrace(TRACE_STRCONV, _T(" trying charset \"%s\""), - nameCS.c_str()); - m2w = iconv_open(nameCS.ToAscii(), cname); - - // and check for bytesex ourselves: - if ( m2w != ICONV_T_INVALID ) - { - char buf[2], *bufPtr; - wchar_t wbuf[2], *wbufPtr; - size_t insz, outsz; - size_t res; - - buf[0] = 'A'; - buf[1] = 0; - wbuf[0] = 0; - insz = 2; - outsz = SIZEOF_WCHAR_T * 2; - wbufPtr = wbuf; - bufPtr = buf; - - res = iconv( - m2w, ICONV_CHAR_CAST(&bufPtr), &insz, - (char**)&wbufPtr, &outsz); - - if (ICONV_FAILED(res, insz)) - { - wxLogLastError(wxT("iconv")); - wxLogError(_("Conversion to charset '%s' doesn't work."), - nameCS.c_str()); - } - else // ok, can convert to this encoding, remember it - { - ms_wcCharsetName = nameCS; - ms_wcNeedsSwap = wbuf[0] != (wchar_t)buf[0]; - } - } - } - else // use charset not requiring byte swapping - { - ms_wcCharsetName = nameXE; - } - } - - wxLogTrace(TRACE_STRCONV, - wxT("iconv wchar_t charset is \"%s\"%s"), - ms_wcCharsetName.empty() ? _T("") - : ms_wcCharsetName.c_str(), - ms_wcNeedsSwap ? _T(" (needs swap)") - : _T("")); - } - else // we already have ms_wcCharsetName - { - m2w = iconv_open(ms_wcCharsetName.ToAscii(), cname); - } - - if ( ms_wcCharsetName.empty() ) - { - w2m = ICONV_T_INVALID; - } - else - { - w2m = iconv_open(cname, ms_wcCharsetName.ToAscii()); - if ( w2m == ICONV_T_INVALID ) - { - wxLogTrace(TRACE_STRCONV, - wxT("\"%s\" -> \"%s\" works but not the converse!?"), - ms_wcCharsetName.c_str(), cname.data()); - } - } -} - -wxMBConv_iconv::~wxMBConv_iconv() -{ - if ( m2w != ICONV_T_INVALID ) - iconv_close(m2w); - if ( w2m != ICONV_T_INVALID ) - iconv_close(w2m); -} - -size_t wxMBConv_iconv::MB2WC(wchar_t *buf, const char *psz, size_t n) const -{ - // find the string length: notice that must be done differently for - // NUL-terminated strings and UTF-16/32 which are terminated with 2/4 NULs - size_t inbuf; - const size_t nulLen = GetMBNulLen(); - switch ( nulLen ) - { - default: - return wxCONV_FAILED; - - case 1: - inbuf = strlen(psz); // arguably more optimized than our version - break; - - case 2: - case 4: - // for UTF-16/32 not only we need to have 2/4 consecutive NULs but - // they also have to start at character boundary and not span two - // adjacent characters - const char *p; - for ( p = psz; NotAllNULs(p, nulLen); p += nulLen ) - ; - inbuf = p - psz; - break; - } - -#if wxUSE_THREADS - // NB: iconv() is MT-safe, but each thread must use its own iconv_t handle. - // Unfortunately there are a couple of global wxCSConv objects such as - // wxConvLocal that are used all over wx code, so we have to make sure - // the handle is used by at most one thread at the time. Otherwise - // only a few wx classes would be safe to use from non-main threads - // as MB<->WC conversion would fail "randomly". - wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex); -#endif // wxUSE_THREADS - - size_t outbuf = n * SIZEOF_WCHAR_T; - size_t res, cres; - // VS: Use these instead of psz, buf because iconv() modifies its arguments: - wchar_t *bufPtr = buf; - const char *pszPtr = psz; - - if (buf) - { - // have destination buffer, convert there - cres = iconv(m2w, - ICONV_CHAR_CAST(&pszPtr), &inbuf, - (char**)&bufPtr, &outbuf); - res = n - (outbuf / SIZEOF_WCHAR_T); - - if (ms_wcNeedsSwap) - { - // convert to native endianness - for ( unsigned i = 0; i < res; i++ ) - buf[n] = WC_BSWAP(buf[i]); - } - - // NUL-terminate the string if there is any space left - if (res < n) - buf[res] = 0; - } - else - { - // no destination buffer... convert using temp buffer - // to calculate destination buffer requirement - wchar_t tbuf[8]; - res = 0; - - do - { - bufPtr = tbuf; - outbuf = 8 * SIZEOF_WCHAR_T; - - cres = iconv(m2w, - ICONV_CHAR_CAST(&pszPtr), &inbuf, - (char**)&bufPtr, &outbuf ); - - res += 8 - (outbuf / SIZEOF_WCHAR_T); - } - while ((cres == (size_t)-1) && (errno == E2BIG)); - } - - if (ICONV_FAILED(cres, inbuf)) - { - //VS: it is ok if iconv fails, hence trace only - wxLogTrace(TRACE_STRCONV, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode())); - return wxCONV_FAILED; - } - - return res; -} - -size_t wxMBConv_iconv::WC2MB(char *buf, const wchar_t *psz, size_t n) const -{ -#if wxUSE_THREADS - // NB: explained in MB2WC - wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex); -#endif - - size_t inlen = wxWcslen(psz); - size_t inbuf = inlen * SIZEOF_WCHAR_T; - size_t outbuf = n; - size_t res, cres; - - wchar_t *tmpbuf = 0; - - if (ms_wcNeedsSwap) - { - // need to copy to temp buffer to switch endianness - // (doing WC_BSWAP twice on the original buffer won't help, as it - // could be in read-only memory, or be accessed in some other thread) - tmpbuf = (wchar_t *)malloc(inbuf + SIZEOF_WCHAR_T); - for ( size_t i = 0; i < inlen; i++ ) - tmpbuf[n] = WC_BSWAP(psz[i]); - - tmpbuf[inlen] = L'\0'; - psz = tmpbuf; - } - - if (buf) - { - // have destination buffer, convert there - cres = iconv( w2m, ICONV_CHAR_CAST(&psz), &inbuf, &buf, &outbuf ); - - res = n - outbuf; - - // NB: iconv was given only wcslen(psz) characters on input, and so - // it couldn't convert the trailing zero. Let's do it ourselves - // if there's some room left for it in the output buffer. - if (res < n) - buf[0] = 0; - } - else - { - // no destination buffer: convert using temp buffer - // to calculate destination buffer requirement - char tbuf[16]; - res = 0; - do - { - buf = tbuf; - outbuf = 16; - - cres = iconv( w2m, ICONV_CHAR_CAST(&psz), &inbuf, &buf, &outbuf ); - - res += 16 - outbuf; - } - while ((cres == (size_t)-1) && (errno == E2BIG)); - } - - if (ms_wcNeedsSwap) - { - free(tmpbuf); - } - - if (ICONV_FAILED(cres, inbuf)) - { - wxLogTrace(TRACE_STRCONV, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode())); - return wxCONV_FAILED; - } - - return res; -} - -size_t wxMBConv_iconv::GetMBNulLen() const -{ - if ( m_minMBCharWidth == 0 ) - { - wxMBConv_iconv * const self = wxConstCast(this, wxMBConv_iconv); - -#if wxUSE_THREADS - // NB: explained in MB2WC - wxMutexLocker lock(self->m_iconvMutex); -#endif - - const wchar_t *wnul = L""; - char buf[8]; // should be enough for NUL in any encoding - size_t inLen = sizeof(wchar_t), - outLen = WXSIZEOF(buf); - char *inBuff = (char *)wnul; - char *outBuff = buf; - if ( iconv(w2m, ICONV_CHAR_CAST(&inBuff), &inLen, &outBuff, &outLen) == (size_t)-1 ) - { - self->m_minMBCharWidth = (size_t)-1; - } - else // ok - { - self->m_minMBCharWidth = outBuff - buf; - } - } - - return m_minMBCharWidth; -} - -#endif // HAVE_ICONV - - -// ============================================================================ -// Win32 conversion classes -// ============================================================================ - -#ifdef wxHAVE_WIN32_MB2WC - -// from utils.cpp -#if wxUSE_FONTMAP -extern WXDLLIMPEXP_BASE long wxCharsetToCodepage(const wxChar *charset); -extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding); -#endif - -class wxMBConv_win32 : public wxMBConv -{ -public: - wxMBConv_win32() - { - m_CodePage = CP_ACP; - m_minMBCharWidth = 0; - } - - wxMBConv_win32(const wxMBConv_win32& conv) - : wxMBConv() - { - m_CodePage = conv.m_CodePage; - m_minMBCharWidth = conv.m_minMBCharWidth; - } - -#if wxUSE_FONTMAP - wxMBConv_win32(const wxChar* name) - { - m_CodePage = wxCharsetToCodepage(name); - m_minMBCharWidth = 0; - } - - wxMBConv_win32(wxFontEncoding encoding) - { - m_CodePage = wxEncodingToCodepage(encoding); - m_minMBCharWidth = 0; - } -#endif // wxUSE_FONTMAP - - virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const - { - // note that we have to use MB_ERR_INVALID_CHARS flag as it without it - // the behaviour is not compatible with the Unix version (using iconv) - // and break the library itself, e.g. wxTextInputStream::NextChar() - // wouldn't work if reading an incomplete MB char didn't result in an - // error - // - // Moreover, MB_ERR_INVALID_CHARS is only supported on Win 2K SP4 or - // Win XP or newer and it is not supported for UTF-[78] so we always - // use our own conversions in this case. See - // http://blogs.msdn.com/michkap/archive/2005/04/19/409566.aspx - // http://msdn.microsoft.com/library/en-us/intl/unicode_17si.asp - if ( m_CodePage == CP_UTF8 ) - { - return wxConvUTF8.MB2WC(buf, psz, n); - } - - if ( m_CodePage == CP_UTF7 ) - { - return wxConvUTF7.MB2WC(buf, psz, n); - } - - int flags = 0; - if ( (m_CodePage < 50000 && m_CodePage != CP_SYMBOL) && - IsAtLeastWin2kSP4() ) - { - flags = MB_ERR_INVALID_CHARS; - } - - const size_t len = ::MultiByteToWideChar - ( - m_CodePage, // code page - flags, // flags: fall on error - psz, // input string - -1, // its length (NUL-terminated) - buf, // output string - buf ? n : 0 // size of output buffer - ); - if ( !len ) - { - // function totally failed - return wxCONV_FAILED; - } - - // if we were really converting and didn't use MB_ERR_INVALID_CHARS, - // check if we succeeded, by doing a double trip: - if ( !flags && buf ) - { - const size_t mbLen = strlen(psz); - wxCharBuffer mbBuf(mbLen); - if ( ::WideCharToMultiByte - ( - m_CodePage, - 0, - buf, - -1, - mbBuf.data(), - mbLen + 1, // size in bytes, not length - NULL, - NULL - ) == 0 || - strcmp(mbBuf, psz) != 0 ) - { - // we didn't obtain the same thing we started from, hence - // the conversion was lossy and we consider that it failed - return wxCONV_FAILED; - } - } - - // note that it returns count of written chars for buf != NULL and size - // of the needed buffer for buf == NULL so in either case the length of - // the string (which never includes the terminating NUL) is one less - return len - 1; - } - - virtual size_t WC2MB(char *buf, const wchar_t *pwz, size_t n) const - { - /* - we have a problem here: by default, WideCharToMultiByte() may - replace characters unrepresentable in the target code page with bad - quality approximations such as turning "1/2" symbol (U+00BD) into - "1" for the code pages which don't have it and we, obviously, want - to avoid this at any price - - the trouble is that this function does it _silently_, i.e. it won't - even tell us whether it did or not... Win98/2000 and higher provide - WC_NO_BEST_FIT_CHARS but it doesn't work for the older systems and - we have to resort to a round trip, i.e. check that converting back - results in the same string -- this is, of course, expensive but - otherwise we simply can't be sure to not garble the data. - */ - - // determine if we can rely on WC_NO_BEST_FIT_CHARS: according to MSDN - // it doesn't work with CJK encodings (which we test for rather roughly - // here...) nor with UTF-7/8 nor, of course, with Windows versions not - // supporting it - BOOL usedDef wxDUMMY_INITIALIZE(false); - BOOL *pUsedDef; - int flags; - if ( CanUseNoBestFit() && m_CodePage < 50000 ) - { - // it's our lucky day - flags = WC_NO_BEST_FIT_CHARS; - pUsedDef = &usedDef; - } - else // old system or unsupported encoding - { - flags = 0; - pUsedDef = NULL; - } - - const size_t len = ::WideCharToMultiByte - ( - m_CodePage, // code page - flags, // either none or no best fit - pwz, // input string - -1, // it is (wide) NUL-terminated - buf, // output buffer - buf ? n : 0, // and its size - NULL, // default "replacement" char - pUsedDef // [out] was it used? - ); - - if ( !len ) - { - // function totally failed - return wxCONV_FAILED; - } - - // if we were really converting, check if we succeeded - if ( buf ) - { - if ( flags ) - { - // check if the conversion failed, i.e. if any replacements - // were done - if ( usedDef ) - return wxCONV_FAILED; - } - else // we must resort to double tripping... - { - wxWCharBuffer wcBuf(n); - if ( MB2WC(wcBuf.data(), buf, n) == wxCONV_FAILED || - wcscmp(wcBuf, pwz) != 0 ) - { - // we didn't obtain the same thing we started from, hence - // the conversion was lossy and we consider that it failed - return wxCONV_FAILED; - } - } - } - - // see the comment above for the reason of "len - 1" - return len - 1; - } - - virtual size_t GetMBNulLen() const - { - if ( m_minMBCharWidth == 0 ) - { - int len = ::WideCharToMultiByte - ( - m_CodePage, // code page - 0, // no flags - L"", // input string - 1, // translate just the NUL - NULL, // output buffer - 0, // and its size - NULL, // no replacement char - NULL // [out] don't care if it was used - ); - - wxMBConv_win32 * const self = wxConstCast(this, wxMBConv_win32); - switch ( len ) - { - default: - wxLogDebug(_T("Unexpected NUL length %d"), len); - self->m_minMBCharWidth = (size_t)-1; - break; - - case 0: - self->m_minMBCharWidth = (size_t)-1; - break; - - case 1: - case 2: - case 4: - self->m_minMBCharWidth = len; - break; - } - } - - return m_minMBCharWidth; - } - - virtual wxMBConv *Clone() const { return new wxMBConv_win32(*this); } - - bool IsOk() const { return m_CodePage != -1; } - -private: - static bool CanUseNoBestFit() - { - static int s_isWin98Or2k = -1; - - if ( s_isWin98Or2k == -1 ) - { - int verMaj, verMin; - switch ( wxGetOsVersion(&verMaj, &verMin) ) - { - case wxOS_WINDOWS_9X: - s_isWin98Or2k = verMaj >= 4 && verMin >= 10; - break; - - case wxOS_WINDOWS_NT: - s_isWin98Or2k = verMaj >= 5; - break; - - default: - // unknown: be conservative by default - s_isWin98Or2k = 0; - break; - } - - wxASSERT_MSG( s_isWin98Or2k != -1, _T("should be set above") ); - } - - return s_isWin98Or2k == 1; - } - - static bool IsAtLeastWin2kSP4() - { -#ifdef __WXWINCE__ - return false; -#else - static int s_isAtLeastWin2kSP4 = -1; - - if ( s_isAtLeastWin2kSP4 == -1 ) - { - OSVERSIONINFOEX ver; - - memset(&ver, 0, sizeof(ver)); - ver.dwOSVersionInfoSize = sizeof(ver); - GetVersionEx((OSVERSIONINFO*)&ver); - - s_isAtLeastWin2kSP4 = - ((ver.dwMajorVersion > 5) || // Vista+ - (ver.dwMajorVersion == 5 && ver.dwMinorVersion > 0) || // XP/2003 - (ver.dwMajorVersion == 5 && ver.dwMinorVersion == 0 && - ver.wServicePackMajor >= 4)) // 2000 SP4+ - ? 1 : 0; - } - - return s_isAtLeastWin2kSP4 == 1; -#endif - } - - - // the code page we're working with - long m_CodePage; - - // cached result of GetMBNulLen(), set to 0 initially meaning - // "unknown" - size_t m_minMBCharWidth; -}; - -#endif // wxHAVE_WIN32_MB2WC - -// ============================================================================ -// Cocoa conversion classes -// ============================================================================ - -#if defined(__WXCOCOA__) - -// RN: There is no UTF-32 support in either Core Foundation or Cocoa. -// Strangely enough, internally Core Foundation uses -// UTF-32 internally quite a bit - its just not public (yet). - -#include -#include - -CFStringEncoding wxCFStringEncFromFontEnc(wxFontEncoding encoding) -{ - CFStringEncoding enc = kCFStringEncodingInvalidId ; - - switch (encoding) - { - case wxFONTENCODING_DEFAULT : - enc = CFStringGetSystemEncoding(); - break ; - - case wxFONTENCODING_ISO8859_1 : - enc = kCFStringEncodingISOLatin1 ; - break ; - case wxFONTENCODING_ISO8859_2 : - enc = kCFStringEncodingISOLatin2; - break ; - case wxFONTENCODING_ISO8859_3 : - enc = kCFStringEncodingISOLatin3 ; - break ; - case wxFONTENCODING_ISO8859_4 : - enc = kCFStringEncodingISOLatin4; - break ; - case wxFONTENCODING_ISO8859_5 : - enc = kCFStringEncodingISOLatinCyrillic; - break ; - case wxFONTENCODING_ISO8859_6 : - enc = kCFStringEncodingISOLatinArabic; - break ; - case wxFONTENCODING_ISO8859_7 : - enc = kCFStringEncodingISOLatinGreek; - break ; - case wxFONTENCODING_ISO8859_8 : - enc = kCFStringEncodingISOLatinHebrew; - break ; - case wxFONTENCODING_ISO8859_9 : - enc = kCFStringEncodingISOLatin5; - break ; - case wxFONTENCODING_ISO8859_10 : - enc = kCFStringEncodingISOLatin6; - break ; - case wxFONTENCODING_ISO8859_11 : - enc = kCFStringEncodingISOLatinThai; - break ; - case wxFONTENCODING_ISO8859_13 : - enc = kCFStringEncodingISOLatin7; - break ; - case wxFONTENCODING_ISO8859_14 : - enc = kCFStringEncodingISOLatin8; - break ; - case wxFONTENCODING_ISO8859_15 : - enc = kCFStringEncodingISOLatin9; - break ; - - case wxFONTENCODING_KOI8 : - enc = kCFStringEncodingKOI8_R; - break ; - case wxFONTENCODING_ALTERNATIVE : // MS-DOS CP866 - enc = kCFStringEncodingDOSRussian; - break ; - -// case wxFONTENCODING_BULGARIAN : -// enc = ; -// break ; - - case wxFONTENCODING_CP437 : - enc = kCFStringEncodingDOSLatinUS ; - break ; - case wxFONTENCODING_CP850 : - enc = kCFStringEncodingDOSLatin1; - break ; - case wxFONTENCODING_CP852 : - enc = kCFStringEncodingDOSLatin2; - break ; - case wxFONTENCODING_CP855 : - enc = kCFStringEncodingDOSCyrillic; - break ; - case wxFONTENCODING_CP866 : - enc = kCFStringEncodingDOSRussian ; - break ; - case wxFONTENCODING_CP874 : - enc = kCFStringEncodingDOSThai; - break ; - case wxFONTENCODING_CP932 : - enc = kCFStringEncodingDOSJapanese; - break ; - case wxFONTENCODING_CP936 : - enc = kCFStringEncodingDOSChineseSimplif ; - break ; - case wxFONTENCODING_CP949 : - enc = kCFStringEncodingDOSKorean; - break ; - case wxFONTENCODING_CP950 : - enc = kCFStringEncodingDOSChineseTrad; - break ; - case wxFONTENCODING_CP1250 : - enc = kCFStringEncodingWindowsLatin2; - break ; - case wxFONTENCODING_CP1251 : - enc = kCFStringEncodingWindowsCyrillic ; - break ; - case wxFONTENCODING_CP1252 : - enc = kCFStringEncodingWindowsLatin1 ; - break ; - case wxFONTENCODING_CP1253 : - enc = kCFStringEncodingWindowsGreek; - break ; - case wxFONTENCODING_CP1254 : - enc = kCFStringEncodingWindowsLatin5; - break ; - case wxFONTENCODING_CP1255 : - enc = kCFStringEncodingWindowsHebrew ; - break ; - case wxFONTENCODING_CP1256 : - enc = kCFStringEncodingWindowsArabic ; - break ; - case wxFONTENCODING_CP1257 : - enc = kCFStringEncodingWindowsBalticRim; - break ; -// This only really encodes to UTF7 (if that) evidently -// case wxFONTENCODING_UTF7 : -// enc = kCFStringEncodingNonLossyASCII ; -// break ; - case wxFONTENCODING_UTF8 : - enc = kCFStringEncodingUTF8 ; - break ; - case wxFONTENCODING_EUC_JP : - enc = kCFStringEncodingEUC_JP; - break ; - case wxFONTENCODING_UTF16 : - enc = kCFStringEncodingUnicode ; - break ; - case wxFONTENCODING_MACROMAN : - enc = kCFStringEncodingMacRoman ; - break ; - case wxFONTENCODING_MACJAPANESE : - enc = kCFStringEncodingMacJapanese ; - break ; - case wxFONTENCODING_MACCHINESETRAD : - enc = kCFStringEncodingMacChineseTrad ; - break ; - case wxFONTENCODING_MACKOREAN : - enc = kCFStringEncodingMacKorean ; - break ; - case wxFONTENCODING_MACARABIC : - enc = kCFStringEncodingMacArabic ; - break ; - case wxFONTENCODING_MACHEBREW : - enc = kCFStringEncodingMacHebrew ; - break ; - case wxFONTENCODING_MACGREEK : - enc = kCFStringEncodingMacGreek ; - break ; - case wxFONTENCODING_MACCYRILLIC : - enc = kCFStringEncodingMacCyrillic ; - break ; - case wxFONTENCODING_MACDEVANAGARI : - enc = kCFStringEncodingMacDevanagari ; - break ; - case wxFONTENCODING_MACGURMUKHI : - enc = kCFStringEncodingMacGurmukhi ; - break ; - case wxFONTENCODING_MACGUJARATI : - enc = kCFStringEncodingMacGujarati ; - break ; - case wxFONTENCODING_MACORIYA : - enc = kCFStringEncodingMacOriya ; - break ; - case wxFONTENCODING_MACBENGALI : - enc = kCFStringEncodingMacBengali ; - break ; - case wxFONTENCODING_MACTAMIL : - enc = kCFStringEncodingMacTamil ; - break ; - case wxFONTENCODING_MACTELUGU : - enc = kCFStringEncodingMacTelugu ; - break ; - case wxFONTENCODING_MACKANNADA : - enc = kCFStringEncodingMacKannada ; - break ; - case wxFONTENCODING_MACMALAJALAM : - enc = kCFStringEncodingMacMalayalam ; - break ; - case wxFONTENCODING_MACSINHALESE : - enc = kCFStringEncodingMacSinhalese ; - break ; - case wxFONTENCODING_MACBURMESE : - enc = kCFStringEncodingMacBurmese ; - break ; - case wxFONTENCODING_MACKHMER : - enc = kCFStringEncodingMacKhmer ; - break ; - case wxFONTENCODING_MACTHAI : - enc = kCFStringEncodingMacThai ; - break ; - case wxFONTENCODING_MACLAOTIAN : - enc = kCFStringEncodingMacLaotian ; - break ; - case wxFONTENCODING_MACGEORGIAN : - enc = kCFStringEncodingMacGeorgian ; - break ; - case wxFONTENCODING_MACARMENIAN : - enc = kCFStringEncodingMacArmenian ; - break ; - case wxFONTENCODING_MACCHINESESIMP : - enc = kCFStringEncodingMacChineseSimp ; - break ; - case wxFONTENCODING_MACTIBETAN : - enc = kCFStringEncodingMacTibetan ; - break ; - case wxFONTENCODING_MACMONGOLIAN : - enc = kCFStringEncodingMacMongolian ; - break ; - case wxFONTENCODING_MACETHIOPIC : - enc = kCFStringEncodingMacEthiopic ; - break ; - case wxFONTENCODING_MACCENTRALEUR : - enc = kCFStringEncodingMacCentralEurRoman ; - break ; - case wxFONTENCODING_MACVIATNAMESE : - enc = kCFStringEncodingMacVietnamese ; - break ; - case wxFONTENCODING_MACARABICEXT : - enc = kCFStringEncodingMacExtArabic ; - break ; - case wxFONTENCODING_MACSYMBOL : - enc = kCFStringEncodingMacSymbol ; - break ; - case wxFONTENCODING_MACDINGBATS : - enc = kCFStringEncodingMacDingbats ; - break ; - case wxFONTENCODING_MACTURKISH : - enc = kCFStringEncodingMacTurkish ; - break ; - case wxFONTENCODING_MACCROATIAN : - enc = kCFStringEncodingMacCroatian ; - break ; - case wxFONTENCODING_MACICELANDIC : - enc = kCFStringEncodingMacIcelandic ; - break ; - case wxFONTENCODING_MACROMANIAN : - enc = kCFStringEncodingMacRomanian ; - break ; - case wxFONTENCODING_MACCELTIC : - enc = kCFStringEncodingMacCeltic ; - break ; - case wxFONTENCODING_MACGAELIC : - enc = kCFStringEncodingMacGaelic ; - break ; -// case wxFONTENCODING_MACKEYBOARD : -// enc = kCFStringEncodingMacKeyboardGlyphs ; -// break ; - - default : - // because gcc is picky - break ; - } - - return enc ; -} - -class wxMBConv_cocoa : public wxMBConv -{ -public: - wxMBConv_cocoa() - { - Init(CFStringGetSystemEncoding()) ; - } - - wxMBConv_cocoa(const wxMBConv_cocoa& conv) - { - m_encoding = conv.m_encoding; - } - -#if wxUSE_FONTMAP - wxMBConv_cocoa(const wxChar* name) - { - Init( wxCFStringEncFromFontEnc(wxFontMapperBase::Get()->CharsetToEncoding(name, false) ) ) ; - } -#endif - - wxMBConv_cocoa(wxFontEncoding encoding) - { - Init( wxCFStringEncFromFontEnc(encoding) ); - } - - virtual ~wxMBConv_cocoa() - { - } - - void Init( CFStringEncoding encoding) - { - m_encoding = encoding ; - } - - size_t MB2WC(wchar_t * szOut, const char * szUnConv, size_t nOutSize) const - { - wxASSERT(szUnConv); - - CFStringRef theString = CFStringCreateWithBytes ( - NULL, //the allocator - (const UInt8*)szUnConv, - strlen(szUnConv), - m_encoding, - false //no BOM/external representation - ); - - wxASSERT(theString); - - size_t nOutLength = CFStringGetLength(theString); - - if (szOut == NULL) - { - CFRelease(theString); - return nOutLength; - } - - CFRange theRange = { 0, nOutSize }; - -#if SIZEOF_WCHAR_T == 4 - UniChar* szUniCharBuffer = new UniChar[nOutSize]; -#endif - - CFStringGetCharacters(theString, theRange, szUniCharBuffer); - - CFRelease(theString); - - szUniCharBuffer[nOutLength] = '\0'; - -#if SIZEOF_WCHAR_T == 4 - wxMBConvUTF16 converter; - converter.MB2WC( szOut, (const char*)szUniCharBuffer, nOutSize ); - delete [] szUniCharBuffer; -#endif - - return nOutLength; - } - - size_t WC2MB(char *szOut, const wchar_t *szUnConv, size_t nOutSize) const - { - wxASSERT(szUnConv); - - size_t nRealOutSize; - size_t nBufSize = wxWcslen(szUnConv); - UniChar* szUniBuffer = (UniChar*) szUnConv; - -#if SIZEOF_WCHAR_T == 4 - wxMBConvUTF16 converter ; - nBufSize = converter.WC2MB( NULL, szUnConv, 0 ); - szUniBuffer = new UniChar[ (nBufSize / sizeof(UniChar)) + 1]; - converter.WC2MB( (char*) szUniBuffer, szUnConv, nBufSize + sizeof(UniChar)); - nBufSize /= sizeof(UniChar); -#endif - - CFStringRef theString = CFStringCreateWithCharactersNoCopy( - NULL, //allocator - szUniBuffer, - nBufSize, - kCFAllocatorNull //deallocator - we want to deallocate it ourselves - ); - - wxASSERT(theString); - - //Note that CER puts a BOM when converting to unicode - //so we check and use getchars instead in that case - if (m_encoding == kCFStringEncodingUnicode) - { - if (szOut != NULL) - CFStringGetCharacters(theString, CFRangeMake(0, nOutSize - 1), (UniChar*) szOut); - - nRealOutSize = CFStringGetLength(theString) + 1; - } - else - { - CFStringGetBytes( - theString, - CFRangeMake(0, CFStringGetLength(theString)), - m_encoding, - 0, //what to put in characters that can't be converted - - //0 tells CFString to return NULL if it meets such a character - false, //not an external representation - (UInt8*) szOut, - nOutSize, - (CFIndex*) &nRealOutSize - ); - } - - CFRelease(theString); - -#if SIZEOF_WCHAR_T == 4 - delete[] szUniBuffer; -#endif - - return nRealOutSize - 1; - } - - virtual wxMBConv *Clone() const { return new wxMBConv_cocoa(*this); } - - bool IsOk() const - { - return m_encoding != kCFStringEncodingInvalidId && - CFStringIsEncodingAvailable(m_encoding); - } - -private: - CFStringEncoding m_encoding ; -}; - -#endif // defined(__WXCOCOA__) - -// ============================================================================ -// Mac conversion classes -// ============================================================================ - -#if defined(__WXMAC__) && defined(TARGET_CARBON) - -class wxMBConv_mac : public wxMBConv -{ -public: - wxMBConv_mac() - { - Init(CFStringGetSystemEncoding()) ; - } - - wxMBConv_mac(const wxMBConv_mac& conv) - { - Init(conv.m_char_encoding); - } - -#if wxUSE_FONTMAP - wxMBConv_mac(const wxChar* name) - { - wxFontEncoding enc = wxFontMapperBase::Get()->CharsetToEncoding(name, false); - Init( (enc != wxFONTENCODING_SYSTEM) ? wxMacGetSystemEncFromFontEnc( enc ) : kTextEncodingUnknown); - } -#endif - - wxMBConv_mac(wxFontEncoding encoding) - { - Init( wxMacGetSystemEncFromFontEnc(encoding) ); - } - - virtual ~wxMBConv_mac() - { - OSStatus status = noErr ; - if (m_MB2WC_converter) - status = TECDisposeConverter(m_MB2WC_converter); - if (m_WC2MB_converter) - status = TECDisposeConverter(m_WC2MB_converter); - } - - void Init( TextEncodingBase encoding,TextEncodingVariant encodingVariant = kTextEncodingDefaultVariant , - TextEncodingFormat encodingFormat = kTextEncodingDefaultFormat) - { - m_MB2WC_converter = NULL ; - m_WC2MB_converter = NULL ; - if ( encoding != kTextEncodingUnknown ) - { - m_char_encoding = CreateTextEncoding(encoding, encodingVariant, encodingFormat) ; - m_unicode_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault, 0, kUnicode16BitFormat) ; - } - else - { - m_char_encoding = kTextEncodingUnknown; - m_unicode_encoding = kTextEncodingUnknown; - } - } - - virtual void CreateIfNeeded() const - { - if ( m_MB2WC_converter == NULL && m_WC2MB_converter == NULL && - m_char_encoding != kTextEncodingUnknown && m_unicode_encoding != kTextEncodingUnknown ) - { - OSStatus status = noErr ; - status = TECCreateConverter(&m_MB2WC_converter, - m_char_encoding, - m_unicode_encoding); - wxASSERT_MSG( status == noErr , _("Unable to create TextEncodingConverter")) ; - status = TECCreateConverter(&m_WC2MB_converter, - m_unicode_encoding, - m_char_encoding); - wxASSERT_MSG( status == noErr , _("Unable to create TextEncodingConverter")) ; - } - } - - size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const - { - CreateIfNeeded() ; - OSStatus status = noErr ; - ByteCount byteOutLen ; - ByteCount byteInLen = strlen(psz) + 1; - wchar_t *tbuf = NULL ; - UniChar* ubuf = NULL ; - size_t res = 0 ; - - if (buf == NULL) - { - // Apple specs say at least 32 - n = wxMax( 32, byteInLen ) ; - tbuf = (wchar_t*) malloc( n * SIZEOF_WCHAR_T ) ; - } - - ByteCount byteBufferLen = n * sizeof( UniChar ) ; - -#if SIZEOF_WCHAR_T == 4 - ubuf = (UniChar*) malloc( byteBufferLen + 2 ) ; -#else - ubuf = (UniChar*) (buf ? buf : tbuf) ; -#endif - { -#if wxUSE_THREADS - wxMutexLocker lock( m_MB2WC_guard ); -#endif - status = TECConvertText( - m_MB2WC_converter, (ConstTextPtr) psz, byteInLen, &byteInLen, - (TextPtr) ubuf, byteBufferLen, &byteOutLen); - } - -#if SIZEOF_WCHAR_T == 4 - // we have to terminate here, because n might be larger for the trailing zero, and if UniChar - // is not properly terminated we get random characters at the end - ubuf[byteOutLen / sizeof( UniChar ) ] = 0 ; - wxMBConvUTF16 converter ; - res = converter.MB2WC( (buf ? buf : tbuf), (const char*)ubuf, n ) ; - free( ubuf ) ; -#else - res = byteOutLen / sizeof( UniChar ) ; -#endif - - if ( buf == NULL ) - free(tbuf) ; - - if ( buf && res < n) - buf[res] = 0; - - return res ; - } - - size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const - { - CreateIfNeeded() ; - OSStatus status = noErr ; - ByteCount byteOutLen ; - ByteCount byteInLen = wxWcslen(psz) * SIZEOF_WCHAR_T ; - - char *tbuf = NULL ; - - if (buf == NULL) - { - // Apple specs say at least 32 - n = wxMax( 32, ((byteInLen / SIZEOF_WCHAR_T) * 8) + SIZEOF_WCHAR_T ); - tbuf = (char*) malloc( n ) ; - } - - ByteCount byteBufferLen = n ; - UniChar* ubuf = NULL ; - -#if SIZEOF_WCHAR_T == 4 - wxMBConvUTF16 converter ; - size_t unicharlen = converter.WC2MB( NULL, psz, 0 ) ; - byteInLen = unicharlen ; - ubuf = (UniChar*) malloc( byteInLen + 2 ) ; - converter.WC2MB( (char*) ubuf, psz, unicharlen + 2 ) ; -#else - ubuf = (UniChar*) psz ; -#endif - - { -#if wxUSE_THREADS - wxMutexLocker lock( m_WC2MB_guard ); -#endif - status = TECConvertText( - m_WC2MB_converter, (ConstTextPtr) ubuf, byteInLen, &byteInLen, - (TextPtr) (buf ? buf : tbuf), byteBufferLen, &byteOutLen); - } - -#if SIZEOF_WCHAR_T == 4 - free( ubuf ) ; -#endif - - if ( buf == NULL ) - free(tbuf) ; - - size_t res = byteOutLen ; - if ( buf && res < n) - { - buf[res] = 0; - - //we need to double-trip to verify it didn't insert any ? in place - //of bogus characters - wxWCharBuffer wcBuf(n); - size_t pszlen = wxWcslen(psz); - if ( MB2WC(wcBuf.data(), buf, n) == wxCONV_FAILED || - wxWcslen(wcBuf) != pszlen || - memcmp(wcBuf, psz, pszlen * sizeof(wchar_t)) != 0 ) - { - // we didn't obtain the same thing we started from, hence - // the conversion was lossy and we consider that it failed - return wxCONV_FAILED; - } - } - - return res ; - } - - virtual wxMBConv *Clone() const { return new wxMBConv_mac(*this); } - - bool IsOk() const - { - CreateIfNeeded() ; - return m_MB2WC_converter != NULL && m_WC2MB_converter != NULL; - } - -protected : - mutable TECObjectRef m_MB2WC_converter; - mutable TECObjectRef m_WC2MB_converter; -#if wxUSE_THREADS - mutable wxMutex m_MB2WC_guard; - mutable wxMutex m_WC2MB_guard; -#endif - - TextEncodingBase m_char_encoding; - TextEncodingBase m_unicode_encoding; -}; - -// MB is decomposed (D) normalized UTF8 - -class wxMBConv_macUTF8D : public wxMBConv_mac -{ -public : - wxMBConv_macUTF8D() - { - Init( kTextEncodingUnicodeDefault , kUnicodeNoSubset , kUnicodeUTF8Format ) ; - m_uni = NULL; - m_uniBack = NULL ; - } - - virtual ~wxMBConv_macUTF8D() - { - if (m_uni!=NULL) - DisposeUnicodeToTextInfo(&m_uni); - if (m_uniBack!=NULL) - DisposeUnicodeToTextInfo(&m_uniBack); - } - - size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const - { - CreateIfNeeded() ; - OSStatus status = noErr ; - ByteCount byteOutLen ; - ByteCount byteInLen = wxWcslen(psz) * SIZEOF_WCHAR_T ; - - char *tbuf = NULL ; - - if (buf == NULL) - { - // Apple specs say at least 32 - n = wxMax( 32, ((byteInLen / SIZEOF_WCHAR_T) * 8) + SIZEOF_WCHAR_T ); - tbuf = (char*) malloc( n ) ; - } - - ByteCount byteBufferLen = n ; - UniChar* ubuf = NULL ; - -#if SIZEOF_WCHAR_T == 4 - wxMBConvUTF16 converter ; - size_t unicharlen = converter.WC2MB( NULL, psz, 0 ) ; - byteInLen = unicharlen ; - ubuf = (UniChar*) malloc( byteInLen + 2 ) ; - converter.WC2MB( (char*) ubuf, psz, unicharlen + 2 ) ; -#else - ubuf = (UniChar*) psz ; -#endif - - // ubuf is a non-decomposed UniChar buffer - - ByteCount dcubuflen = byteInLen * 2 + 2 ; - ByteCount dcubufread , dcubufwritten ; - UniChar *dcubuf = (UniChar*) malloc( dcubuflen ) ; - - { -#if wxUSE_THREADS - wxMutexLocker lock( m_WC2MB_guard ); -#endif - ConvertFromUnicodeToText( m_uni , byteInLen , ubuf , - kUnicodeDefaultDirectionMask, 0, NULL, NULL, NULL, dcubuflen , &dcubufread , &dcubufwritten , dcubuf ) ; - - // we now convert that decomposed buffer into UTF8 - - status = TECConvertText( - m_WC2MB_converter, (ConstTextPtr) dcubuf, dcubufwritten, &dcubufread, - (TextPtr) (buf ? buf : tbuf), byteBufferLen, &byteOutLen); - } - - free( dcubuf ); - -#if SIZEOF_WCHAR_T == 4 - free( ubuf ) ; -#endif - - if ( buf == NULL ) - free(tbuf) ; - - size_t res = byteOutLen ; - if ( buf && res < n) - { - buf[res] = 0; - // don't test for round-trip fidelity yet, we cannot guarantee it yet - } - - return res ; - } - - size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const - { - CreateIfNeeded() ; - OSStatus status = noErr ; - ByteCount byteOutLen ; - ByteCount byteInLen = strlen(psz) + 1; - wchar_t *tbuf = NULL ; - UniChar* ubuf = NULL ; - size_t res = 0 ; - - if (buf == NULL) - { - // Apple specs say at least 32 - n = wxMax( 32, byteInLen ) ; - tbuf = (wchar_t*) malloc( n * SIZEOF_WCHAR_T ) ; - } - - ByteCount byteBufferLen = n * sizeof( UniChar ) ; - -#if SIZEOF_WCHAR_T == 4 - ubuf = (UniChar*) malloc( byteBufferLen + 2 ) ; -#else - ubuf = (UniChar*) (buf ? buf : tbuf) ; -#endif - - ByteCount dcubuflen = byteBufferLen * 2 + 2 ; - ByteCount dcubufread , dcubufwritten ; - UniChar *dcubuf = (UniChar*) malloc( dcubuflen ) ; - - { -#if wxUSE_THREADS - wxMutexLocker lock( m_MB2WC_guard ); -#endif - status = TECConvertText( - m_MB2WC_converter, (ConstTextPtr) psz, byteInLen, &byteInLen, - (TextPtr) dcubuf, dcubuflen, &byteOutLen); - // we have to terminate here, because n might be larger for the trailing zero, and if UniChar - // is not properly terminated we get random characters at the end - dcubuf[byteOutLen / sizeof( UniChar ) ] = 0 ; - - // now from the decomposed UniChar to properly composed uniChar - ConvertFromUnicodeToText( m_uniBack , byteOutLen , dcubuf , - kUnicodeDefaultDirectionMask, 0, NULL, NULL, NULL, dcubuflen , &dcubufread , &dcubufwritten , ubuf ) ; - } - - free( dcubuf ); - byteOutLen = dcubufwritten ; - ubuf[byteOutLen / sizeof( UniChar ) ] = 0 ; - - -#if SIZEOF_WCHAR_T == 4 - wxMBConvUTF16 converter ; - res = converter.MB2WC( (buf ? buf : tbuf), (const char*)ubuf, n ) ; - free( ubuf ) ; -#else - res = byteOutLen / sizeof( UniChar ) ; -#endif - - if ( buf == NULL ) - free(tbuf) ; - - if ( buf && res < n) - buf[res] = 0; - - return res ; - } - - virtual void CreateIfNeeded() const - { - wxMBConv_mac::CreateIfNeeded() ; - if ( m_uni == NULL ) - { - m_map.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, - kUnicodeNoSubset, kTextEncodingDefaultFormat); - m_map.otherEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, - kUnicodeCanonicalDecompVariant, kTextEncodingDefaultFormat); - m_map.mappingVersion = kUnicodeUseLatestMapping; - - OSStatus err = CreateUnicodeToTextInfo(&m_map, &m_uni); - wxASSERT_MSG( err == noErr , _(" Couldn't create the UnicodeConverter")) ; - - m_map.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, - kUnicodeNoSubset, kTextEncodingDefaultFormat); - m_map.otherEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, - kUnicodeCanonicalCompVariant, kTextEncodingDefaultFormat); - m_map.mappingVersion = kUnicodeUseLatestMapping; - err = CreateUnicodeToTextInfo(&m_map, &m_uniBack); - wxASSERT_MSG( err == noErr , _(" Couldn't create the UnicodeConverter")) ; - } - } -protected : - mutable UnicodeToTextInfo m_uni; - mutable UnicodeToTextInfo m_uniBack; - mutable UnicodeMapping m_map; -}; -#endif // defined(__WXMAC__) && defined(TARGET_CARBON) - -// ============================================================================ -// wxEncodingConverter based conversion classes -// ============================================================================ - -#if wxUSE_FONTMAP - -class wxMBConv_wxwin : public wxMBConv -{ -private: - void Init() - { - m_ok = m2w.Init(m_enc, wxFONTENCODING_UNICODE) && - w2m.Init(wxFONTENCODING_UNICODE, m_enc); - } - -public: - // temporarily just use wxEncodingConverter stuff, - // so that it works while a better implementation is built - wxMBConv_wxwin(const wxChar* name) - { - if (name) - m_enc = wxFontMapperBase::Get()->CharsetToEncoding(name, false); - else - m_enc = wxFONTENCODING_SYSTEM; - - Init(); - } - - wxMBConv_wxwin(wxFontEncoding enc) - { - m_enc = enc; - - Init(); - } - - size_t MB2WC(wchar_t *buf, const char *psz, size_t WXUNUSED(n)) const - { - size_t inbuf = strlen(psz); - if (buf) - { - if (!m2w.Convert(psz, buf)) - return wxCONV_FAILED; - } - return inbuf; - } - - size_t WC2MB(char *buf, const wchar_t *psz, size_t WXUNUSED(n)) const - { - const size_t inbuf = wxWcslen(psz); - if (buf) - { - if (!w2m.Convert(psz, buf)) - return wxCONV_FAILED; - } - - return inbuf; - } - - virtual size_t GetMBNulLen() const - { - switch ( m_enc ) - { - case wxFONTENCODING_UTF16BE: - case wxFONTENCODING_UTF16LE: - return 2; - - case wxFONTENCODING_UTF32BE: - case wxFONTENCODING_UTF32LE: - return 4; - - default: - return 1; - } - } - - virtual wxMBConv *Clone() const { return new wxMBConv_wxwin(m_enc); } - - bool IsOk() const { return m_ok; } - -public: - wxFontEncoding m_enc; - wxEncodingConverter m2w, w2m; - -private: - // were we initialized successfully? - bool m_ok; - - DECLARE_NO_COPY_CLASS(wxMBConv_wxwin) -}; - -// make the constructors available for unit testing -WXDLLIMPEXP_BASE wxMBConv* new_wxMBConv_wxwin( const wxChar* name ) -{ - wxMBConv_wxwin* result = new wxMBConv_wxwin( name ); - if ( !result->IsOk() ) - { - delete result; - return 0; - } - - return result; -} - -#endif // wxUSE_FONTMAP - -// ============================================================================ -// wxCSConv implementation -// ============================================================================ - -void wxCSConv::Init() -{ - m_name = NULL; - m_convReal = NULL; - m_deferred = true; -} - -wxCSConv::wxCSConv(const wxChar *charset) -{ - Init(); - - if ( charset ) - { - SetName(charset); - } - -#if wxUSE_FONTMAP - m_encoding = wxFontMapperBase::GetEncodingFromName(charset); - if ( m_encoding == wxFONTENCODING_MAX ) - { - // set to unknown/invalid value - m_encoding = wxFONTENCODING_SYSTEM; - } - else if ( m_encoding == wxFONTENCODING_DEFAULT ) - { - // wxFONTENCODING_DEFAULT is same as US-ASCII in this context - m_encoding = wxFONTENCODING_ISO8859_1; - } -#else - m_encoding = wxFONTENCODING_SYSTEM; -#endif -} - -wxCSConv::wxCSConv(wxFontEncoding encoding) -{ - if ( encoding == wxFONTENCODING_MAX || encoding == wxFONTENCODING_DEFAULT ) - { - wxFAIL_MSG( _T("invalid encoding value in wxCSConv ctor") ); - - encoding = wxFONTENCODING_SYSTEM; - } - - Init(); - - m_encoding = encoding; -} - -wxCSConv::~wxCSConv() -{ - Clear(); -} - -wxCSConv::wxCSConv(const wxCSConv& conv) - : wxMBConv() -{ - Init(); - - SetName(conv.m_name); - m_encoding = conv.m_encoding; -} - -wxCSConv& wxCSConv::operator=(const wxCSConv& conv) -{ - Clear(); - - SetName(conv.m_name); - m_encoding = conv.m_encoding; - - return *this; -} - -void wxCSConv::Clear() -{ - free(m_name); - delete m_convReal; - - m_name = NULL; - m_convReal = NULL; -} - -void wxCSConv::SetName(const wxChar *charset) -{ - if (charset) - { - m_name = wxStrdup(charset); - m_deferred = true; - } -} - -#if wxUSE_FONTMAP - -WX_DECLARE_HASH_MAP( wxFontEncoding, wxString, wxIntegerHash, wxIntegerEqual, - wxEncodingNameCache ); - -static wxEncodingNameCache gs_nameCache; -#endif - -wxMBConv *wxCSConv::DoCreate() const -{ -#if wxUSE_FONTMAP - wxLogTrace(TRACE_STRCONV, - wxT("creating conversion for %s"), - (m_name ? m_name - : wxFontMapperBase::GetEncodingName(m_encoding).c_str())); -#endif // wxUSE_FONTMAP - - // check for the special case of ASCII or ISO8859-1 charset: as we have - // special knowledge of it anyhow, we don't need to create a special - // conversion object - if ( m_encoding == wxFONTENCODING_ISO8859_1 || - m_encoding == wxFONTENCODING_DEFAULT ) - { - // don't convert at all - return NULL; - } - - // we trust OS to do conversion better than we can so try external - // conversion methods first - // - // the full order is: - // 1. OS conversion (iconv() under Unix or Win32 API) - // 2. hard coded conversions for UTF - // 3. wxEncodingConverter as fall back - - // step (1) -#ifdef HAVE_ICONV -#if !wxUSE_FONTMAP - if ( m_name ) -#endif // !wxUSE_FONTMAP - { - wxString name(m_name); -#if wxUSE_FONTMAP - wxFontEncoding encoding(m_encoding); -#endif - - if ( !name.empty() ) - { - wxMBConv_iconv *conv = new wxMBConv_iconv(name); - if ( conv->IsOk() ) - return conv; - - delete conv; - -#if wxUSE_FONTMAP - encoding = - wxFontMapperBase::Get()->CharsetToEncoding(name, false); -#endif // wxUSE_FONTMAP - } -#if wxUSE_FONTMAP - { - const wxEncodingNameCache::iterator it = gs_nameCache.find(encoding); - if ( it != gs_nameCache.end() ) - { - if ( it->second.empty() ) - return NULL; - - wxMBConv_iconv *conv = new wxMBConv_iconv(it->second); - if ( conv->IsOk() ) - return conv; - - delete conv; - } - - const wxChar** names = wxFontMapperBase::GetAllEncodingNames(encoding); - // CS : in case this does not return valid names (eg for MacRoman) encoding - // got a 'failure' entry in the cache all the same, although it just has to - // be created using a different method, so only store failed iconv creation - // attempts (or perhaps we shoulnd't do this at all ?) - if ( names[0] != NULL ) - { - for ( ; *names; ++names ) - { - wxMBConv_iconv *conv = new wxMBConv_iconv(*names); - if ( conv->IsOk() ) - { - gs_nameCache[encoding] = *names; - return conv; - } - - delete conv; - } - - gs_nameCache[encoding] = _T(""); // cache the failure - } - } -#endif // wxUSE_FONTMAP - } -#endif // HAVE_ICONV - -#ifdef wxHAVE_WIN32_MB2WC - { -#if wxUSE_FONTMAP - wxMBConv_win32 *conv = m_name ? new wxMBConv_win32(m_name) - : new wxMBConv_win32(m_encoding); - if ( conv->IsOk() ) - return conv; - - delete conv; -#else - return NULL; -#endif - } -#endif // wxHAVE_WIN32_MB2WC - -#if defined(__WXMAC__) - { - // leave UTF16 and UTF32 to the built-ins of wx - if ( m_name || ( m_encoding < wxFONTENCODING_UTF16BE || - ( m_encoding >= wxFONTENCODING_MACMIN && m_encoding <= wxFONTENCODING_MACMAX ) ) ) - { -#if wxUSE_FONTMAP - wxMBConv_mac *conv = m_name ? new wxMBConv_mac(m_name) - : new wxMBConv_mac(m_encoding); -#else - wxMBConv_mac *conv = new wxMBConv_mac(m_encoding); -#endif - if ( conv->IsOk() ) - return conv; - - delete conv; - } - } -#endif - -#if defined(__WXCOCOA__) - { - if ( m_name || ( m_encoding <= wxFONTENCODING_UTF16 ) ) - { -#if wxUSE_FONTMAP - wxMBConv_cocoa *conv = m_name ? new wxMBConv_cocoa(m_name) - : new wxMBConv_cocoa(m_encoding); -#else - wxMBConv_cocoa *conv = new wxMBConv_cocoa(m_encoding); -#endif - - if ( conv->IsOk() ) - return conv; - - delete conv; - } - } -#endif - // step (2) - wxFontEncoding enc = m_encoding; -#if wxUSE_FONTMAP - if ( enc == wxFONTENCODING_SYSTEM && m_name ) - { - // use "false" to suppress interactive dialogs -- we can be called from - // anywhere and popping up a dialog from here is the last thing we want to - // do - enc = wxFontMapperBase::Get()->CharsetToEncoding(m_name, false); - } -#endif // wxUSE_FONTMAP - - switch ( enc ) - { - case wxFONTENCODING_UTF7: - return new wxMBConvUTF7; - - case wxFONTENCODING_UTF8: - return new wxMBConvUTF8; - - case wxFONTENCODING_UTF16BE: - return new wxMBConvUTF16BE; - - case wxFONTENCODING_UTF16LE: - return new wxMBConvUTF16LE; - - case wxFONTENCODING_UTF32BE: - return new wxMBConvUTF32BE; - - case wxFONTENCODING_UTF32LE: - return new wxMBConvUTF32LE; - - default: - // nothing to do but put here to suppress gcc warnings - break; - } - - // step (3) -#if wxUSE_FONTMAP - { - wxMBConv_wxwin *conv = m_name ? new wxMBConv_wxwin(m_name) - : new wxMBConv_wxwin(m_encoding); - if ( conv->IsOk() ) - return conv; - - delete conv; - } -#endif // wxUSE_FONTMAP - - // NB: This is a hack to prevent deadlock. What could otherwise happen - // in Unicode build: wxConvLocal creation ends up being here - // because of some failure and logs the error. But wxLog will try to - // attach a timestamp, for which it will need wxConvLocal (to convert - // time to char* and then wchar_t*), but that fails, tries to log the - // error, but wxLog has an (already locked) critical section that - // guards the static buffer. - static bool alreadyLoggingError = false; - if (!alreadyLoggingError) - { - alreadyLoggingError = true; - wxLogError(_("Cannot convert from the charset '%s'!"), - m_name ? m_name - : -#if wxUSE_FONTMAP - wxFontMapperBase::GetEncodingDescription(m_encoding).c_str() -#else // !wxUSE_FONTMAP - wxString::Format(_("encoding %i"), m_encoding).c_str() -#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP - ); - - alreadyLoggingError = false; - } - - return NULL; -} - -void wxCSConv::CreateConvIfNeeded() const -{ - if ( m_deferred ) - { - wxCSConv *self = (wxCSConv *)this; // const_cast - - // if we don't have neither the name nor the encoding, use the default - // encoding for this system - if ( !m_name && m_encoding == wxFONTENCODING_SYSTEM ) - { -#if wxUSE_INTL - self->m_encoding = wxLocale::GetSystemEncoding(); -#else - // fallback to some reasonable default: - self->m_encoding = wxFONTENCODING_ISO8859_1; -#endif // wxUSE_INTL - } - - self->m_convReal = DoCreate(); - self->m_deferred = false; - } -} - -bool wxCSConv::IsOk() const -{ - CreateConvIfNeeded(); - - // special case: no convReal created for wxFONTENCODING_ISO8859_1 - if ( m_encoding == wxFONTENCODING_ISO8859_1 ) - return true; // always ok as we do it ourselves - - // m_convReal->IsOk() is called at its own creation, so we know it must - // be ok if m_convReal is non-NULL - return m_convReal != NULL; -} - -size_t wxCSConv::ToWChar(wchar_t *dst, size_t dstLen, - const char *src, size_t srcLen) const -{ - CreateConvIfNeeded(); - - if (m_convReal) - return m_convReal->ToWChar(dst, dstLen, src, srcLen); - - // latin-1 (direct) - if ( srcLen == wxNO_LEN ) - srcLen = strlen(src) + 1; // take trailing NUL too - - if ( dst ) - { - if ( dstLen < srcLen ) - return wxCONV_FAILED; - - for ( size_t n = 0; n < srcLen; n++ ) - dst[n] = (unsigned char)(src[n]); - } - - return srcLen; -} - -size_t wxCSConv::FromWChar(char *dst, size_t dstLen, - const wchar_t *src, size_t srcLen) const -{ - CreateConvIfNeeded(); - - if (m_convReal) - return m_convReal->FromWChar(dst, dstLen, src, srcLen); - - // latin-1 (direct) - if ( srcLen == wxNO_LEN ) - srcLen = wxWcslen(src) + 1; - - if ( dst ) - { - if ( dstLen < srcLen ) - return wxCONV_FAILED; - - for ( size_t n = 0; n < srcLen; n++ ) - { - if ( src[n] > 0xFF ) - return wxCONV_FAILED; - - dst[n] = (char)src[n]; - } - - } - else // still need to check the input validity - { - for ( size_t n = 0; n < srcLen; n++ ) - { - if ( src[n] > 0xFF ) - return wxCONV_FAILED; - } - } - - return srcLen; -} - -size_t wxCSConv::MB2WC(wchar_t *buf, const char *psz, size_t n) const -{ - // this function exists only for ABI-compatibility in 2.8 branch - return wxMBConv::MB2WC(buf, psz, n); -} - -size_t wxCSConv::WC2MB(char *buf, const wchar_t *psz, size_t n) const -{ - // this function exists only for ABI-compatibility in 2.8 branch - return wxMBConv::WC2MB(buf, psz, n); -} - -size_t wxCSConv::GetMBNulLen() const -{ - CreateConvIfNeeded(); - - if ( m_convReal ) - { - return m_convReal->GetMBNulLen(); - } - - return 1; -} - -// ---------------------------------------------------------------------------- -// globals -// ---------------------------------------------------------------------------- - -#ifdef __WINDOWS__ - static wxMBConv_win32 wxConvLibcObj; -#elif defined(__WXMAC__) && !defined(__MACH__) - static wxMBConv_mac wxConvLibcObj ; -#else - static wxMBConvLibc wxConvLibcObj; -#endif - -static wxCSConv wxConvLocalObj(wxFONTENCODING_SYSTEM); -static wxCSConv wxConvISO8859_1Obj(wxFONTENCODING_ISO8859_1); -static wxMBConvUTF7 wxConvUTF7Obj; -static wxMBConvUTF8 wxConvUTF8Obj; -#if defined(__WXMAC__) && defined(TARGET_CARBON) -static wxMBConv_macUTF8D wxConvMacUTF8DObj; -#endif -WXDLLIMPEXP_DATA_BASE(wxMBConv&) wxConvLibc = wxConvLibcObj; -WXDLLIMPEXP_DATA_BASE(wxCSConv&) wxConvLocal = wxConvLocalObj; -WXDLLIMPEXP_DATA_BASE(wxCSConv&) wxConvISO8859_1 = wxConvISO8859_1Obj; -WXDLLIMPEXP_DATA_BASE(wxMBConvUTF7&) wxConvUTF7 = wxConvUTF7Obj; -WXDLLIMPEXP_DATA_BASE(wxMBConvUTF8&) wxConvUTF8 = wxConvUTF8Obj; -WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvCurrent = &wxConvLibcObj; -WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvUI = &wxConvLocal; -WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvFileName = & -#ifdef __WXOSX__ -#if defined(__WXMAC__) && defined(TARGET_CARBON) - wxConvMacUTF8DObj; -#else - wxConvUTF8Obj; -#endif -#else // !__WXOSX__ - wxConvLibcObj; -#endif // __WXOSX__/!__WXOSX__ - -#if wxUSE_UNICODE - -wxWCharBuffer wxSafeConvertMB2WX(const char *s) -{ - if ( !s ) - return wxWCharBuffer(); - - wxWCharBuffer wbuf(wxConvLibc.cMB2WX(s)); - if ( !wbuf ) - wbuf = wxConvUTF8.cMB2WX(s); - if ( !wbuf ) - wbuf = wxConvISO8859_1.cMB2WX(s); - - return wbuf; -} - -wxCharBuffer wxSafeConvertWX2MB(const wchar_t *ws) -{ - if ( !ws ) - return wxCharBuffer(); - - wxCharBuffer buf(wxConvLibc.cWX2MB(ws)); - if ( !buf ) - buf = wxMBConvUTF8(wxMBConvUTF8::MAP_INVALID_UTF8_TO_OCTAL).cWX2MB(ws); - - return buf; -} - -#endif // wxUSE_UNICODE - -#else // !wxUSE_WCHAR_T - -// stand-ins in absence of wchar_t -WXDLLIMPEXP_DATA_BASE(wxMBConv) wxConvLibc, - wxConvISO8859_1, - wxConvLocal, - wxConvUTF8; - -WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvCurrent = NULL; - -#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/strconv.cpp +// Purpose: Unicode conversion classes +// Author: Ove Kaaven, Robert Roebling, Vadim Zeitlin, Vaclav Slavik, +// Ryan Norton, Fredrik Roubert (UTF7) +// Modified by: +// Created: 29/01/98 +// RCS-ID: $Id: strconv.cpp 64156 2010-04-27 08:52:30Z VZ $ +// Copyright: (c) 1999 Ove Kaaven, Robert Roebling, Vaclav Slavik +// (c) 2000-2003 Vadim Zeitlin +// (c) 2004 Ryan Norton, Fredrik Roubert +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifndef WX_PRECOMP + #ifdef __WXMSW__ + #include "wx/msw/missing.h" + #endif + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" + #include "wx/hashmap.h" +#endif + +#include "wx/strconv.h" + +#if wxUSE_WCHAR_T + +#ifdef __WINDOWS__ + #include "wx/msw/private.h" +#endif + +#ifndef __WXWINCE__ +#include +#endif + +#include +#include +#include + +#if defined(__WIN32__) && !defined(__WXMICROWIN__) + #define wxHAVE_WIN32_MB2WC +#endif + +#ifdef __SALFORDC__ + #include +#endif + +#ifdef HAVE_ICONV + #include + #include "wx/thread.h" +#endif + +#include "wx/encconv.h" +#include "wx/fontmap.h" + +#ifdef __WXMAC__ +#ifndef __DARWIN__ +#include +#include +#include +#endif + +// includes Mac headers +#include "wx/mac/private.h" +#include "wx/thread.h" + +#endif + + +#define TRACE_STRCONV _T("strconv") + +// WC_UTF16 is defined only if sizeof(wchar_t) == 2, otherwise it's supposed to +// be 4 bytes +#if SIZEOF_WCHAR_T == 2 + #define WC_UTF16 +#endif + + +// ============================================================================ +// implementation +// ============================================================================ + +// helper function of cMB2WC(): check if n bytes at this location are all NUL +static bool NotAllNULs(const char *p, size_t n) +{ + while ( n && *p++ == '\0' ) + n--; + + return n != 0; +} + +// ---------------------------------------------------------------------------- +// UTF-16 en/decoding to/from UCS-4 with surrogates handling +// ---------------------------------------------------------------------------- + +static size_t encode_utf16(wxUint32 input, wxUint16 *output) +{ + if (input <= 0xffff) + { + if (output) + *output = (wxUint16) input; + + return 1; + } + else if (input >= 0x110000) + { + return wxCONV_FAILED; + } + else + { + if (output) + { + *output++ = (wxUint16) ((input >> 10) + 0xd7c0); + *output = (wxUint16) ((input & 0x3ff) + 0xdc00); + } + + return 2; + } +} + +static size_t decode_utf16(const wxUint16* input, wxUint32& output) +{ + if ((*input < 0xd800) || (*input > 0xdfff)) + { + output = *input; + return 1; + } + else if ((input[1] < 0xdc00) || (input[1] > 0xdfff)) + { + output = *input; + return wxCONV_FAILED; + } + else + { + output = ((input[0] - 0xd7c0) << 10) + (input[1] - 0xdc00); + return 2; + } +} + +#ifdef WC_UTF16 + typedef wchar_t wxDecodeSurrogate_t; +#else // !WC_UTF16 + typedef wxUint16 wxDecodeSurrogate_t; +#endif // WC_UTF16/!WC_UTF16 + +// returns the next UTF-32 character from the wchar_t buffer and advances the +// pointer to the character after this one +// +// if an invalid character is found, *pSrc is set to NULL, the caller must +// check for this +static wxUint32 wxDecodeSurrogate(const wxDecodeSurrogate_t **pSrc) +{ + wxUint32 out; + const size_t + n = decode_utf16(wx_reinterpret_cast(const wxUint16 *, *pSrc), out); + if ( n == wxCONV_FAILED ) + *pSrc = NULL; + else + *pSrc += n; + + return out; +} + +// ---------------------------------------------------------------------------- +// wxMBConv +// ---------------------------------------------------------------------------- + +size_t +wxMBConv::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + // although new conversion classes are supposed to implement this function + // directly, the existins ones only implement the old MB2WC() and so, to + // avoid to have to rewrite all conversion classes at once, we provide a + // default (but not efficient) implementation of this one in terms of the + // old function by copying the input to ensure that it's NUL-terminated and + // then using MB2WC() to convert it + + // the number of chars [which would be] written to dst [if it were not NULL] + size_t dstWritten = 0; + + // the number of NULs terminating this string + size_t nulLen = 0; // not really needed, but just to avoid warnings + + // if we were not given the input size we just have to assume that the + // string is properly terminated as we have no way of knowing how long it + // is anyhow, but if we do have the size check whether there are enough + // NULs at the end + wxCharBuffer bufTmp; + const char *srcEnd; + if ( srcLen != wxNO_LEN ) + { + // we need to know how to find the end of this string + nulLen = GetMBNulLen(); + if ( nulLen == wxCONV_FAILED ) + return wxCONV_FAILED; + + // if there are enough NULs we can avoid the copy + if ( srcLen < nulLen || NotAllNULs(src + srcLen - nulLen, nulLen) ) + { + // make a copy in order to properly NUL-terminate the string + bufTmp = wxCharBuffer(srcLen + nulLen - 1 /* 1 will be added */); + char * const p = bufTmp.data(); + memcpy(p, src, srcLen); + for ( char *s = p + srcLen; s < p + srcLen + nulLen; s++ ) + *s = '\0'; + + src = bufTmp; + } + + srcEnd = src + srcLen; + } + else // quit after the first loop iteration + { + srcEnd = NULL; + } + + for ( ;; ) + { + // try to convert the current chunk + size_t lenChunk = MB2WC(NULL, src, 0); + if ( lenChunk == wxCONV_FAILED ) + return wxCONV_FAILED; + + lenChunk++; // for the L'\0' at the end of this chunk + + dstWritten += lenChunk; + + if ( lenChunk == 1 ) + { + // nothing left in the input string, conversion succeeded + break; + } + + if ( dst ) + { + if ( dstWritten > dstLen ) + return wxCONV_FAILED; + + if ( MB2WC(dst, src, lenChunk) == wxCONV_FAILED ) + return wxCONV_FAILED; + + dst += lenChunk; + } + + if ( !srcEnd ) + { + // we convert just one chunk in this case as this is the entire + // string anyhow + break; + } + + // advance the input pointer past the end of this chunk + while ( NotAllNULs(src, nulLen) ) + { + // notice that we must skip over multiple bytes here as we suppose + // that if NUL takes 2 or 4 bytes, then all the other characters do + // too and so if advanced by a single byte we might erroneously + // detect sequences of NUL bytes in the middle of the input + src += nulLen; + } + + src += nulLen; // skipping over its terminator as well + + // note that ">=" (and not just "==") is needed here as the terminator + // we skipped just above could be inside or just after the buffer + // delimited by inEnd + if ( src >= srcEnd ) + break; + } + + return dstWritten; +} + +size_t +wxMBConv::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + // the number of chars [which would be] written to dst [if it were not NULL] + size_t dstWritten = 0; + + // make a copy of the input string unless it is already properly + // NUL-terminated + // + // if we don't know its length we have no choice but to assume that it is, + // indeed, properly terminated + wxWCharBuffer bufTmp; + if ( srcLen == wxNO_LEN ) + { + srcLen = wxWcslen(src) + 1; + } + else if ( srcLen != 0 && src[srcLen - 1] != L'\0' ) + { + // make a copy in order to properly NUL-terminate the string + bufTmp = wxWCharBuffer(srcLen); + memcpy(bufTmp.data(), src, srcLen * sizeof(wchar_t)); + src = bufTmp; + } + + const size_t lenNul = GetMBNulLen(); + for ( const wchar_t * const srcEnd = src + srcLen; + src < srcEnd; + src += wxWcslen(src) + 1 /* skip L'\0' too */ ) + { + // try to convert the current chunk + size_t lenChunk = WC2MB(NULL, src, 0); + + if ( lenChunk == wxCONV_FAILED ) + return wxCONV_FAILED; + + lenChunk += lenNul; + dstWritten += lenChunk; + + if ( dst ) + { + if ( dstWritten > dstLen ) + return wxCONV_FAILED; + + if ( WC2MB(dst, src, lenChunk) == wxCONV_FAILED ) + return wxCONV_FAILED; + + dst += lenChunk; + } + } + + return dstWritten; +} + +size_t wxMBConv::MB2WC(wchar_t *outBuff, const char *inBuff, size_t outLen) const +{ + size_t rc = ToWChar(outBuff, outLen, inBuff); + if ( rc != wxCONV_FAILED ) + { + // ToWChar() returns the buffer length, i.e. including the trailing + // NUL, while this method doesn't take it into account + rc--; + } + + return rc; +} + +size_t wxMBConv::WC2MB(char *outBuff, const wchar_t *inBuff, size_t outLen) const +{ + size_t rc = FromWChar(outBuff, outLen, inBuff); + if ( rc != wxCONV_FAILED ) + { + rc -= GetMBNulLen(); + } + + return rc; +} + +wxMBConv::~wxMBConv() +{ + // nothing to do here (necessary for Darwin linking probably) +} + +const wxWCharBuffer wxMBConv::cMB2WC(const char *psz) const +{ + if ( psz ) + { + // calculate the length of the buffer needed first + const size_t nLen = MB2WC(NULL, psz, 0); + if ( nLen != wxCONV_FAILED ) + { + // now do the actual conversion + wxWCharBuffer buf(nLen /* +1 added implicitly */); + + // +1 for the trailing NULL + if ( MB2WC(buf.data(), psz, nLen + 1) != wxCONV_FAILED ) + return buf; + } + } + + return wxWCharBuffer(); +} + +const wxCharBuffer wxMBConv::cWC2MB(const wchar_t *pwz) const +{ + if ( pwz ) + { + const size_t nLen = WC2MB(NULL, pwz, 0); + if ( nLen != wxCONV_FAILED ) + { + // extra space for trailing NUL(s) + static const size_t extraLen = GetMaxMBNulLen(); + + wxCharBuffer buf(nLen + extraLen - 1); + if ( WC2MB(buf.data(), pwz, nLen + extraLen) != wxCONV_FAILED ) + return buf; + } + } + + return wxCharBuffer(); +} + +const wxWCharBuffer +wxMBConv::cMB2WC(const char *inBuff, size_t inLen, size_t *outLen) const +{ + const size_t dstLen = ToWChar(NULL, 0, inBuff, inLen); + if ( dstLen != wxCONV_FAILED ) + { + wxWCharBuffer wbuf(dstLen - 1); + if ( ToWChar(wbuf.data(), dstLen, inBuff, inLen) != wxCONV_FAILED ) + { + if ( outLen ) + { + *outLen = dstLen; + if ( wbuf[dstLen - 1] == L'\0' ) + (*outLen)--; + } + + return wbuf; + } + } + + if ( outLen ) + *outLen = 0; + + return wxWCharBuffer(); +} + +const wxCharBuffer +wxMBConv::cWC2MB(const wchar_t *inBuff, size_t inLen, size_t *outLen) const +{ + size_t dstLen = FromWChar(NULL, 0, inBuff, inLen); + if ( dstLen != wxCONV_FAILED ) + { + // special case of empty input: can't allocate 0 size buffer below as + // wxCharBuffer insists on NUL-terminating it + wxCharBuffer buf(dstLen ? dstLen - 1 : 1); + if ( FromWChar(buf.data(), dstLen, inBuff, inLen) != wxCONV_FAILED ) + { + if ( outLen ) + { + *outLen = dstLen; + + const size_t nulLen = GetMBNulLen(); + if ( dstLen >= nulLen && + !NotAllNULs(buf.data() + dstLen - nulLen, nulLen) ) + { + // in this case the output is NUL-terminated and we're not + // supposed to count NUL + *outLen -= nulLen; + } + } + + return buf; + } + } + + if ( outLen ) + *outLen = 0; + + return wxCharBuffer(); +} + +// ---------------------------------------------------------------------------- +// wxMBConvLibc +// ---------------------------------------------------------------------------- + +size_t wxMBConvLibc::MB2WC(wchar_t *buf, const char *psz, size_t n) const +{ + return wxMB2WC(buf, psz, n); +} + +size_t wxMBConvLibc::WC2MB(char *buf, const wchar_t *psz, size_t n) const +{ + return wxWC2MB(buf, psz, n); +} + +// ---------------------------------------------------------------------------- +// wxConvBrokenFileNames +// ---------------------------------------------------------------------------- + +#ifdef __UNIX__ + +wxConvBrokenFileNames::wxConvBrokenFileNames(const wxChar *charset) +{ + if ( !charset || wxStricmp(charset, _T("UTF-8")) == 0 + || wxStricmp(charset, _T("UTF8")) == 0 ) + m_conv = new wxMBConvUTF8(wxMBConvUTF8::MAP_INVALID_UTF8_TO_PUA); + else + m_conv = new wxCSConv(charset); +} + +#endif // __UNIX__ + +// ---------------------------------------------------------------------------- +// UTF-7 +// ---------------------------------------------------------------------------- + +// Implementation (C) 2004 Fredrik Roubert + +// +// BASE64 decoding table +// +static const unsigned char utf7unb64[] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +size_t wxMBConvUTF7::MB2WC(wchar_t *buf, const char *psz, size_t n) const +{ + size_t len = 0; + + while ( *psz && (!buf || (len < n)) ) + { + unsigned char cc = *psz++; + if (cc != '+') + { + // plain ASCII char + if (buf) + *buf++ = cc; + len++; + } + else if (*psz == '-') + { + // encoded plus sign + if (buf) + *buf++ = cc; + len++; + psz++; + } + else // start of BASE64 encoded string + { + bool lsb, ok; + unsigned int d, l; + for ( ok = lsb = false, d = 0, l = 0; + (cc = utf7unb64[(unsigned char)*psz]) != 0xff; + psz++ ) + { + d <<= 6; + d += cc; + for (l += 6; l >= 8; lsb = !lsb) + { + unsigned char c = (unsigned char)((d >> (l -= 8)) % 256); + if (lsb) + { + if (buf) + *buf++ |= c; + len ++; + } + else + { + if (buf) + *buf = (wchar_t)(c << 8); + } + + ok = true; + } + } + + if ( !ok ) + { + // in valid UTF7 we should have valid characters after '+' + return wxCONV_FAILED; + } + + if (*psz == '-') + psz++; + } + } + + if ( buf && (len < n) ) + *buf = '\0'; + + return len; +} + +// +// BASE64 encoding table +// +static const unsigned char utf7enb64[] = +{ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' +}; + +// +// UTF-7 encoding table +// +// 0 - Set D (directly encoded characters) +// 1 - Set O (optional direct characters) +// 2 - whitespace characters (optional) +// 3 - special characters +// +static const unsigned char utf7encode[128] = +{ + 3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 3, 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 3, 3 +}; + +size_t wxMBConvUTF7::WC2MB(char *buf, const wchar_t *psz, size_t n) const +{ + size_t len = 0; + + while (*psz && ((!buf) || (len < n))) + { + wchar_t cc = *psz++; + if (cc < 0x80 && utf7encode[cc] < 1) + { + // plain ASCII char + if (buf) + *buf++ = (char)cc; + + len++; + } +#ifndef WC_UTF16 + else if (((wxUint32)cc) > 0xffff) + { + // no surrogate pair generation (yet?) + return wxCONV_FAILED; + } +#endif + else + { + if (buf) + *buf++ = '+'; + + len++; + if (cc != '+') + { + // BASE64 encode string + unsigned int lsb, d, l; + for (d = 0, l = 0; /*nothing*/; psz++) + { + for (lsb = 0; lsb < 2; lsb ++) + { + d <<= 8; + d += lsb ? cc & 0xff : (cc & 0xff00) >> 8; + + for (l += 8; l >= 6; ) + { + l -= 6; + if (buf) + *buf++ = utf7enb64[(d >> l) % 64]; + len++; + } + } + + cc = *psz; + if (!(cc) || (cc < 0x80 && utf7encode[cc] < 1)) + break; + } + + if (l != 0) + { + if (buf) + *buf++ = utf7enb64[((d % 16) << (6 - l)) % 64]; + + len++; + } + } + + if (buf) + *buf++ = '-'; + len++; + } + } + + if (buf && (len < n)) + *buf = 0; + + return len; +} + +// ---------------------------------------------------------------------------- +// UTF-8 +// ---------------------------------------------------------------------------- + +static wxUint32 utf8_max[]= + { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff, 0xffffffff }; + +// boundaries of the private use area we use to (temporarily) remap invalid +// characters invalid in a UTF-8 encoded string +const wxUint32 wxUnicodePUA = 0x100000; +const wxUint32 wxUnicodePUAEnd = wxUnicodePUA + 256; + +size_t wxMBConvUTF8::MB2WC(wchar_t *buf, const char *psz, size_t n) const +{ + size_t len = 0; + + while (*psz && ((!buf) || (len < n))) + { + const char *opsz = psz; + bool invalid = false; + unsigned char cc = *psz++, fc = cc; + unsigned cnt; + for (cnt = 0; fc & 0x80; cnt++) + fc <<= 1; + + if (!cnt) + { + // plain ASCII char + if (buf) + *buf++ = cc; + len++; + + // escape the escape character for octal escapes + if ((m_options & MAP_INVALID_UTF8_TO_OCTAL) + && cc == '\\' && (!buf || len < n)) + { + if (buf) + *buf++ = cc; + len++; + } + } + else + { + cnt--; + if (!cnt) + { + // invalid UTF-8 sequence + invalid = true; + } + else + { + unsigned ocnt = cnt - 1; + wxUint32 res = cc & (0x3f >> cnt); + while (cnt--) + { + cc = *psz; + if ((cc & 0xC0) != 0x80) + { + // invalid UTF-8 sequence + invalid = true; + break; + } + + psz++; + res = (res << 6) | (cc & 0x3f); + } + + if (invalid || res <= utf8_max[ocnt]) + { + // illegal UTF-8 encoding + invalid = true; + } + else if ((m_options & MAP_INVALID_UTF8_TO_PUA) && + res >= wxUnicodePUA && res < wxUnicodePUAEnd) + { + // if one of our PUA characters turns up externally + // it must also be treated as an illegal sequence + // (a bit like you have to escape an escape character) + invalid = true; + } + else + { +#ifdef WC_UTF16 + // cast is ok because wchar_t == wxUuint16 if WC_UTF16 + size_t pa = encode_utf16(res, (wxUint16 *)buf); + if (pa == wxCONV_FAILED) + { + invalid = true; + } + else + { + if (buf) + buf += pa; + len += pa; + } +#else // !WC_UTF16 + if (buf) + *buf++ = (wchar_t)res; + len++; +#endif // WC_UTF16/!WC_UTF16 + } + } + + if (invalid) + { + if (m_options & MAP_INVALID_UTF8_TO_PUA) + { + while (opsz < psz && (!buf || len < n)) + { +#ifdef WC_UTF16 + // cast is ok because wchar_t == wxUuint16 if WC_UTF16 + size_t pa = encode_utf16((unsigned char)*opsz + wxUnicodePUA, (wxUint16 *)buf); + wxASSERT(pa != wxCONV_FAILED); + if (buf) + buf += pa; + opsz++; + len += pa; +#else + if (buf) + *buf++ = (wchar_t)(wxUnicodePUA + (unsigned char)*opsz); + opsz++; + len++; +#endif + } + } + else if (m_options & MAP_INVALID_UTF8_TO_OCTAL) + { + while (opsz < psz && (!buf || len < n)) + { + if ( buf && len + 3 < n ) + { + unsigned char on = *opsz; + *buf++ = L'\\'; + *buf++ = (wchar_t)( L'0' + on / 0100 ); + *buf++ = (wchar_t)( L'0' + (on % 0100) / 010 ); + *buf++ = (wchar_t)( L'0' + on % 010 ); + } + + opsz++; + len += 4; + } + } + else // MAP_INVALID_UTF8_NOT + { + return wxCONV_FAILED; + } + } + } + } + + if (buf && (len < n)) + *buf = 0; + + return len; +} + +static inline bool isoctal(wchar_t wch) +{ + return L'0' <= wch && wch <= L'7'; +} + +size_t wxMBConvUTF8::WC2MB(char *buf, const wchar_t *psz, size_t n) const +{ + size_t len = 0; + + while (*psz && ((!buf) || (len < n))) + { + wxUint32 cc; + +#ifdef WC_UTF16 + // cast is ok for WC_UTF16 + size_t pa = decode_utf16((const wxUint16 *)psz, cc); + psz += (pa == wxCONV_FAILED) ? 1 : pa; +#else + cc = (*psz++) & 0x7fffffff; +#endif + + if ( (m_options & MAP_INVALID_UTF8_TO_PUA) + && cc >= wxUnicodePUA && cc < wxUnicodePUAEnd ) + { + if (buf) + *buf++ = (char)(cc - wxUnicodePUA); + len++; + } + else if ( (m_options & MAP_INVALID_UTF8_TO_OCTAL) + && cc == L'\\' && psz[0] == L'\\' ) + { + if (buf) + *buf++ = (char)cc; + psz++; + len++; + } + else if ( (m_options & MAP_INVALID_UTF8_TO_OCTAL) && + cc == L'\\' && + isoctal(psz[0]) && isoctal(psz[1]) && isoctal(psz[2]) ) + { + if (buf) + { + *buf++ = (char) ((psz[0] - L'0') * 0100 + + (psz[1] - L'0') * 010 + + (psz[2] - L'0')); + } + + psz += 3; + len++; + } + else + { + unsigned cnt; + for (cnt = 0; cc > utf8_max[cnt]; cnt++) + { + } + + if (!cnt) + { + // plain ASCII char + if (buf) + *buf++ = (char) cc; + len++; + } + else + { + len += cnt + 1; + if (buf) + { + *buf++ = (char) ((-128 >> cnt) | ((cc >> (cnt * 6)) & (0x3f >> cnt))); + while (cnt--) + *buf++ = (char) (0x80 | ((cc >> (cnt * 6)) & 0x3f)); + } + } + } + } + + if (buf && (len < n)) + *buf = 0; + + return len; +} + +// ============================================================================ +// UTF-16 +// ============================================================================ + +#ifdef WORDS_BIGENDIAN + #define wxMBConvUTF16straight wxMBConvUTF16BE + #define wxMBConvUTF16swap wxMBConvUTF16LE +#else + #define wxMBConvUTF16swap wxMBConvUTF16BE + #define wxMBConvUTF16straight wxMBConvUTF16LE +#endif + +/* static */ +size_t wxMBConvUTF16Base::GetLength(const char *src, size_t srcLen) +{ + if ( srcLen == wxNO_LEN ) + { + // count the number of bytes in input, including the trailing NULs + const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); + for ( srcLen = 1; *inBuff++; srcLen++ ) + ; + + srcLen *= BYTES_PER_CHAR; + } + else // we already have the length + { + // we can only convert an entire number of UTF-16 characters + if ( srcLen % BYTES_PER_CHAR ) + return wxCONV_FAILED; + } + + return srcLen; +} + +// case when in-memory representation is UTF-16 too +#ifdef WC_UTF16 + +// ---------------------------------------------------------------------------- +// conversions without endianness change +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF16straight::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + // set up the scene for using memcpy() (which is presumably more efficient + // than copying the bytes one by one) + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + const size_t inLen = srcLen / BYTES_PER_CHAR; + if ( dst ) + { + if ( dstLen < inLen ) + return wxCONV_FAILED; + + memcpy(dst, src, srcLen); + } + + return inLen; +} + +size_t +wxMBConvUTF16straight::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + srcLen *= BYTES_PER_CHAR; + + if ( dst ) + { + if ( dstLen < srcLen ) + return wxCONV_FAILED; + + memcpy(dst, src, srcLen); + } + + return srcLen; +} + +// ---------------------------------------------------------------------------- +// endian-reversing conversions +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF16swap::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + srcLen /= BYTES_PER_CHAR; + + if ( dst ) + { + if ( dstLen < srcLen ) + return wxCONV_FAILED; + + const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); + for ( size_t n = 0; n < srcLen; n++, inBuff++ ) + { + *dst++ = wxUINT16_SWAP_ALWAYS(*inBuff); + } + } + + return srcLen; +} + +size_t +wxMBConvUTF16swap::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + srcLen *= BYTES_PER_CHAR; + + if ( dst ) + { + if ( dstLen < srcLen ) + return wxCONV_FAILED; + + wxUint16 *outBuff = wx_reinterpret_cast(wxUint16 *, dst); + for ( size_t n = 0; n < srcLen; n += BYTES_PER_CHAR, src++ ) + { + *outBuff++ = wxUINT16_SWAP_ALWAYS(*src); + } + } + + return srcLen; +} + +#else // !WC_UTF16: wchar_t is UTF-32 + +// ---------------------------------------------------------------------------- +// conversions without endianness change +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF16straight::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + const size_t inLen = srcLen / BYTES_PER_CHAR; + if ( !dst ) + { + // optimization: return maximal space which could be needed for this + // string even if the real size could be smaller if the buffer contains + // any surrogates + return inLen; + } + + size_t outLen = 0; + const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); + for ( const wxUint16 * const inEnd = inBuff + inLen; inBuff < inEnd; ) + { + const wxUint32 ch = wxDecodeSurrogate(&inBuff); + if ( !inBuff ) + return wxCONV_FAILED; + + if ( ++outLen > dstLen ) + return wxCONV_FAILED; + + *dst++ = ch; + } + + + return outLen; +} + +size_t +wxMBConvUTF16straight::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + size_t outLen = 0; + wxUint16 *outBuff = wx_reinterpret_cast(wxUint16 *, dst); + for ( size_t n = 0; n < srcLen; n++ ) + { + wxUint16 cc[2]; + const size_t numChars = encode_utf16(*src++, cc); + if ( numChars == wxCONV_FAILED ) + return wxCONV_FAILED; + + outLen += numChars * BYTES_PER_CHAR; + if ( outBuff ) + { + if ( outLen > dstLen ) + return wxCONV_FAILED; + + *outBuff++ = cc[0]; + if ( numChars == 2 ) + { + // second character of a surrogate + *outBuff++ = cc[1]; + } + } + } + + return outLen; +} + +// ---------------------------------------------------------------------------- +// endian-reversing conversions +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF16swap::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + const size_t inLen = srcLen / BYTES_PER_CHAR; + if ( !dst ) + { + // optimization: return maximal space which could be needed for this + // string even if the real size could be smaller if the buffer contains + // any surrogates + return inLen; + } + + size_t outLen = 0; + const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); + for ( const wxUint16 * const inEnd = inBuff + inLen; inBuff < inEnd; ) + { + wxUint32 ch; + wxUint16 tmp[2]; + + tmp[0] = wxUINT16_SWAP_ALWAYS(*inBuff); + inBuff++; + tmp[1] = wxUINT16_SWAP_ALWAYS(*inBuff); + + const size_t numChars = decode_utf16(tmp, ch); + if ( numChars == wxCONV_FAILED ) + return wxCONV_FAILED; + + if ( numChars == 2 ) + inBuff++; + + if ( ++outLen > dstLen ) + return wxCONV_FAILED; + + *dst++ = ch; + } + + + return outLen; +} + +size_t +wxMBConvUTF16swap::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + size_t outLen = 0; + wxUint16 *outBuff = wx_reinterpret_cast(wxUint16 *, dst); + for ( const wchar_t *srcEnd = src + srcLen; src < srcEnd; src++ ) + { + wxUint16 cc[2]; + const size_t numChars = encode_utf16(*src, cc); + if ( numChars == wxCONV_FAILED ) + return wxCONV_FAILED; + + outLen += numChars * BYTES_PER_CHAR; + if ( outBuff ) + { + if ( outLen > dstLen ) + return wxCONV_FAILED; + + *outBuff++ = wxUINT16_SWAP_ALWAYS(cc[0]); + if ( numChars == 2 ) + { + // second character of a surrogate + *outBuff++ = wxUINT16_SWAP_ALWAYS(cc[1]); + } + } + } + + return outLen; +} + +#endif // WC_UTF16/!WC_UTF16 + + +// ============================================================================ +// UTF-32 +// ============================================================================ + +#ifdef WORDS_BIGENDIAN + #define wxMBConvUTF32straight wxMBConvUTF32BE + #define wxMBConvUTF32swap wxMBConvUTF32LE +#else + #define wxMBConvUTF32swap wxMBConvUTF32BE + #define wxMBConvUTF32straight wxMBConvUTF32LE +#endif + + +WXDLLIMPEXP_DATA_BASE(wxMBConvUTF32LE) wxConvUTF32LE; +WXDLLIMPEXP_DATA_BASE(wxMBConvUTF32BE) wxConvUTF32BE; + +/* static */ +size_t wxMBConvUTF32Base::GetLength(const char *src, size_t srcLen) +{ + if ( srcLen == wxNO_LEN ) + { + // count the number of bytes in input, including the trailing NULs + const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); + for ( srcLen = 1; *inBuff++; srcLen++ ) + ; + + srcLen *= BYTES_PER_CHAR; + } + else // we already have the length + { + // we can only convert an entire number of UTF-32 characters + if ( srcLen % BYTES_PER_CHAR ) + return wxCONV_FAILED; + } + + return srcLen; +} + +// case when in-memory representation is UTF-16 +#ifdef WC_UTF16 + +// ---------------------------------------------------------------------------- +// conversions without endianness change +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF32straight::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); + const size_t inLen = srcLen / BYTES_PER_CHAR; + size_t outLen = 0; + for ( size_t n = 0; n < inLen; n++ ) + { + wxUint16 cc[2]; + const size_t numChars = encode_utf16(*inBuff++, cc); + if ( numChars == wxCONV_FAILED ) + return wxCONV_FAILED; + + outLen += numChars; + if ( dst ) + { + if ( outLen > dstLen ) + return wxCONV_FAILED; + + *dst++ = cc[0]; + if ( numChars == 2 ) + { + // second character of a surrogate + *dst++ = cc[1]; + } + } + } + + return outLen; +} + +size_t +wxMBConvUTF32straight::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + if ( !dst ) + { + // optimization: return maximal space which could be needed for this + // string instead of the exact amount which could be less if there are + // any surrogates in the input + // + // we consider that surrogates are rare enough to make it worthwhile to + // avoid running the loop below at the cost of slightly extra memory + // consumption + return srcLen * BYTES_PER_CHAR; + } + + wxUint32 *outBuff = wx_reinterpret_cast(wxUint32 *, dst); + size_t outLen = 0; + for ( const wchar_t * const srcEnd = src + srcLen; src < srcEnd; ) + { + const wxUint32 ch = wxDecodeSurrogate(&src); + if ( !src ) + return wxCONV_FAILED; + + outLen += BYTES_PER_CHAR; + + if ( outLen > dstLen ) + return wxCONV_FAILED; + + *outBuff++ = ch; + } + + return outLen; +} + +// ---------------------------------------------------------------------------- +// endian-reversing conversions +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF32swap::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); + const size_t inLen = srcLen / BYTES_PER_CHAR; + size_t outLen = 0; + for ( size_t n = 0; n < inLen; n++, inBuff++ ) + { + wxUint16 cc[2]; + const size_t numChars = encode_utf16(wxUINT32_SWAP_ALWAYS(*inBuff), cc); + if ( numChars == wxCONV_FAILED ) + return wxCONV_FAILED; + + outLen += numChars; + if ( dst ) + { + if ( outLen > dstLen ) + return wxCONV_FAILED; + + *dst++ = cc[0]; + if ( numChars == 2 ) + { + // second character of a surrogate + *dst++ = cc[1]; + } + } + } + + return outLen; +} + +size_t +wxMBConvUTF32swap::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + if ( !dst ) + { + // optimization: return maximal space which could be needed for this + // string instead of the exact amount which could be less if there are + // any surrogates in the input + // + // we consider that surrogates are rare enough to make it worthwhile to + // avoid running the loop below at the cost of slightly extra memory + // consumption + return srcLen*BYTES_PER_CHAR; + } + + wxUint32 *outBuff = wx_reinterpret_cast(wxUint32 *, dst); + size_t outLen = 0; + for ( const wchar_t * const srcEnd = src + srcLen; src < srcEnd; ) + { + const wxUint32 ch = wxDecodeSurrogate(&src); + if ( !src ) + return wxCONV_FAILED; + + outLen += BYTES_PER_CHAR; + + if ( outLen > dstLen ) + return wxCONV_FAILED; + + *outBuff++ = wxUINT32_SWAP_ALWAYS(ch); + } + + return outLen; +} + +#else // !WC_UTF16: wchar_t is UTF-32 + +// ---------------------------------------------------------------------------- +// conversions without endianness change +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF32straight::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + // use memcpy() as it should be much faster than hand-written loop + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + const size_t inLen = srcLen/BYTES_PER_CHAR; + if ( dst ) + { + if ( dstLen < inLen ) + return wxCONV_FAILED; + + memcpy(dst, src, srcLen); + } + + return inLen; +} + +size_t +wxMBConvUTF32straight::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + srcLen *= BYTES_PER_CHAR; + + if ( dst ) + { + if ( dstLen < srcLen ) + return wxCONV_FAILED; + + memcpy(dst, src, srcLen); + } + + return srcLen; +} + +// ---------------------------------------------------------------------------- +// endian-reversing conversions +// ---------------------------------------------------------------------------- + +size_t +wxMBConvUTF32swap::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + srcLen = GetLength(src, srcLen); + if ( srcLen == wxNO_LEN ) + return wxCONV_FAILED; + + srcLen /= BYTES_PER_CHAR; + + if ( dst ) + { + if ( dstLen < srcLen ) + return wxCONV_FAILED; + + const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); + for ( size_t n = 0; n < srcLen; n++, inBuff++ ) + { + *dst++ = wxUINT32_SWAP_ALWAYS(*inBuff); + } + } + + return srcLen; +} + +size_t +wxMBConvUTF32swap::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + srcLen *= BYTES_PER_CHAR; + + if ( dst ) + { + if ( dstLen < srcLen ) + return wxCONV_FAILED; + + wxUint32 *outBuff = wx_reinterpret_cast(wxUint32 *, dst); + for ( size_t n = 0; n < srcLen; n += BYTES_PER_CHAR, src++ ) + { + *outBuff++ = wxUINT32_SWAP_ALWAYS(*src); + } + } + + return srcLen; +} + +#endif // WC_UTF16/!WC_UTF16 + + +// ============================================================================ +// The classes doing conversion using the iconv_xxx() functions +// ============================================================================ + +#ifdef HAVE_ICONV + +// VS: glibc 2.1.3 is broken in that iconv() conversion to/from UCS4 fails with +// E2BIG if output buffer is _exactly_ as big as needed. Such case is +// (unless there's yet another bug in glibc) the only case when iconv() +// returns with (size_t)-1 (which means error) and says there are 0 bytes +// left in the input buffer -- when _real_ error occurs, +// bytes-left-in-input buffer is non-zero. Hence, this alternative test for +// iconv() failure. +// [This bug does not appear in glibc 2.2.] +#if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ <= 1 +#define ICONV_FAILED(cres, bufLeft) ((cres == (size_t)-1) && \ + (errno != E2BIG || bufLeft != 0)) +#else +#define ICONV_FAILED(cres, bufLeft) (cres == (size_t)-1) +#endif + +#define ICONV_CHAR_CAST(x) ((ICONV_CONST char **)(x)) + +#define ICONV_T_INVALID ((iconv_t)-1) + +#if SIZEOF_WCHAR_T == 4 + #define WC_BSWAP wxUINT32_SWAP_ALWAYS + #define WC_ENC wxFONTENCODING_UTF32 +#elif SIZEOF_WCHAR_T == 2 + #define WC_BSWAP wxUINT16_SWAP_ALWAYS + #define WC_ENC wxFONTENCODING_UTF16 +#else // sizeof(wchar_t) != 2 nor 4 + // does this ever happen? + #error "Unknown sizeof(wchar_t): please report this to wx-dev@lists.wxwindows.org" +#endif + +// ---------------------------------------------------------------------------- +// wxMBConv_iconv: encapsulates an iconv character set +// ---------------------------------------------------------------------------- + +class wxMBConv_iconv : public wxMBConv +{ +public: + wxMBConv_iconv(const wxChar *name); + virtual ~wxMBConv_iconv(); + + virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const; + virtual size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const; + + // classify this encoding as explained in wxMBConv::GetMBNulLen() comment + virtual size_t GetMBNulLen() const; + + virtual wxMBConv *Clone() const + { + wxMBConv_iconv *p = new wxMBConv_iconv(m_name); + p->m_minMBCharWidth = m_minMBCharWidth; + return p; + } + + bool IsOk() const + { return (m2w != ICONV_T_INVALID) && (w2m != ICONV_T_INVALID); } + +protected: + // the iconv handlers used to translate from multibyte + // to wide char and in the other direction + iconv_t m2w, + w2m; + +#if wxUSE_THREADS + // guards access to m2w and w2m objects + wxMutex m_iconvMutex; +#endif + +private: + // the name (for iconv_open()) of a wide char charset -- if none is + // available on this machine, it will remain NULL + static wxString ms_wcCharsetName; + + // true if the wide char encoding we use (i.e. ms_wcCharsetName) has + // different endian-ness than the native one + static bool ms_wcNeedsSwap; + + + // name of the encoding handled by this conversion + wxString m_name; + + // cached result of GetMBNulLen(); set to 0 meaning "unknown" + // initially + size_t m_minMBCharWidth; +}; + +// make the constructor available for unit testing +WXDLLIMPEXP_BASE wxMBConv* new_wxMBConv_iconv( const wxChar* name ) +{ + wxMBConv_iconv* result = new wxMBConv_iconv( name ); + if ( !result->IsOk() ) + { + delete result; + return 0; + } + + return result; +} + +wxString wxMBConv_iconv::ms_wcCharsetName; +bool wxMBConv_iconv::ms_wcNeedsSwap = false; + +wxMBConv_iconv::wxMBConv_iconv(const wxChar *name) + : m_name(name) +{ + m_minMBCharWidth = 0; + + // iconv operates with chars, not wxChars, but luckily it uses only ASCII + // names for the charsets + const wxCharBuffer cname(wxString(name).ToAscii()); + + // check for charset that represents wchar_t: + if ( ms_wcCharsetName.empty() ) + { + wxLogTrace(TRACE_STRCONV, _T("Looking for wide char codeset:")); + +#if wxUSE_FONTMAP + const wxChar **names = wxFontMapperBase::GetAllEncodingNames(WC_ENC); +#else // !wxUSE_FONTMAP + static const wxChar *names_static[] = + { +#if SIZEOF_WCHAR_T == 4 + _T("UCS-4"), +#elif SIZEOF_WCHAR_T == 2 + _T("UCS-2"), +#endif + NULL + }; + const wxChar **names = names_static; +#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP + + for ( ; *names && ms_wcCharsetName.empty(); ++names ) + { + const wxString nameCS(*names); + + // first try charset with explicit bytesex info (e.g. "UCS-4LE"): + wxString nameXE(nameCS); + +#ifdef WORDS_BIGENDIAN + nameXE += _T("BE"); +#else // little endian + nameXE += _T("LE"); +#endif + + wxLogTrace(TRACE_STRCONV, _T(" trying charset \"%s\""), + nameXE.c_str()); + + m2w = iconv_open(nameXE.ToAscii(), cname); + if ( m2w == ICONV_T_INVALID ) + { + // try charset w/o bytesex info (e.g. "UCS4") + wxLogTrace(TRACE_STRCONV, _T(" trying charset \"%s\""), + nameCS.c_str()); + m2w = iconv_open(nameCS.ToAscii(), cname); + + // and check for bytesex ourselves: + if ( m2w != ICONV_T_INVALID ) + { + char buf[2], *bufPtr; + wchar_t wbuf[2], *wbufPtr; + size_t insz, outsz; + size_t res; + + buf[0] = 'A'; + buf[1] = 0; + wbuf[0] = 0; + insz = 2; + outsz = SIZEOF_WCHAR_T * 2; + wbufPtr = wbuf; + bufPtr = buf; + + res = iconv( + m2w, ICONV_CHAR_CAST(&bufPtr), &insz, + (char**)&wbufPtr, &outsz); + + if (ICONV_FAILED(res, insz)) + { + wxLogLastError(wxT("iconv")); + wxLogError(_("Conversion to charset '%s' doesn't work."), + nameCS.c_str()); + } + else // ok, can convert to this encoding, remember it + { + ms_wcCharsetName = nameCS; + ms_wcNeedsSwap = wbuf[0] != (wchar_t)buf[0]; + } + } + } + else // use charset not requiring byte swapping + { + ms_wcCharsetName = nameXE; + } + } + + wxLogTrace(TRACE_STRCONV, + wxT("iconv wchar_t charset is \"%s\"%s"), + ms_wcCharsetName.empty() ? _T("") + : ms_wcCharsetName.c_str(), + ms_wcNeedsSwap ? _T(" (needs swap)") + : _T("")); + } + else // we already have ms_wcCharsetName + { + m2w = iconv_open(ms_wcCharsetName.ToAscii(), cname); + } + + if ( ms_wcCharsetName.empty() ) + { + w2m = ICONV_T_INVALID; + } + else + { + w2m = iconv_open(cname, ms_wcCharsetName.ToAscii()); + if ( w2m == ICONV_T_INVALID ) + { + wxLogTrace(TRACE_STRCONV, + wxT("\"%s\" -> \"%s\" works but not the converse!?"), + ms_wcCharsetName.c_str(), cname.data()); + } + } +} + +wxMBConv_iconv::~wxMBConv_iconv() +{ + if ( m2w != ICONV_T_INVALID ) + iconv_close(m2w); + if ( w2m != ICONV_T_INVALID ) + iconv_close(w2m); +} + +size_t wxMBConv_iconv::MB2WC(wchar_t *buf, const char *psz, size_t n) const +{ + // find the string length: notice that must be done differently for + // NUL-terminated strings and UTF-16/32 which are terminated with 2/4 NULs + size_t inbuf; + const size_t nulLen = GetMBNulLen(); + switch ( nulLen ) + { + default: + return wxCONV_FAILED; + + case 1: + inbuf = strlen(psz); // arguably more optimized than our version + break; + + case 2: + case 4: + // for UTF-16/32 not only we need to have 2/4 consecutive NULs but + // they also have to start at character boundary and not span two + // adjacent characters + const char *p; + for ( p = psz; NotAllNULs(p, nulLen); p += nulLen ) + ; + inbuf = p - psz; + break; + } + +#if wxUSE_THREADS + // NB: iconv() is MT-safe, but each thread must use its own iconv_t handle. + // Unfortunately there are a couple of global wxCSConv objects such as + // wxConvLocal that are used all over wx code, so we have to make sure + // the handle is used by at most one thread at the time. Otherwise + // only a few wx classes would be safe to use from non-main threads + // as MB<->WC conversion would fail "randomly". + wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex); +#endif // wxUSE_THREADS + + size_t outbuf = n * SIZEOF_WCHAR_T; + size_t res, cres; + // VS: Use these instead of psz, buf because iconv() modifies its arguments: + wchar_t *bufPtr = buf; + const char *pszPtr = psz; + + if (buf) + { + // have destination buffer, convert there + cres = iconv(m2w, + ICONV_CHAR_CAST(&pszPtr), &inbuf, + (char**)&bufPtr, &outbuf); + res = n - (outbuf / SIZEOF_WCHAR_T); + + if (ms_wcNeedsSwap) + { + // convert to native endianness + for ( unsigned i = 0; i < res; i++ ) + buf[n] = WC_BSWAP(buf[i]); + } + + // NUL-terminate the string if there is any space left + if (res < n) + buf[res] = 0; + } + else + { + // no destination buffer... convert using temp buffer + // to calculate destination buffer requirement + wchar_t tbuf[8]; + res = 0; + + do + { + bufPtr = tbuf; + outbuf = 8 * SIZEOF_WCHAR_T; + + cres = iconv(m2w, + ICONV_CHAR_CAST(&pszPtr), &inbuf, + (char**)&bufPtr, &outbuf ); + + res += 8 - (outbuf / SIZEOF_WCHAR_T); + } + while ((cres == (size_t)-1) && (errno == E2BIG)); + } + + if (ICONV_FAILED(cres, inbuf)) + { + //VS: it is ok if iconv fails, hence trace only + wxLogTrace(TRACE_STRCONV, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode())); + return wxCONV_FAILED; + } + + return res; +} + +size_t wxMBConv_iconv::WC2MB(char *buf, const wchar_t *psz, size_t n) const +{ +#if wxUSE_THREADS + // NB: explained in MB2WC + wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex); +#endif + + size_t inlen = wxWcslen(psz); + size_t inbuf = inlen * SIZEOF_WCHAR_T; + size_t outbuf = n; + size_t res, cres; + + wchar_t *tmpbuf = 0; + + if (ms_wcNeedsSwap) + { + // need to copy to temp buffer to switch endianness + // (doing WC_BSWAP twice on the original buffer won't help, as it + // could be in read-only memory, or be accessed in some other thread) + tmpbuf = (wchar_t *)malloc(inbuf + SIZEOF_WCHAR_T); + for ( size_t i = 0; i < inlen; i++ ) + tmpbuf[n] = WC_BSWAP(psz[i]); + + tmpbuf[inlen] = L'\0'; + psz = tmpbuf; + } + + if (buf) + { + // have destination buffer, convert there + cres = iconv( w2m, ICONV_CHAR_CAST(&psz), &inbuf, &buf, &outbuf ); + + res = n - outbuf; + + // NB: iconv was given only wcslen(psz) characters on input, and so + // it couldn't convert the trailing zero. Let's do it ourselves + // if there's some room left for it in the output buffer. + if (res < n) + buf[0] = 0; + } + else + { + // no destination buffer: convert using temp buffer + // to calculate destination buffer requirement + char tbuf[16]; + res = 0; + do + { + buf = tbuf; + outbuf = 16; + + cres = iconv( w2m, ICONV_CHAR_CAST(&psz), &inbuf, &buf, &outbuf ); + + res += 16 - outbuf; + } + while ((cres == (size_t)-1) && (errno == E2BIG)); + } + + if (ms_wcNeedsSwap) + { + free(tmpbuf); + } + + if (ICONV_FAILED(cres, inbuf)) + { + wxLogTrace(TRACE_STRCONV, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode())); + return wxCONV_FAILED; + } + + return res; +} + +size_t wxMBConv_iconv::GetMBNulLen() const +{ + if ( m_minMBCharWidth == 0 ) + { + wxMBConv_iconv * const self = wxConstCast(this, wxMBConv_iconv); + +#if wxUSE_THREADS + // NB: explained in MB2WC + wxMutexLocker lock(self->m_iconvMutex); +#endif + + const wchar_t *wnul = L""; + char buf[8]; // should be enough for NUL in any encoding + size_t inLen = sizeof(wchar_t), + outLen = WXSIZEOF(buf); + char *inBuff = (char *)wnul; + char *outBuff = buf; + if ( iconv(w2m, ICONV_CHAR_CAST(&inBuff), &inLen, &outBuff, &outLen) == (size_t)-1 ) + { + self->m_minMBCharWidth = (size_t)-1; + } + else // ok + { + self->m_minMBCharWidth = outBuff - buf; + } + } + + return m_minMBCharWidth; +} + +#endif // HAVE_ICONV + + +// ============================================================================ +// Win32 conversion classes +// ============================================================================ + +#ifdef wxHAVE_WIN32_MB2WC + +// from utils.cpp +#if wxUSE_FONTMAP +extern WXDLLIMPEXP_BASE long wxCharsetToCodepage(const wxChar *charset); +extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding); +#endif + +class wxMBConv_win32 : public wxMBConv +{ +public: + wxMBConv_win32() + { + m_CodePage = CP_ACP; + m_minMBCharWidth = 0; + } + + wxMBConv_win32(const wxMBConv_win32& conv) + : wxMBConv() + { + m_CodePage = conv.m_CodePage; + m_minMBCharWidth = conv.m_minMBCharWidth; + } + +#if wxUSE_FONTMAP + wxMBConv_win32(const wxChar* name) + { + m_CodePage = wxCharsetToCodepage(name); + m_minMBCharWidth = 0; + } + + wxMBConv_win32(wxFontEncoding encoding) + { + m_CodePage = wxEncodingToCodepage(encoding); + m_minMBCharWidth = 0; + } +#endif // wxUSE_FONTMAP + + virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const + { + // note that we have to use MB_ERR_INVALID_CHARS flag as it without it + // the behaviour is not compatible with the Unix version (using iconv) + // and break the library itself, e.g. wxTextInputStream::NextChar() + // wouldn't work if reading an incomplete MB char didn't result in an + // error + // + // Moreover, MB_ERR_INVALID_CHARS is only supported on Win 2K SP4 or + // Win XP or newer and it is not supported for UTF-[78] so we always + // use our own conversions in this case. See + // http://blogs.msdn.com/michkap/archive/2005/04/19/409566.aspx + // http://msdn.microsoft.com/library/en-us/intl/unicode_17si.asp + if ( m_CodePage == CP_UTF8 ) + { + return wxConvUTF8.MB2WC(buf, psz, n); + } + + if ( m_CodePage == CP_UTF7 ) + { + return wxConvUTF7.MB2WC(buf, psz, n); + } + + int flags = 0; + if ( (m_CodePage < 50000 && m_CodePage != CP_SYMBOL) && + IsAtLeastWin2kSP4() ) + { + flags = MB_ERR_INVALID_CHARS; + } + + const size_t len = ::MultiByteToWideChar + ( + m_CodePage, // code page + flags, // flags: fall on error + psz, // input string + -1, // its length (NUL-terminated) + buf, // output string + buf ? n : 0 // size of output buffer + ); + if ( !len ) + { + // function totally failed + return wxCONV_FAILED; + } + + // if we were really converting and didn't use MB_ERR_INVALID_CHARS, + // check if we succeeded, by doing a double trip: + if ( !flags && buf ) + { + const size_t mbLen = strlen(psz); + wxCharBuffer mbBuf(mbLen); + if ( ::WideCharToMultiByte + ( + m_CodePage, + 0, + buf, + -1, + mbBuf.data(), + mbLen + 1, // size in bytes, not length + NULL, + NULL + ) == 0 || + strcmp(mbBuf, psz) != 0 ) + { + // we didn't obtain the same thing we started from, hence + // the conversion was lossy and we consider that it failed + return wxCONV_FAILED; + } + } + + // note that it returns count of written chars for buf != NULL and size + // of the needed buffer for buf == NULL so in either case the length of + // the string (which never includes the terminating NUL) is one less + return len - 1; + } + + virtual size_t WC2MB(char *buf, const wchar_t *pwz, size_t n) const + { + /* + we have a problem here: by default, WideCharToMultiByte() may + replace characters unrepresentable in the target code page with bad + quality approximations such as turning "1/2" symbol (U+00BD) into + "1" for the code pages which don't have it and we, obviously, want + to avoid this at any price + + the trouble is that this function does it _silently_, i.e. it won't + even tell us whether it did or not... Win98/2000 and higher provide + WC_NO_BEST_FIT_CHARS but it doesn't work for the older systems and + we have to resort to a round trip, i.e. check that converting back + results in the same string -- this is, of course, expensive but + otherwise we simply can't be sure to not garble the data. + */ + + // determine if we can rely on WC_NO_BEST_FIT_CHARS: according to MSDN + // it doesn't work with CJK encodings (which we test for rather roughly + // here...) nor with UTF-7/8 nor, of course, with Windows versions not + // supporting it + BOOL usedDef wxDUMMY_INITIALIZE(false); + BOOL *pUsedDef; + int flags; + if ( CanUseNoBestFit() && m_CodePage < 50000 ) + { + // it's our lucky day + flags = WC_NO_BEST_FIT_CHARS; + pUsedDef = &usedDef; + } + else // old system or unsupported encoding + { + flags = 0; + pUsedDef = NULL; + } + + const size_t len = ::WideCharToMultiByte + ( + m_CodePage, // code page + flags, // either none or no best fit + pwz, // input string + -1, // it is (wide) NUL-terminated + buf, // output buffer + buf ? n : 0, // and its size + NULL, // default "replacement" char + pUsedDef // [out] was it used? + ); + + if ( !len ) + { + // function totally failed + return wxCONV_FAILED; + } + + // if we were really converting, check if we succeeded + if ( buf ) + { + if ( flags ) + { + // check if the conversion failed, i.e. if any replacements + // were done + if ( usedDef ) + return wxCONV_FAILED; + } + else // we must resort to double tripping... + { + wxWCharBuffer wcBuf(n); + if ( MB2WC(wcBuf.data(), buf, n) == wxCONV_FAILED || + wcscmp(wcBuf, pwz) != 0 ) + { + // we didn't obtain the same thing we started from, hence + // the conversion was lossy and we consider that it failed + return wxCONV_FAILED; + } + } + } + + // see the comment above for the reason of "len - 1" + return len - 1; + } + + virtual size_t GetMBNulLen() const + { + if ( m_minMBCharWidth == 0 ) + { + int len = ::WideCharToMultiByte + ( + m_CodePage, // code page + 0, // no flags + L"", // input string + 1, // translate just the NUL + NULL, // output buffer + 0, // and its size + NULL, // no replacement char + NULL // [out] don't care if it was used + ); + + wxMBConv_win32 * const self = wxConstCast(this, wxMBConv_win32); + switch ( len ) + { + default: + wxLogDebug(_T("Unexpected NUL length %d"), len); + self->m_minMBCharWidth = (size_t)-1; + break; + + case 0: + self->m_minMBCharWidth = (size_t)-1; + break; + + case 1: + case 2: + case 4: + self->m_minMBCharWidth = len; + break; + } + } + + return m_minMBCharWidth; + } + + virtual wxMBConv *Clone() const { return new wxMBConv_win32(*this); } + + bool IsOk() const { return m_CodePage != -1; } + +private: + static bool CanUseNoBestFit() + { + static int s_isWin98Or2k = -1; + + if ( s_isWin98Or2k == -1 ) + { + int verMaj, verMin; + switch ( wxGetOsVersion(&verMaj, &verMin) ) + { + case wxOS_WINDOWS_9X: + s_isWin98Or2k = verMaj >= 4 && verMin >= 10; + break; + + case wxOS_WINDOWS_NT: + s_isWin98Or2k = verMaj >= 5; + break; + + default: + // unknown: be conservative by default + s_isWin98Or2k = 0; + break; + } + + wxASSERT_MSG( s_isWin98Or2k != -1, _T("should be set above") ); + } + + return s_isWin98Or2k == 1; + } + + static bool IsAtLeastWin2kSP4() + { +#ifdef __WXWINCE__ + return false; +#else + static int s_isAtLeastWin2kSP4 = -1; + + if ( s_isAtLeastWin2kSP4 == -1 ) + { + OSVERSIONINFOEX ver; + + memset(&ver, 0, sizeof(ver)); + ver.dwOSVersionInfoSize = sizeof(ver); + GetVersionEx((OSVERSIONINFO*)&ver); + + s_isAtLeastWin2kSP4 = + ((ver.dwMajorVersion > 5) || // Vista+ + (ver.dwMajorVersion == 5 && ver.dwMinorVersion > 0) || // XP/2003 + (ver.dwMajorVersion == 5 && ver.dwMinorVersion == 0 && + ver.wServicePackMajor >= 4)) // 2000 SP4+ + ? 1 : 0; + } + + return s_isAtLeastWin2kSP4 == 1; +#endif + } + + + // the code page we're working with + long m_CodePage; + + // cached result of GetMBNulLen(), set to 0 initially meaning + // "unknown" + size_t m_minMBCharWidth; +}; + +#endif // wxHAVE_WIN32_MB2WC + +// ============================================================================ +// Cocoa conversion classes +// ============================================================================ + +#if defined(__WXCOCOA__) + +// RN: There is no UTF-32 support in either Core Foundation or Cocoa. +// Strangely enough, internally Core Foundation uses +// UTF-32 internally quite a bit - its just not public (yet). + +#include +#include + +CFStringEncoding wxCFStringEncFromFontEnc(wxFontEncoding encoding) +{ + CFStringEncoding enc = kCFStringEncodingInvalidId ; + + switch (encoding) + { + case wxFONTENCODING_DEFAULT : + enc = CFStringGetSystemEncoding(); + break ; + + case wxFONTENCODING_ISO8859_1 : + enc = kCFStringEncodingISOLatin1 ; + break ; + case wxFONTENCODING_ISO8859_2 : + enc = kCFStringEncodingISOLatin2; + break ; + case wxFONTENCODING_ISO8859_3 : + enc = kCFStringEncodingISOLatin3 ; + break ; + case wxFONTENCODING_ISO8859_4 : + enc = kCFStringEncodingISOLatin4; + break ; + case wxFONTENCODING_ISO8859_5 : + enc = kCFStringEncodingISOLatinCyrillic; + break ; + case wxFONTENCODING_ISO8859_6 : + enc = kCFStringEncodingISOLatinArabic; + break ; + case wxFONTENCODING_ISO8859_7 : + enc = kCFStringEncodingISOLatinGreek; + break ; + case wxFONTENCODING_ISO8859_8 : + enc = kCFStringEncodingISOLatinHebrew; + break ; + case wxFONTENCODING_ISO8859_9 : + enc = kCFStringEncodingISOLatin5; + break ; + case wxFONTENCODING_ISO8859_10 : + enc = kCFStringEncodingISOLatin6; + break ; + case wxFONTENCODING_ISO8859_11 : + enc = kCFStringEncodingISOLatinThai; + break ; + case wxFONTENCODING_ISO8859_13 : + enc = kCFStringEncodingISOLatin7; + break ; + case wxFONTENCODING_ISO8859_14 : + enc = kCFStringEncodingISOLatin8; + break ; + case wxFONTENCODING_ISO8859_15 : + enc = kCFStringEncodingISOLatin9; + break ; + + case wxFONTENCODING_KOI8 : + enc = kCFStringEncodingKOI8_R; + break ; + case wxFONTENCODING_ALTERNATIVE : // MS-DOS CP866 + enc = kCFStringEncodingDOSRussian; + break ; + +// case wxFONTENCODING_BULGARIAN : +// enc = ; +// break ; + + case wxFONTENCODING_CP437 : + enc = kCFStringEncodingDOSLatinUS ; + break ; + case wxFONTENCODING_CP850 : + enc = kCFStringEncodingDOSLatin1; + break ; + case wxFONTENCODING_CP852 : + enc = kCFStringEncodingDOSLatin2; + break ; + case wxFONTENCODING_CP855 : + enc = kCFStringEncodingDOSCyrillic; + break ; + case wxFONTENCODING_CP866 : + enc = kCFStringEncodingDOSRussian ; + break ; + case wxFONTENCODING_CP874 : + enc = kCFStringEncodingDOSThai; + break ; + case wxFONTENCODING_CP932 : + enc = kCFStringEncodingDOSJapanese; + break ; + case wxFONTENCODING_CP936 : + enc = kCFStringEncodingDOSChineseSimplif ; + break ; + case wxFONTENCODING_CP949 : + enc = kCFStringEncodingDOSKorean; + break ; + case wxFONTENCODING_CP950 : + enc = kCFStringEncodingDOSChineseTrad; + break ; + case wxFONTENCODING_CP1250 : + enc = kCFStringEncodingWindowsLatin2; + break ; + case wxFONTENCODING_CP1251 : + enc = kCFStringEncodingWindowsCyrillic ; + break ; + case wxFONTENCODING_CP1252 : + enc = kCFStringEncodingWindowsLatin1 ; + break ; + case wxFONTENCODING_CP1253 : + enc = kCFStringEncodingWindowsGreek; + break ; + case wxFONTENCODING_CP1254 : + enc = kCFStringEncodingWindowsLatin5; + break ; + case wxFONTENCODING_CP1255 : + enc = kCFStringEncodingWindowsHebrew ; + break ; + case wxFONTENCODING_CP1256 : + enc = kCFStringEncodingWindowsArabic ; + break ; + case wxFONTENCODING_CP1257 : + enc = kCFStringEncodingWindowsBalticRim; + break ; +// This only really encodes to UTF7 (if that) evidently +// case wxFONTENCODING_UTF7 : +// enc = kCFStringEncodingNonLossyASCII ; +// break ; + case wxFONTENCODING_UTF8 : + enc = kCFStringEncodingUTF8 ; + break ; + case wxFONTENCODING_EUC_JP : + enc = kCFStringEncodingEUC_JP; + break ; + case wxFONTENCODING_UTF16 : + enc = kCFStringEncodingUnicode ; + break ; + case wxFONTENCODING_MACROMAN : + enc = kCFStringEncodingMacRoman ; + break ; + case wxFONTENCODING_MACJAPANESE : + enc = kCFStringEncodingMacJapanese ; + break ; + case wxFONTENCODING_MACCHINESETRAD : + enc = kCFStringEncodingMacChineseTrad ; + break ; + case wxFONTENCODING_MACKOREAN : + enc = kCFStringEncodingMacKorean ; + break ; + case wxFONTENCODING_MACARABIC : + enc = kCFStringEncodingMacArabic ; + break ; + case wxFONTENCODING_MACHEBREW : + enc = kCFStringEncodingMacHebrew ; + break ; + case wxFONTENCODING_MACGREEK : + enc = kCFStringEncodingMacGreek ; + break ; + case wxFONTENCODING_MACCYRILLIC : + enc = kCFStringEncodingMacCyrillic ; + break ; + case wxFONTENCODING_MACDEVANAGARI : + enc = kCFStringEncodingMacDevanagari ; + break ; + case wxFONTENCODING_MACGURMUKHI : + enc = kCFStringEncodingMacGurmukhi ; + break ; + case wxFONTENCODING_MACGUJARATI : + enc = kCFStringEncodingMacGujarati ; + break ; + case wxFONTENCODING_MACORIYA : + enc = kCFStringEncodingMacOriya ; + break ; + case wxFONTENCODING_MACBENGALI : + enc = kCFStringEncodingMacBengali ; + break ; + case wxFONTENCODING_MACTAMIL : + enc = kCFStringEncodingMacTamil ; + break ; + case wxFONTENCODING_MACTELUGU : + enc = kCFStringEncodingMacTelugu ; + break ; + case wxFONTENCODING_MACKANNADA : + enc = kCFStringEncodingMacKannada ; + break ; + case wxFONTENCODING_MACMALAJALAM : + enc = kCFStringEncodingMacMalayalam ; + break ; + case wxFONTENCODING_MACSINHALESE : + enc = kCFStringEncodingMacSinhalese ; + break ; + case wxFONTENCODING_MACBURMESE : + enc = kCFStringEncodingMacBurmese ; + break ; + case wxFONTENCODING_MACKHMER : + enc = kCFStringEncodingMacKhmer ; + break ; + case wxFONTENCODING_MACTHAI : + enc = kCFStringEncodingMacThai ; + break ; + case wxFONTENCODING_MACLAOTIAN : + enc = kCFStringEncodingMacLaotian ; + break ; + case wxFONTENCODING_MACGEORGIAN : + enc = kCFStringEncodingMacGeorgian ; + break ; + case wxFONTENCODING_MACARMENIAN : + enc = kCFStringEncodingMacArmenian ; + break ; + case wxFONTENCODING_MACCHINESESIMP : + enc = kCFStringEncodingMacChineseSimp ; + break ; + case wxFONTENCODING_MACTIBETAN : + enc = kCFStringEncodingMacTibetan ; + break ; + case wxFONTENCODING_MACMONGOLIAN : + enc = kCFStringEncodingMacMongolian ; + break ; + case wxFONTENCODING_MACETHIOPIC : + enc = kCFStringEncodingMacEthiopic ; + break ; + case wxFONTENCODING_MACCENTRALEUR : + enc = kCFStringEncodingMacCentralEurRoman ; + break ; + case wxFONTENCODING_MACVIATNAMESE : + enc = kCFStringEncodingMacVietnamese ; + break ; + case wxFONTENCODING_MACARABICEXT : + enc = kCFStringEncodingMacExtArabic ; + break ; + case wxFONTENCODING_MACSYMBOL : + enc = kCFStringEncodingMacSymbol ; + break ; + case wxFONTENCODING_MACDINGBATS : + enc = kCFStringEncodingMacDingbats ; + break ; + case wxFONTENCODING_MACTURKISH : + enc = kCFStringEncodingMacTurkish ; + break ; + case wxFONTENCODING_MACCROATIAN : + enc = kCFStringEncodingMacCroatian ; + break ; + case wxFONTENCODING_MACICELANDIC : + enc = kCFStringEncodingMacIcelandic ; + break ; + case wxFONTENCODING_MACROMANIAN : + enc = kCFStringEncodingMacRomanian ; + break ; + case wxFONTENCODING_MACCELTIC : + enc = kCFStringEncodingMacCeltic ; + break ; + case wxFONTENCODING_MACGAELIC : + enc = kCFStringEncodingMacGaelic ; + break ; +// case wxFONTENCODING_MACKEYBOARD : +// enc = kCFStringEncodingMacKeyboardGlyphs ; +// break ; + + default : + // because gcc is picky + break ; + } + + return enc ; +} + +class wxMBConv_cocoa : public wxMBConv +{ +public: + wxMBConv_cocoa() + { + Init(CFStringGetSystemEncoding()) ; + } + + wxMBConv_cocoa(const wxMBConv_cocoa& conv) + { + m_encoding = conv.m_encoding; + } + +#if wxUSE_FONTMAP + wxMBConv_cocoa(const wxChar* name) + { + Init( wxCFStringEncFromFontEnc(wxFontMapperBase::Get()->CharsetToEncoding(name, false) ) ) ; + } +#endif + + wxMBConv_cocoa(wxFontEncoding encoding) + { + Init( wxCFStringEncFromFontEnc(encoding) ); + } + + virtual ~wxMBConv_cocoa() + { + } + + void Init( CFStringEncoding encoding) + { + m_encoding = encoding ; + } + + size_t MB2WC(wchar_t * szOut, const char * szUnConv, size_t nOutSize) const + { + wxASSERT(szUnConv); + + CFStringRef theString = CFStringCreateWithBytes ( + NULL, //the allocator + (const UInt8*)szUnConv, + strlen(szUnConv), + m_encoding, + false //no BOM/external representation + ); + + wxASSERT(theString); + + size_t nOutLength = CFStringGetLength(theString); + + if (szOut == NULL) + { + CFRelease(theString); + return nOutLength; + } + + CFRange theRange = { 0, nOutSize }; + +#if SIZEOF_WCHAR_T == 4 + UniChar* szUniCharBuffer = new UniChar[nOutSize]; +#endif + + CFStringGetCharacters(theString, theRange, szUniCharBuffer); + + CFRelease(theString); + + szUniCharBuffer[nOutLength] = '\0'; + +#if SIZEOF_WCHAR_T == 4 + wxMBConvUTF16 converter; + converter.MB2WC( szOut, (const char*)szUniCharBuffer, nOutSize ); + delete [] szUniCharBuffer; +#endif + + return nOutLength; + } + + size_t WC2MB(char *szOut, const wchar_t *szUnConv, size_t nOutSize) const + { + wxASSERT(szUnConv); + + size_t nRealOutSize; + size_t nBufSize = wxWcslen(szUnConv); + UniChar* szUniBuffer = (UniChar*) szUnConv; + +#if SIZEOF_WCHAR_T == 4 + wxMBConvUTF16 converter ; + nBufSize = converter.WC2MB( NULL, szUnConv, 0 ); + szUniBuffer = new UniChar[ (nBufSize / sizeof(UniChar)) + 1]; + converter.WC2MB( (char*) szUniBuffer, szUnConv, nBufSize + sizeof(UniChar)); + nBufSize /= sizeof(UniChar); +#endif + + CFStringRef theString = CFStringCreateWithCharactersNoCopy( + NULL, //allocator + szUniBuffer, + nBufSize, + kCFAllocatorNull //deallocator - we want to deallocate it ourselves + ); + + wxASSERT(theString); + + //Note that CER puts a BOM when converting to unicode + //so we check and use getchars instead in that case + if (m_encoding == kCFStringEncodingUnicode) + { + if (szOut != NULL) + CFStringGetCharacters(theString, CFRangeMake(0, nOutSize - 1), (UniChar*) szOut); + + nRealOutSize = CFStringGetLength(theString) + 1; + } + else + { + CFStringGetBytes( + theString, + CFRangeMake(0, CFStringGetLength(theString)), + m_encoding, + 0, //what to put in characters that can't be converted - + //0 tells CFString to return NULL if it meets such a character + false, //not an external representation + (UInt8*) szOut, + nOutSize, + (CFIndex*) &nRealOutSize + ); + } + + CFRelease(theString); + +#if SIZEOF_WCHAR_T == 4 + delete[] szUniBuffer; +#endif + + return nRealOutSize - 1; + } + + virtual wxMBConv *Clone() const { return new wxMBConv_cocoa(*this); } + + bool IsOk() const + { + return m_encoding != kCFStringEncodingInvalidId && + CFStringIsEncodingAvailable(m_encoding); + } + +private: + CFStringEncoding m_encoding ; +}; + +#endif // defined(__WXCOCOA__) + +// ============================================================================ +// Mac conversion classes +// ============================================================================ + +#if defined(__WXMAC__) && defined(TARGET_CARBON) + +class wxMBConv_mac : public wxMBConv +{ +public: + wxMBConv_mac() + { + Init(CFStringGetSystemEncoding()) ; + } + + wxMBConv_mac(const wxMBConv_mac& conv) + { + Init(conv.m_char_encoding); + } + +#if wxUSE_FONTMAP + wxMBConv_mac(const wxChar* name) + { + wxFontEncoding enc = wxFontMapperBase::Get()->CharsetToEncoding(name, false); + Init( (enc != wxFONTENCODING_SYSTEM) ? wxMacGetSystemEncFromFontEnc( enc ) : kTextEncodingUnknown); + } +#endif + + wxMBConv_mac(wxFontEncoding encoding) + { + Init( wxMacGetSystemEncFromFontEnc(encoding) ); + } + + virtual ~wxMBConv_mac() + { + OSStatus status = noErr ; + if (m_MB2WC_converter) + status = TECDisposeConverter(m_MB2WC_converter); + if (m_WC2MB_converter) + status = TECDisposeConverter(m_WC2MB_converter); + } + + void Init( TextEncodingBase encoding,TextEncodingVariant encodingVariant = kTextEncodingDefaultVariant , + TextEncodingFormat encodingFormat = kTextEncodingDefaultFormat) + { + m_MB2WC_converter = NULL ; + m_WC2MB_converter = NULL ; + if ( encoding != kTextEncodingUnknown ) + { + m_char_encoding = CreateTextEncoding(encoding, encodingVariant, encodingFormat) ; + m_unicode_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault, 0, kUnicode16BitFormat) ; + } + else + { + m_char_encoding = kTextEncodingUnknown; + m_unicode_encoding = kTextEncodingUnknown; + } + } + + virtual void CreateIfNeeded() const + { + if ( m_MB2WC_converter == NULL && m_WC2MB_converter == NULL && + m_char_encoding != kTextEncodingUnknown && m_unicode_encoding != kTextEncodingUnknown ) + { + OSStatus status = noErr ; + status = TECCreateConverter(&m_MB2WC_converter, + m_char_encoding, + m_unicode_encoding); + wxASSERT_MSG( status == noErr , _("Unable to create TextEncodingConverter")) ; + status = TECCreateConverter(&m_WC2MB_converter, + m_unicode_encoding, + m_char_encoding); + wxASSERT_MSG( status == noErr , _("Unable to create TextEncodingConverter")) ; + } + } + + size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const + { + CreateIfNeeded() ; + OSStatus status = noErr ; + ByteCount byteOutLen ; + ByteCount byteInLen = strlen(psz) + 1; + wchar_t *tbuf = NULL ; + UniChar* ubuf = NULL ; + size_t res = 0 ; + + if (buf == NULL) + { + // Apple specs say at least 32 + n = wxMax( 32, byteInLen ) ; + tbuf = (wchar_t*) malloc( n * SIZEOF_WCHAR_T ) ; + } + + ByteCount byteBufferLen = n * sizeof( UniChar ) ; + +#if SIZEOF_WCHAR_T == 4 + ubuf = (UniChar*) malloc( byteBufferLen + 2 ) ; +#else + ubuf = (UniChar*) (buf ? buf : tbuf) ; +#endif + { +#if wxUSE_THREADS + wxMutexLocker lock( m_MB2WC_guard ); +#endif + status = TECConvertText( + m_MB2WC_converter, (ConstTextPtr) psz, byteInLen, &byteInLen, + (TextPtr) ubuf, byteBufferLen, &byteOutLen); + } + +#if SIZEOF_WCHAR_T == 4 + // we have to terminate here, because n might be larger for the trailing zero, and if UniChar + // is not properly terminated we get random characters at the end + ubuf[byteOutLen / sizeof( UniChar ) ] = 0 ; + wxMBConvUTF16 converter ; + res = converter.MB2WC( (buf ? buf : tbuf), (const char*)ubuf, n ) ; + free( ubuf ) ; +#else + res = byteOutLen / sizeof( UniChar ) ; +#endif + + if ( buf == NULL ) + free(tbuf) ; + + if ( buf && res < n) + buf[res] = 0; + + return res ; + } + + size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const + { + CreateIfNeeded() ; + OSStatus status = noErr ; + ByteCount byteOutLen ; + ByteCount byteInLen = wxWcslen(psz) * SIZEOF_WCHAR_T ; + + char *tbuf = NULL ; + + if (buf == NULL) + { + // Apple specs say at least 32 + n = wxMax( 32, ((byteInLen / SIZEOF_WCHAR_T) * 8) + SIZEOF_WCHAR_T ); + tbuf = (char*) malloc( n ) ; + } + + ByteCount byteBufferLen = n ; + UniChar* ubuf = NULL ; + +#if SIZEOF_WCHAR_T == 4 + wxMBConvUTF16 converter ; + size_t unicharlen = converter.WC2MB( NULL, psz, 0 ) ; + byteInLen = unicharlen ; + ubuf = (UniChar*) malloc( byteInLen + 2 ) ; + converter.WC2MB( (char*) ubuf, psz, unicharlen + 2 ) ; +#else + ubuf = (UniChar*) psz ; +#endif + + { +#if wxUSE_THREADS + wxMutexLocker lock( m_WC2MB_guard ); +#endif + status = TECConvertText( + m_WC2MB_converter, (ConstTextPtr) ubuf, byteInLen, &byteInLen, + (TextPtr) (buf ? buf : tbuf), byteBufferLen, &byteOutLen); + } + +#if SIZEOF_WCHAR_T == 4 + free( ubuf ) ; +#endif + + if ( buf == NULL ) + free(tbuf) ; + + size_t res = byteOutLen ; + if ( buf && res < n) + { + buf[res] = 0; + + //we need to double-trip to verify it didn't insert any ? in place + //of bogus characters + wxWCharBuffer wcBuf(n); + size_t pszlen = wxWcslen(psz); + if ( MB2WC(wcBuf.data(), buf, n) == wxCONV_FAILED || + wxWcslen(wcBuf) != pszlen || + memcmp(wcBuf, psz, pszlen * sizeof(wchar_t)) != 0 ) + { + // we didn't obtain the same thing we started from, hence + // the conversion was lossy and we consider that it failed + return wxCONV_FAILED; + } + } + + return res ; + } + + virtual wxMBConv *Clone() const { return new wxMBConv_mac(*this); } + + bool IsOk() const + { + CreateIfNeeded() ; + return m_MB2WC_converter != NULL && m_WC2MB_converter != NULL; + } + +protected : + mutable TECObjectRef m_MB2WC_converter; + mutable TECObjectRef m_WC2MB_converter; +#if wxUSE_THREADS + mutable wxMutex m_MB2WC_guard; + mutable wxMutex m_WC2MB_guard; +#endif + + TextEncodingBase m_char_encoding; + TextEncodingBase m_unicode_encoding; +}; + +// MB is decomposed (D) normalized UTF8 + +class wxMBConv_macUTF8D : public wxMBConv_mac +{ +public : + wxMBConv_macUTF8D() + { + Init( kTextEncodingUnicodeDefault , kUnicodeNoSubset , kUnicodeUTF8Format ) ; + m_uni = NULL; + m_uniBack = NULL ; + } + + virtual ~wxMBConv_macUTF8D() + { + if (m_uni!=NULL) + DisposeUnicodeToTextInfo(&m_uni); + if (m_uniBack!=NULL) + DisposeUnicodeToTextInfo(&m_uniBack); + } + + size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const + { + CreateIfNeeded() ; + OSStatus status = noErr ; + ByteCount byteOutLen ; + ByteCount byteInLen = wxWcslen(psz) * SIZEOF_WCHAR_T ; + + char *tbuf = NULL ; + + if (buf == NULL) + { + // Apple specs say at least 32 + n = wxMax( 32, ((byteInLen / SIZEOF_WCHAR_T) * 8) + SIZEOF_WCHAR_T ); + tbuf = (char*) malloc( n ) ; + } + + ByteCount byteBufferLen = n ; + UniChar* ubuf = NULL ; + +#if SIZEOF_WCHAR_T == 4 + wxMBConvUTF16 converter ; + size_t unicharlen = converter.WC2MB( NULL, psz, 0 ) ; + byteInLen = unicharlen ; + ubuf = (UniChar*) malloc( byteInLen + 2 ) ; + converter.WC2MB( (char*) ubuf, psz, unicharlen + 2 ) ; +#else + ubuf = (UniChar*) psz ; +#endif + + // ubuf is a non-decomposed UniChar buffer + + ByteCount dcubuflen = byteInLen * 2 + 2 ; + ByteCount dcubufread , dcubufwritten ; + UniChar *dcubuf = (UniChar*) malloc( dcubuflen ) ; + + { +#if wxUSE_THREADS + wxMutexLocker lock( m_WC2MB_guard ); +#endif + ConvertFromUnicodeToText( m_uni , byteInLen , ubuf , + kUnicodeDefaultDirectionMask, 0, NULL, NULL, NULL, dcubuflen , &dcubufread , &dcubufwritten , dcubuf ) ; + + // we now convert that decomposed buffer into UTF8 + + status = TECConvertText( + m_WC2MB_converter, (ConstTextPtr) dcubuf, dcubufwritten, &dcubufread, + (TextPtr) (buf ? buf : tbuf), byteBufferLen, &byteOutLen); + } + + free( dcubuf ); + +#if SIZEOF_WCHAR_T == 4 + free( ubuf ) ; +#endif + + if ( buf == NULL ) + free(tbuf) ; + + size_t res = byteOutLen ; + if ( buf && res < n) + { + buf[res] = 0; + // don't test for round-trip fidelity yet, we cannot guarantee it yet + } + + return res ; + } + + size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const + { + CreateIfNeeded() ; + OSStatus status = noErr ; + ByteCount byteOutLen ; + ByteCount byteInLen = strlen(psz) + 1; + wchar_t *tbuf = NULL ; + UniChar* ubuf = NULL ; + size_t res = 0 ; + + if (buf == NULL) + { + // Apple specs say at least 32 + n = wxMax( 32, byteInLen ) ; + tbuf = (wchar_t*) malloc( n * SIZEOF_WCHAR_T ) ; + } + + ByteCount byteBufferLen = n * sizeof( UniChar ) ; + +#if SIZEOF_WCHAR_T == 4 + ubuf = (UniChar*) malloc( byteBufferLen + 2 ) ; +#else + ubuf = (UniChar*) (buf ? buf : tbuf) ; +#endif + + ByteCount dcubuflen = byteBufferLen * 2 + 2 ; + ByteCount dcubufread , dcubufwritten ; + UniChar *dcubuf = (UniChar*) malloc( dcubuflen ) ; + + { +#if wxUSE_THREADS + wxMutexLocker lock( m_MB2WC_guard ); +#endif + status = TECConvertText( + m_MB2WC_converter, (ConstTextPtr) psz, byteInLen, &byteInLen, + (TextPtr) dcubuf, dcubuflen, &byteOutLen); + // we have to terminate here, because n might be larger for the trailing zero, and if UniChar + // is not properly terminated we get random characters at the end + dcubuf[byteOutLen / sizeof( UniChar ) ] = 0 ; + + // now from the decomposed UniChar to properly composed uniChar + ConvertFromUnicodeToText( m_uniBack , byteOutLen , dcubuf , + kUnicodeDefaultDirectionMask, 0, NULL, NULL, NULL, dcubuflen , &dcubufread , &dcubufwritten , ubuf ) ; + } + + free( dcubuf ); + byteOutLen = dcubufwritten ; + ubuf[byteOutLen / sizeof( UniChar ) ] = 0 ; + + +#if SIZEOF_WCHAR_T == 4 + wxMBConvUTF16 converter ; + res = converter.MB2WC( (buf ? buf : tbuf), (const char*)ubuf, n ) ; + free( ubuf ) ; +#else + res = byteOutLen / sizeof( UniChar ) ; +#endif + + if ( buf == NULL ) + free(tbuf) ; + + if ( buf && res < n) + buf[res] = 0; + + return res ; + } + + virtual void CreateIfNeeded() const + { + wxMBConv_mac::CreateIfNeeded() ; + if ( m_uni == NULL ) + { + m_map.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kUnicodeNoSubset, kTextEncodingDefaultFormat); + m_map.otherEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kUnicodeCanonicalDecompVariant, kTextEncodingDefaultFormat); + m_map.mappingVersion = kUnicodeUseLatestMapping; + + OSStatus err = CreateUnicodeToTextInfo(&m_map, &m_uni); + wxASSERT_MSG( err == noErr , _(" Couldn't create the UnicodeConverter")) ; + + m_map.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kUnicodeNoSubset, kTextEncodingDefaultFormat); + m_map.otherEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kUnicodeCanonicalCompVariant, kTextEncodingDefaultFormat); + m_map.mappingVersion = kUnicodeUseLatestMapping; + err = CreateUnicodeToTextInfo(&m_map, &m_uniBack); + wxASSERT_MSG( err == noErr , _(" Couldn't create the UnicodeConverter")) ; + } + } +protected : + mutable UnicodeToTextInfo m_uni; + mutable UnicodeToTextInfo m_uniBack; + mutable UnicodeMapping m_map; +}; +#endif // defined(__WXMAC__) && defined(TARGET_CARBON) + +// ============================================================================ +// wxEncodingConverter based conversion classes +// ============================================================================ + +#if wxUSE_FONTMAP + +class wxMBConv_wxwin : public wxMBConv +{ +private: + void Init() + { + m_ok = m2w.Init(m_enc, wxFONTENCODING_UNICODE) && + w2m.Init(wxFONTENCODING_UNICODE, m_enc); + } + +public: + // temporarily just use wxEncodingConverter stuff, + // so that it works while a better implementation is built + wxMBConv_wxwin(const wxChar* name) + { + if (name) + m_enc = wxFontMapperBase::Get()->CharsetToEncoding(name, false); + else + m_enc = wxFONTENCODING_SYSTEM; + + Init(); + } + + wxMBConv_wxwin(wxFontEncoding enc) + { + m_enc = enc; + + Init(); + } + + size_t MB2WC(wchar_t *buf, const char *psz, size_t WXUNUSED(n)) const + { + size_t inbuf = strlen(psz); + if (buf) + { + if (!m2w.Convert(psz, buf)) + return wxCONV_FAILED; + } + return inbuf; + } + + size_t WC2MB(char *buf, const wchar_t *psz, size_t WXUNUSED(n)) const + { + const size_t inbuf = wxWcslen(psz); + if (buf) + { + if (!w2m.Convert(psz, buf)) + return wxCONV_FAILED; + } + + return inbuf; + } + + virtual size_t GetMBNulLen() const + { + switch ( m_enc ) + { + case wxFONTENCODING_UTF16BE: + case wxFONTENCODING_UTF16LE: + return 2; + + case wxFONTENCODING_UTF32BE: + case wxFONTENCODING_UTF32LE: + return 4; + + default: + return 1; + } + } + + virtual wxMBConv *Clone() const { return new wxMBConv_wxwin(m_enc); } + + bool IsOk() const { return m_ok; } + +public: + wxFontEncoding m_enc; + wxEncodingConverter m2w, w2m; + +private: + // were we initialized successfully? + bool m_ok; + + DECLARE_NO_COPY_CLASS(wxMBConv_wxwin) +}; + +// make the constructors available for unit testing +WXDLLIMPEXP_BASE wxMBConv* new_wxMBConv_wxwin( const wxChar* name ) +{ + wxMBConv_wxwin* result = new wxMBConv_wxwin( name ); + if ( !result->IsOk() ) + { + delete result; + return 0; + } + + return result; +} + +#endif // wxUSE_FONTMAP + +// ============================================================================ +// wxCSConv implementation +// ============================================================================ + +void wxCSConv::Init() +{ + m_name = NULL; + m_convReal = NULL; + m_deferred = true; +} + +wxCSConv::wxCSConv(const wxChar *charset) +{ + Init(); + + if ( charset ) + { + SetName(charset); + } + +#if wxUSE_FONTMAP + m_encoding = wxFontMapperBase::GetEncodingFromName(charset); + if ( m_encoding == wxFONTENCODING_MAX ) + { + // set to unknown/invalid value + m_encoding = wxFONTENCODING_SYSTEM; + } + else if ( m_encoding == wxFONTENCODING_DEFAULT ) + { + // wxFONTENCODING_DEFAULT is same as US-ASCII in this context + m_encoding = wxFONTENCODING_ISO8859_1; + } +#else + m_encoding = wxFONTENCODING_SYSTEM; +#endif +} + +wxCSConv::wxCSConv(wxFontEncoding encoding) +{ + if ( encoding == wxFONTENCODING_MAX || encoding == wxFONTENCODING_DEFAULT ) + { + wxFAIL_MSG( _T("invalid encoding value in wxCSConv ctor") ); + + encoding = wxFONTENCODING_SYSTEM; + } + + Init(); + + m_encoding = encoding; +} + +wxCSConv::~wxCSConv() +{ + Clear(); +} + +wxCSConv::wxCSConv(const wxCSConv& conv) + : wxMBConv() +{ + Init(); + + SetName(conv.m_name); + m_encoding = conv.m_encoding; +} + +wxCSConv& wxCSConv::operator=(const wxCSConv& conv) +{ + Clear(); + + SetName(conv.m_name); + m_encoding = conv.m_encoding; + + return *this; +} + +void wxCSConv::Clear() +{ + free(m_name); + delete m_convReal; + + m_name = NULL; + m_convReal = NULL; +} + +void wxCSConv::SetName(const wxChar *charset) +{ + if (charset) + { + m_name = wxStrdup(charset); + m_deferred = true; + } +} + +#if wxUSE_FONTMAP + +WX_DECLARE_HASH_MAP( wxFontEncoding, wxString, wxIntegerHash, wxIntegerEqual, + wxEncodingNameCache ); + +static wxEncodingNameCache gs_nameCache; +#endif + +wxMBConv *wxCSConv::DoCreate() const +{ +#if wxUSE_FONTMAP + wxLogTrace(TRACE_STRCONV, + wxT("creating conversion for %s"), + (m_name ? m_name + : wxFontMapperBase::GetEncodingName(m_encoding).c_str())); +#endif // wxUSE_FONTMAP + + // check for the special case of ASCII or ISO8859-1 charset: as we have + // special knowledge of it anyhow, we don't need to create a special + // conversion object + if ( m_encoding == wxFONTENCODING_ISO8859_1 || + m_encoding == wxFONTENCODING_DEFAULT ) + { + // don't convert at all + return NULL; + } + + // we trust OS to do conversion better than we can so try external + // conversion methods first + // + // the full order is: + // 1. OS conversion (iconv() under Unix or Win32 API) + // 2. hard coded conversions for UTF + // 3. wxEncodingConverter as fall back + + // step (1) +#ifdef HAVE_ICONV +#if !wxUSE_FONTMAP + if ( m_name ) +#endif // !wxUSE_FONTMAP + { + wxString name(m_name); +#if wxUSE_FONTMAP + wxFontEncoding encoding(m_encoding); +#endif + + if ( !name.empty() ) + { + wxMBConv_iconv *conv = new wxMBConv_iconv(name); + if ( conv->IsOk() ) + return conv; + + delete conv; + +#if wxUSE_FONTMAP + encoding = + wxFontMapperBase::Get()->CharsetToEncoding(name, false); +#endif // wxUSE_FONTMAP + } +#if wxUSE_FONTMAP + { + const wxEncodingNameCache::iterator it = gs_nameCache.find(encoding); + if ( it != gs_nameCache.end() ) + { + if ( it->second.empty() ) + return NULL; + + wxMBConv_iconv *conv = new wxMBConv_iconv(it->second); + if ( conv->IsOk() ) + return conv; + + delete conv; + } + + const wxChar** names = wxFontMapperBase::GetAllEncodingNames(encoding); + // CS : in case this does not return valid names (eg for MacRoman) encoding + // got a 'failure' entry in the cache all the same, although it just has to + // be created using a different method, so only store failed iconv creation + // attempts (or perhaps we shoulnd't do this at all ?) + if ( names[0] != NULL ) + { + for ( ; *names; ++names ) + { + wxMBConv_iconv *conv = new wxMBConv_iconv(*names); + if ( conv->IsOk() ) + { + gs_nameCache[encoding] = *names; + return conv; + } + + delete conv; + } + + gs_nameCache[encoding] = _T(""); // cache the failure + } + } +#endif // wxUSE_FONTMAP + } +#endif // HAVE_ICONV + +#ifdef wxHAVE_WIN32_MB2WC + { +#if wxUSE_FONTMAP + wxMBConv_win32 *conv = m_name ? new wxMBConv_win32(m_name) + : new wxMBConv_win32(m_encoding); + if ( conv->IsOk() ) + return conv; + + delete conv; +#else + return NULL; +#endif + } +#endif // wxHAVE_WIN32_MB2WC + +#if defined(__WXMAC__) + { + // leave UTF16 and UTF32 to the built-ins of wx + if ( m_name || ( m_encoding < wxFONTENCODING_UTF16BE || + ( m_encoding >= wxFONTENCODING_MACMIN && m_encoding <= wxFONTENCODING_MACMAX ) ) ) + { +#if wxUSE_FONTMAP + wxMBConv_mac *conv = m_name ? new wxMBConv_mac(m_name) + : new wxMBConv_mac(m_encoding); +#else + wxMBConv_mac *conv = new wxMBConv_mac(m_encoding); +#endif + if ( conv->IsOk() ) + return conv; + + delete conv; + } + } +#endif + +#if defined(__WXCOCOA__) + { + if ( m_name || ( m_encoding <= wxFONTENCODING_UTF16 ) ) + { +#if wxUSE_FONTMAP + wxMBConv_cocoa *conv = m_name ? new wxMBConv_cocoa(m_name) + : new wxMBConv_cocoa(m_encoding); +#else + wxMBConv_cocoa *conv = new wxMBConv_cocoa(m_encoding); +#endif + + if ( conv->IsOk() ) + return conv; + + delete conv; + } + } +#endif + // step (2) + wxFontEncoding enc = m_encoding; +#if wxUSE_FONTMAP + if ( enc == wxFONTENCODING_SYSTEM && m_name ) + { + // use "false" to suppress interactive dialogs -- we can be called from + // anywhere and popping up a dialog from here is the last thing we want to + // do + enc = wxFontMapperBase::Get()->CharsetToEncoding(m_name, false); + } +#endif // wxUSE_FONTMAP + + switch ( enc ) + { + case wxFONTENCODING_UTF7: + return new wxMBConvUTF7; + + case wxFONTENCODING_UTF8: + return new wxMBConvUTF8; + + case wxFONTENCODING_UTF16BE: + return new wxMBConvUTF16BE; + + case wxFONTENCODING_UTF16LE: + return new wxMBConvUTF16LE; + + case wxFONTENCODING_UTF32BE: + return new wxMBConvUTF32BE; + + case wxFONTENCODING_UTF32LE: + return new wxMBConvUTF32LE; + + default: + // nothing to do but put here to suppress gcc warnings + break; + } + + // step (3) +#if wxUSE_FONTMAP + { + wxMBConv_wxwin *conv = m_name ? new wxMBConv_wxwin(m_name) + : new wxMBConv_wxwin(m_encoding); + if ( conv->IsOk() ) + return conv; + + delete conv; + } +#endif // wxUSE_FONTMAP + + // NB: This is a hack to prevent deadlock. What could otherwise happen + // in Unicode build: wxConvLocal creation ends up being here + // because of some failure and logs the error. But wxLog will try to + // attach a timestamp, for which it will need wxConvLocal (to convert + // time to char* and then wchar_t*), but that fails, tries to log the + // error, but wxLog has an (already locked) critical section that + // guards the static buffer. + static bool alreadyLoggingError = false; + if (!alreadyLoggingError) + { + alreadyLoggingError = true; + wxLogError(_("Cannot convert from the charset '%s'!"), + m_name ? m_name + : +#if wxUSE_FONTMAP + wxFontMapperBase::GetEncodingDescription(m_encoding).c_str() +#else // !wxUSE_FONTMAP + wxString::Format(_("encoding %i"), m_encoding).c_str() +#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP + ); + + alreadyLoggingError = false; + } + + return NULL; +} + +void wxCSConv::CreateConvIfNeeded() const +{ + if ( m_deferred ) + { + wxCSConv *self = (wxCSConv *)this; // const_cast + + // if we don't have neither the name nor the encoding, use the default + // encoding for this system + if ( !m_name && m_encoding == wxFONTENCODING_SYSTEM ) + { +#if wxUSE_INTL + self->m_encoding = wxLocale::GetSystemEncoding(); +#else + // fallback to some reasonable default: + self->m_encoding = wxFONTENCODING_ISO8859_1; +#endif // wxUSE_INTL + } + + self->m_convReal = DoCreate(); + self->m_deferred = false; + } +} + +bool wxCSConv::IsOk() const +{ + CreateConvIfNeeded(); + + // special case: no convReal created for wxFONTENCODING_ISO8859_1 + if ( m_encoding == wxFONTENCODING_ISO8859_1 ) + return true; // always ok as we do it ourselves + + // m_convReal->IsOk() is called at its own creation, so we know it must + // be ok if m_convReal is non-NULL + return m_convReal != NULL; +} + +size_t wxCSConv::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + CreateConvIfNeeded(); + + if (m_convReal) + return m_convReal->ToWChar(dst, dstLen, src, srcLen); + + // latin-1 (direct) + if ( srcLen == wxNO_LEN ) + srcLen = strlen(src) + 1; // take trailing NUL too + + if ( dst ) + { + if ( dstLen < srcLen ) + return wxCONV_FAILED; + + for ( size_t n = 0; n < srcLen; n++ ) + dst[n] = (unsigned char)(src[n]); + } + + return srcLen; +} + +size_t wxCSConv::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + CreateConvIfNeeded(); + + if (m_convReal) + return m_convReal->FromWChar(dst, dstLen, src, srcLen); + + // latin-1 (direct) + if ( srcLen == wxNO_LEN ) + srcLen = wxWcslen(src) + 1; + + if ( dst ) + { + if ( dstLen < srcLen ) + return wxCONV_FAILED; + + for ( size_t n = 0; n < srcLen; n++ ) + { + if ( src[n] > 0xFF ) + return wxCONV_FAILED; + + dst[n] = (char)src[n]; + } + + } + else // still need to check the input validity + { + for ( size_t n = 0; n < srcLen; n++ ) + { + if ( src[n] > 0xFF ) + return wxCONV_FAILED; + } + } + + return srcLen; +} + +size_t wxCSConv::MB2WC(wchar_t *buf, const char *psz, size_t n) const +{ + // this function exists only for ABI-compatibility in 2.8 branch + return wxMBConv::MB2WC(buf, psz, n); +} + +size_t wxCSConv::WC2MB(char *buf, const wchar_t *psz, size_t n) const +{ + // this function exists only for ABI-compatibility in 2.8 branch + return wxMBConv::WC2MB(buf, psz, n); +} + +size_t wxCSConv::GetMBNulLen() const +{ + CreateConvIfNeeded(); + + if ( m_convReal ) + { + return m_convReal->GetMBNulLen(); + } + + return 1; +} + +// ---------------------------------------------------------------------------- +// globals +// ---------------------------------------------------------------------------- + +#ifdef __WINDOWS__ + static wxMBConv_win32 wxConvLibcObj; +#elif defined(__WXMAC__) && !defined(__MACH__) + static wxMBConv_mac wxConvLibcObj ; +#else + static wxMBConvLibc wxConvLibcObj; +#endif + +static wxCSConv wxConvLocalObj(wxFONTENCODING_SYSTEM); +static wxCSConv wxConvISO8859_1Obj(wxFONTENCODING_ISO8859_1); +static wxMBConvUTF7 wxConvUTF7Obj; +static wxMBConvUTF8 wxConvUTF8Obj; +#if defined(__WXMAC__) && defined(TARGET_CARBON) +static wxMBConv_macUTF8D wxConvMacUTF8DObj; +#endif +WXDLLIMPEXP_DATA_BASE(wxMBConv&) wxConvLibc = wxConvLibcObj; +WXDLLIMPEXP_DATA_BASE(wxCSConv&) wxConvLocal = wxConvLocalObj; +WXDLLIMPEXP_DATA_BASE(wxCSConv&) wxConvISO8859_1 = wxConvISO8859_1Obj; +WXDLLIMPEXP_DATA_BASE(wxMBConvUTF7&) wxConvUTF7 = wxConvUTF7Obj; +WXDLLIMPEXP_DATA_BASE(wxMBConvUTF8&) wxConvUTF8 = wxConvUTF8Obj; +WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvCurrent = &wxConvLibcObj; +WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvUI = &wxConvLocal; +WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvFileName = & +#ifdef __WXOSX__ +#if defined(__WXMAC__) && defined(TARGET_CARBON) + wxConvMacUTF8DObj; +#else + wxConvUTF8Obj; +#endif +#else // !__WXOSX__ + wxConvLibcObj; +#endif // __WXOSX__/!__WXOSX__ + +#if wxUSE_UNICODE + +wxWCharBuffer wxSafeConvertMB2WX(const char *s) +{ + if ( !s ) + return wxWCharBuffer(); + + wxWCharBuffer wbuf(wxConvLibc.cMB2WX(s)); + if ( !wbuf ) + wbuf = wxConvUTF8.cMB2WX(s); + if ( !wbuf ) + wbuf = wxConvISO8859_1.cMB2WX(s); + + return wbuf; +} + +wxCharBuffer wxSafeConvertWX2MB(const wchar_t *ws) +{ + if ( !ws ) + return wxCharBuffer(); + + wxCharBuffer buf(wxConvLibc.cWX2MB(ws)); + if ( !buf ) + buf = wxMBConvUTF8(wxMBConvUTF8::MAP_INVALID_UTF8_TO_OCTAL).cWX2MB(ws); + + return buf; +} + +#endif // wxUSE_UNICODE + +#else // !wxUSE_WCHAR_T + +// stand-ins in absence of wchar_t +WXDLLIMPEXP_DATA_BASE(wxMBConv) wxConvLibc, + wxConvISO8859_1, + wxConvLocal, + wxConvUTF8; + +WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvCurrent = NULL; + +#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T diff --git a/Source/3rd Party/wx/src/common/stream.cpp b/Source/3rd Party/wx/src/common/stream.cpp index b74364107..27a9a7cc8 100644 --- a/Source/3rd Party/wx/src/common/stream.cpp +++ b/Source/3rd Party/wx/src/common/stream.cpp @@ -1,1388 +1,1388 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/stream.cpp -// Purpose: wxStream base classes -// Author: Guilhem Lavaux -// Modified by: VZ (23.11.00) to fix realloc()ing new[]ed memory, -// general code review -// Created: 11/07/98 -// RCS-ID: $Id: stream.cpp 51662 2008-02-11 20:23:29Z VZ $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#include "wx/stream.h" - -#ifndef WX_PRECOMP - #include "wx/log.h" -#endif - -#include -#include "wx/datstrm.h" -#include "wx/textfile.h" - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// the temporary buffer size used when copying from stream to stream -#define BUF_TEMP_SIZE 4096 - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxStreamBuffer -// ---------------------------------------------------------------------------- - -void wxStreamBuffer::SetError(wxStreamError err) -{ - if ( m_stream && m_stream->m_lasterror == wxSTREAM_NO_ERROR ) - m_stream->m_lasterror = err; -} - -void wxStreamBuffer::InitBuffer() -{ - m_buffer_start = - m_buffer_end = - m_buffer_pos = NULL; - m_buffer_size = 0; - - // if we are going to allocate the buffer, we should free it later as well - m_destroybuf = true; -} - -void wxStreamBuffer::Init() -{ - InitBuffer(); - - m_fixed = true; -} - -wxStreamBuffer::wxStreamBuffer(BufMode mode) -{ - Init(); - - m_stream = NULL; - m_mode = mode; - - m_flushable = false; -} - -wxStreamBuffer::wxStreamBuffer(wxStreamBase& stream, BufMode mode) -{ - Init(); - - m_stream = &stream; - m_mode = mode; - - m_flushable = true; -} - -wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer) -{ - // doing this has big chances to lead to a crash when the source buffer is - // destroyed (otherwise assume the caller knows what he does) - wxASSERT_MSG( !buffer.m_destroybuf, - _T("it's a bad idea to copy this buffer") ); - - m_buffer_start = buffer.m_buffer_start; - m_buffer_end = buffer.m_buffer_end; - m_buffer_pos = buffer.m_buffer_pos; - m_buffer_size = buffer.m_buffer_size; - m_fixed = buffer.m_fixed; - m_flushable = buffer.m_flushable; - m_stream = buffer.m_stream; - m_mode = buffer.m_mode; - m_destroybuf = false; -} - -void wxStreamBuffer::FreeBuffer() -{ - if ( m_destroybuf ) - { - free(m_buffer_start); - m_buffer_start = NULL; - } -} - -wxStreamBuffer::~wxStreamBuffer() -{ - FreeBuffer(); -} - -wxInputStream *wxStreamBuffer::GetInputStream() const -{ - return m_mode == write ? NULL : (wxInputStream *)m_stream; -} - -wxOutputStream *wxStreamBuffer::GetOutputStream() const -{ - return m_mode == read ? NULL : (wxOutputStream *)m_stream; -} - -void wxStreamBuffer::SetBufferIO(void *buffer_start, - void *buffer_end, - bool takeOwnership) -{ - SetBufferIO(buffer_start, (char *)buffer_end - (char *)buffer_start, - takeOwnership); -} - -void wxStreamBuffer::SetBufferIO(void *start, - size_t len, - bool takeOwnership) -{ - // start by freeing the old buffer - FreeBuffer(); - - m_buffer_start = (char *)start; - m_buffer_end = m_buffer_start + len; - - m_buffer_size = len; - - // if we own it, we free it - m_destroybuf = takeOwnership; - - ResetBuffer(); -} - -void wxStreamBuffer::SetBufferIO(size_t bufsize) -{ - if ( bufsize ) - { - // this will free the old buffer and allocate the new one - SetBufferIO(malloc(bufsize), bufsize, true /* take ownership */); - } - else // no buffer size => no buffer - { - // still free the old one - FreeBuffer(); - InitBuffer(); - } -} - -void wxStreamBuffer::ResetBuffer() -{ - if ( m_stream ) - { - m_stream->Reset(); - m_stream->m_lastcount = 0; - } - - m_buffer_pos = m_mode == read && m_flushable - ? m_buffer_end - : m_buffer_start; -} - -// fill the buffer with as much data as possible (only for read buffers) -bool wxStreamBuffer::FillBuffer() -{ - wxInputStream *inStream = GetInputStream(); - - // It's legal to have no stream, so we don't complain about it just return false - if ( !inStream ) - return false; - - size_t count = inStream->OnSysRead(m_buffer_start, m_buffer_size); - if ( !count ) - return false; - - m_buffer_end = m_buffer_start + count; - m_buffer_pos = m_buffer_start; - - return true; -} - -// write the buffer contents to the stream (only for write buffers) -bool wxStreamBuffer::FlushBuffer() -{ - wxCHECK_MSG( m_flushable, false, _T("can't flush this buffer") ); - - // FIXME: what is this check for? (VZ) - if ( m_buffer_pos == m_buffer_start ) - return false; - - wxOutputStream *outStream = GetOutputStream(); - - wxCHECK_MSG( outStream, false, _T("should have a stream in wxStreamBuffer") ); - - size_t current = m_buffer_pos - m_buffer_start; - size_t count = outStream->OnSysWrite(m_buffer_start, current); - if ( count != current ) - return false; - - m_buffer_pos = m_buffer_start; - - return true; -} - -size_t wxStreamBuffer::GetDataLeft() -{ - /* Why is this done? RR. */ - if ( m_buffer_pos == m_buffer_end && m_flushable) - FillBuffer(); - - return GetBytesLeft(); -} - -// copy up to size bytes from our buffer into the provided one -void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size) -{ - // don't get more bytes than left in the buffer - size_t left = GetBytesLeft(); - - if ( size > left ) - size = left; - - memcpy(buffer, m_buffer_pos, size); - m_buffer_pos += size; -} - -// copy the contents of the provided buffer into this one -void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size) -{ - size_t left = GetBytesLeft(); - - if ( size > left ) - { - if ( m_fixed ) - { - // we can't realloc the buffer, so just copy what we can - size = left; - } - else // !m_fixed - { - // realloc the buffer to have enough space for the data - size_t delta = m_buffer_pos - m_buffer_start; - - char *startOld = m_buffer_start; - m_buffer_size += size; - m_buffer_start = (char *)realloc(m_buffer_start, m_buffer_size); - if ( !m_buffer_start ) - { - // don't leak memory if realloc() failed - m_buffer_start = startOld; - m_buffer_size -= size; - - // what else can we do? - return; - } - - // adjust the pointers invalidated by realloc() - m_buffer_pos = m_buffer_start + delta; - m_buffer_end = m_buffer_start + m_buffer_size; - } - } - - memcpy(m_buffer_pos, buffer, size); - m_buffer_pos += size; -} - -void wxStreamBuffer::PutChar(char c) -{ - wxOutputStream *outStream = GetOutputStream(); - - wxCHECK_RET( outStream, _T("should have a stream in wxStreamBuffer") ); - - // if we don't have buffer at all, just forward this call to the stream, - if ( !HasBuffer() ) - { - outStream->OnSysWrite(&c, sizeof(c)); - } - else - { - // otherwise check we have enough space left - if ( !GetDataLeft() && !FlushBuffer() ) - { - // we don't - SetError(wxSTREAM_WRITE_ERROR); - } - else - { - PutToBuffer(&c, sizeof(c)); - m_stream->m_lastcount = 1; - } - } -} - -char wxStreamBuffer::Peek() -{ - wxCHECK_MSG( m_stream && HasBuffer(), 0, - _T("should have the stream and the buffer in wxStreamBuffer") ); - - if ( !GetDataLeft() ) - { - SetError(wxSTREAM_READ_ERROR); - return 0; - } - - char c; - GetFromBuffer(&c, sizeof(c)); - m_buffer_pos--; - - return c; -} - -char wxStreamBuffer::GetChar() -{ - wxInputStream *inStream = GetInputStream(); - - wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") ); - - char c; - if ( !HasBuffer() ) - { - inStream->OnSysRead(&c, sizeof(c)); - } - else - { - if ( !GetDataLeft() ) - { - SetError(wxSTREAM_READ_ERROR); - c = 0; - } - else - { - GetFromBuffer(&c, sizeof(c)); - m_stream->m_lastcount = 1; - } - } - - return c; -} - -size_t wxStreamBuffer::Read(void *buffer, size_t size) -{ - wxASSERT_MSG( buffer, _T("Warning: Null pointer is about to be used") ); - - /* Clear buffer first */ - memset(buffer, 0x00, size); - - // lasterror is reset before all new IO calls - if ( m_stream ) - m_stream->Reset(); - - size_t readBytes; - if ( !HasBuffer() ) - { - wxInputStream *inStream = GetInputStream(); - - wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") ); - - readBytes = inStream->OnSysRead(buffer, size); - } - else // we have a buffer, use it - { - size_t orig_size = size; - - while ( size > 0 ) - { - size_t left = GetDataLeft(); - - // if the requested number of bytes if greater than the buffer - // size, read data in chunks - if ( size > left ) - { - GetFromBuffer(buffer, left); - size -= left; - buffer = (char *)buffer + left; - - if ( !FillBuffer() ) - { - SetError(wxSTREAM_EOF); - break; - } - } - else // otherwise just do it in one gulp - { - GetFromBuffer(buffer, size); - size = 0; - } - } - - readBytes = orig_size - size; - } - - if ( m_stream ) - m_stream->m_lastcount = readBytes; - - return readBytes; -} - -// this should really be called "Copy()" -size_t wxStreamBuffer::Read(wxStreamBuffer *dbuf) -{ - wxCHECK_MSG( m_mode != write, 0, _T("can't read from this buffer") ); - - char buf[BUF_TEMP_SIZE]; - size_t nRead, - total = 0; - - do - { - nRead = Read(buf, WXSIZEOF(buf)); - if ( nRead ) - { - nRead = dbuf->Write(buf, nRead); - total += nRead; - } - } - while ( nRead ); - - return total; -} - -size_t wxStreamBuffer::Write(const void *buffer, size_t size) -{ - wxASSERT_MSG( buffer, _T("Warning: Null pointer is about to be send") ); - - if (m_stream) - { - // lasterror is reset before all new IO calls - m_stream->Reset(); - } - - size_t ret; - - if ( !HasBuffer() && m_fixed ) - { - wxOutputStream *outStream = GetOutputStream(); - - wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") ); - - // no buffer, just forward the call to the stream - ret = outStream->OnSysWrite(buffer, size); - } - else // we [may] have a buffer, use it - { - size_t orig_size = size; - - while ( size > 0 ) - { - size_t left = GetBytesLeft(); - - // if the buffer is too large to fit in the stream buffer, split - // it in smaller parts - // - // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream), - // we always go to the second case. - // - // FIXME: fine, but if it fails we should (re)try writing it by - // chunks as this will (hopefully) always work (VZ) - - if ( size > left && m_fixed ) - { - PutToBuffer(buffer, left); - size -= left; - buffer = (char *)buffer + left; - - if ( !FlushBuffer() ) - { - SetError(wxSTREAM_WRITE_ERROR); - - break; - } - - m_buffer_pos = m_buffer_start; - } - else // we can do it in one gulp - { - PutToBuffer(buffer, size); - size = 0; - } - } - - ret = orig_size - size; - } - - if (m_stream) - { - // i am not entirely sure what we do this for - m_stream->m_lastcount = ret; - } - - return ret; -} - -size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf) -{ - wxCHECK_MSG( m_mode != read, 0, _T("can't write to this buffer") ); - wxCHECK_MSG( sbuf->m_mode != write, 0, _T("can't read from that buffer") ); - - char buf[BUF_TEMP_SIZE]; - size_t nWrite, - total = 0; - - do - { - size_t nRead = sbuf->Read(buf, WXSIZEOF(buf)); - if ( nRead ) - { - nWrite = Write(buf, nRead); - if ( nWrite < nRead ) - { - // put back data we couldn't copy - wxInputStream *in_stream = (wxInputStream *)sbuf->GetStream(); - - in_stream->Ungetch(buf + nWrite, nRead - nWrite); - } - - total += nWrite; - } - else - { - nWrite = 0; - } - } - while ( nWrite == WXSIZEOF(buf) ); - - return total; -} - -wxFileOffset wxStreamBuffer::Seek(wxFileOffset pos, wxSeekMode mode) -{ - wxFileOffset ret_off, diff; - - wxFileOffset last_access = GetLastAccess(); - - if ( !m_flushable ) - { - switch (mode) - { - case wxFromStart: - diff = pos; - break; - - case wxFromCurrent: - diff = pos + GetIntPosition(); - break; - - case wxFromEnd: - diff = pos + last_access; - break; - - default: - wxFAIL_MSG( _T("invalid seek mode") ); - - return wxInvalidOffset; - } - if (diff < 0 || diff > last_access) - return wxInvalidOffset; - size_t int_diff = wx_truncate_cast(size_t, diff); - wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") ); - SetIntPosition(int_diff); - return diff; - } - - switch ( mode ) - { - case wxFromStart: - // We'll try to compute an internal position later ... - ret_off = m_stream->OnSysSeek(pos, wxFromStart); - ResetBuffer(); - return ret_off; - - case wxFromCurrent: - diff = pos + GetIntPosition(); - - if ( (diff > last_access) || (diff < 0) ) - { - // We must take into account the fact that we have read - // something previously. - ret_off = m_stream->OnSysSeek(diff-last_access, wxFromCurrent); - ResetBuffer(); - return ret_off; - } - else - { - size_t int_diff = wx_truncate_cast(size_t, diff); - wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") ); - SetIntPosition(int_diff); - return pos; - } - - case wxFromEnd: - // Hard to compute: always seek to the requested position. - ret_off = m_stream->OnSysSeek(pos, wxFromEnd); - ResetBuffer(); - return ret_off; - } - - return wxInvalidOffset; -} - -wxFileOffset wxStreamBuffer::Tell() const -{ - wxFileOffset pos; - - // ask the stream for position if we have a real one - if ( m_stream ) - { - pos = m_stream->OnSysTell(); - if ( pos == wxInvalidOffset ) - return wxInvalidOffset; - } - else // no associated stream - { - pos = 0; - } - - pos += GetIntPosition(); - - if ( m_mode == read && m_flushable ) - pos -= GetLastAccess(); - - return pos; -} - -// ---------------------------------------------------------------------------- -// wxStreamBase -// ---------------------------------------------------------------------------- - -wxStreamBase::wxStreamBase() -{ - m_lasterror = wxSTREAM_NO_ERROR; - m_lastcount = 0; -} - -wxStreamBase::~wxStreamBase() -{ -} - -size_t wxStreamBase::GetSize() const -{ - wxFileOffset length = GetLength(); - if ( length == (wxFileOffset)wxInvalidOffset ) - return 0; - - const size_t len = wx_truncate_cast(size_t, length); - wxASSERT_MSG( len == length + size_t(0), _T("large files not supported") ); - - return len; -} - -wxFileOffset wxStreamBase::OnSysSeek(wxFileOffset WXUNUSED(seek), wxSeekMode WXUNUSED(mode)) -{ - return wxInvalidOffset; -} - -wxFileOffset wxStreamBase::OnSysTell() const -{ - return wxInvalidOffset; -} - -// ---------------------------------------------------------------------------- -// wxInputStream -// ---------------------------------------------------------------------------- - -wxInputStream::wxInputStream() -{ - m_wback = NULL; - m_wbacksize = - m_wbackcur = 0; -} - -wxInputStream::~wxInputStream() -{ - free(m_wback); -} - -bool wxInputStream::CanRead() const -{ - // we don't know if there is anything to read or not and by default we - // prefer to be optimistic and try to read data unless we know for sure - // there is no more of it - return m_lasterror != wxSTREAM_EOF; -} - -bool wxInputStream::Eof() const -{ - // the only way the base class can know we're at EOF is when we'd already - // tried to read beyond it in which case last error is set accordingly - return GetLastError() == wxSTREAM_EOF; -} - -char *wxInputStream::AllocSpaceWBack(size_t needed_size) -{ - // get number of bytes left from previous wback buffer - size_t toget = m_wbacksize - m_wbackcur; - - // allocate a buffer large enough to hold prev + new data - char *temp_b = (char *)malloc(needed_size + toget); - - if (!temp_b) - return NULL; - - // copy previous data (and free old buffer) if needed - if (m_wback) - { - memmove(temp_b + needed_size, m_wback + m_wbackcur, toget); - free(m_wback); - } - - // done - m_wback = temp_b; - m_wbackcur = 0; - m_wbacksize = needed_size + toget; - - return m_wback; -} - -size_t wxInputStream::GetWBack(void *buf, size_t size) -{ - wxASSERT_MSG( buf, _T("Warning: Null pointer is about to be used") ); - - /* Clear buffer first */ - memset(buf, 0x00, size); - - if (!m_wback) - return 0; - - // how many bytes do we have in the buffer? - size_t toget = m_wbacksize - m_wbackcur; - - if ( size < toget ) - { - // we won't read everything - toget = size; - } - - // copy the data from the cache - memcpy(buf, m_wback + m_wbackcur, toget); - - m_wbackcur += toget; - if ( m_wbackcur == m_wbacksize ) - { - // TODO: should we really free it here all the time? maybe keep it? - free(m_wback); - m_wback = NULL; - m_wbacksize = 0; - m_wbackcur = 0; - } - - // return the number of bytes copied - return toget; -} - -size_t wxInputStream::Ungetch(const void *buf, size_t bufsize) -{ - wxASSERT_MSG( buf, _T("Warning: Null pointer is about to be used in Ungetch()") ); - - if ( m_lasterror != wxSTREAM_NO_ERROR && m_lasterror != wxSTREAM_EOF ) - { - // can't operate on this stream until the error is cleared - return 0; - } - - char *ptrback = AllocSpaceWBack(bufsize); - if (!ptrback) - return 0; - - // Eof() shouldn't return true any longer - if ( m_lasterror == wxSTREAM_EOF ) - m_lasterror = wxSTREAM_NO_ERROR; - - memcpy(ptrback, buf, bufsize); - return bufsize; -} - -bool wxInputStream::Ungetch(char c) -{ - return Ungetch(&c, sizeof(c)) != 0; -} - -int wxInputStream::GetC() -{ - unsigned char c; - Read(&c, sizeof(c)); - return LastRead() ? c : wxEOF; -} - -wxInputStream& wxInputStream::Read(void *buf, size_t size) -{ - wxASSERT_MSG( buf, _T("Warning: Null pointer is about to be read") ); - - char *p = (char *)buf; - m_lastcount = 0; - - size_t read = GetWBack(buf, size); - for ( ;; ) - { - size -= read; - m_lastcount += read; - p += read; - - if ( !size ) - { - // we read the requested amount of data - break; - } - - if ( p != buf && !CanRead() ) - { - // we have already read something and we would block in OnSysRead() - // now: don't do it but return immediately - break; - } - - read = OnSysRead(p, size); - if ( !read ) - { - // no more data available - break; - } - } - - return *this; -} - -char wxInputStream::Peek() -{ - char c; - Read(&c, sizeof(c)); - if (m_lasterror == wxSTREAM_NO_ERROR) - { - Ungetch(c); - return c; - } - - return 0; -} - -wxInputStream& wxInputStream::Read(wxOutputStream& stream_out) -{ - size_t lastcount = 0; - char buf[BUF_TEMP_SIZE]; - - for ( ;; ) - { - size_t bytes_read = Read(buf, WXSIZEOF(buf)).LastRead(); - if ( !bytes_read ) - break; - - if ( stream_out.Write(buf, bytes_read).LastWrite() != bytes_read ) - break; - - lastcount += bytes_read; - } - - m_lastcount = lastcount; - - return *this; -} - -wxFileOffset wxInputStream::SeekI(wxFileOffset pos, wxSeekMode mode) -{ - // RR: This code is duplicated in wxBufferedInputStream. This is - // not really a good design, but buffered stream are different - // from all other in that they handle two stream-related objects, - // the stream buffer and parent stream. - - // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek - if (m_lasterror==wxSTREAM_EOF) - m_lasterror=wxSTREAM_NO_ERROR; - - /* RR: A call to SeekI() will automatically invalidate any previous - call to Ungetch(), otherwise it would be possible to SeekI() to - one position, unread some bytes there, SeekI() to another position - and the data would be corrupted. - - GRG: Could add code here to try to navigate within the wback - buffer if possible, but is it really needed? It would only work - when seeking in wxFromCurrent mode, else it would invalidate - anyway... */ - - if (m_wback) - { - wxLogDebug( wxT("Seeking in stream which has data written back to it.") ); - - free(m_wback); - m_wback = NULL; - m_wbacksize = 0; - m_wbackcur = 0; - } - - return OnSysSeek(pos, mode); -} - -wxFileOffset wxInputStream::TellI() const -{ - wxFileOffset pos = OnSysTell(); - - if (pos != wxInvalidOffset) - pos -= (m_wbacksize - m_wbackcur); - - return pos; -} - - -// ---------------------------------------------------------------------------- -// wxOutputStream -// ---------------------------------------------------------------------------- - -wxOutputStream::wxOutputStream() -{ -} - -wxOutputStream::~wxOutputStream() -{ -} - -size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer), - size_t WXUNUSED(bufsize)) -{ - return 0; -} - -void wxOutputStream::PutC(char c) -{ - Write(&c, sizeof(c)); -} - -wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size) -{ - m_lastcount = OnSysWrite(buffer, size); - return *this; -} - -wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in) -{ - stream_in.Read(*this); - return *this; -} - -wxFileOffset wxOutputStream::TellO() const -{ - return OnSysTell(); -} - -wxFileOffset wxOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode) -{ - return OnSysSeek(pos, mode); -} - -void wxOutputStream::Sync() -{ -} - - -// ---------------------------------------------------------------------------- -// wxCountingOutputStream -// ---------------------------------------------------------------------------- - -wxCountingOutputStream::wxCountingOutputStream () -{ - m_currentPos = 0; -} - -wxFileOffset wxCountingOutputStream::GetLength() const -{ - return m_lastcount; -} - -size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer), - size_t size) -{ - m_currentPos += size; - if (m_currentPos > m_lastcount) - m_lastcount = m_currentPos; - - return m_currentPos; -} - -wxFileOffset wxCountingOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - ssize_t new_pos = wx_truncate_cast(ssize_t, pos); - - switch ( mode ) - { - case wxFromStart: - wxCHECK_MSG( (wxFileOffset)new_pos == pos, wxInvalidOffset, wxT("huge position not supported") ); - break; - - case wxFromEnd: - new_pos = m_lastcount + new_pos; - wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_lastcount + pos), wxInvalidOffset, wxT("huge position not supported") ); - break; - - case wxFromCurrent: - new_pos = m_currentPos + new_pos; - wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_currentPos + pos), wxInvalidOffset, wxT("huge position not supported") ); - break; - - default: - wxFAIL_MSG( _T("invalid seek mode") ); - return wxInvalidOffset; - } - - m_currentPos = new_pos; - - if (m_currentPos > m_lastcount) - m_lastcount = m_currentPos; - - return m_currentPos; -} - -wxFileOffset wxCountingOutputStream::OnSysTell() const -{ - return m_currentPos; -} - -// ---------------------------------------------------------------------------- -// wxFilterInputStream -// ---------------------------------------------------------------------------- - -wxFilterInputStream::wxFilterInputStream() - : m_parent_i_stream(NULL), - m_owns(false) -{ -} - -wxFilterInputStream::wxFilterInputStream(wxInputStream& stream) - : m_parent_i_stream(&stream), - m_owns(false) -{ -} - -wxFilterInputStream::wxFilterInputStream(wxInputStream *stream) - : m_parent_i_stream(stream), - m_owns(true) -{ -} - -wxFilterInputStream::~wxFilterInputStream() -{ - if (m_owns) - delete m_parent_i_stream; -} - -// ---------------------------------------------------------------------------- -// wxFilterOutputStream -// ---------------------------------------------------------------------------- - -wxFilterOutputStream::wxFilterOutputStream() - : m_parent_o_stream(NULL), - m_owns(false) -{ -} - -wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream) - : m_parent_o_stream(&stream), - m_owns(false) -{ -} - -wxFilterOutputStream::wxFilterOutputStream(wxOutputStream *stream) - : m_parent_o_stream(stream), - m_owns(true) -{ -} - -bool wxFilterOutputStream::Close() -{ - if (m_parent_o_stream && m_owns) - return m_parent_o_stream->Close(); - else - return true; -} - -wxFilterOutputStream::~wxFilterOutputStream() -{ - if (m_owns) - delete m_parent_o_stream; -} - -// ---------------------------------------------------------------------------- -// wxFilterClassFactoryBase -// ---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase, wxObject) - -wxString wxFilterClassFactoryBase::PopExtension(const wxString& location) const -{ - return location.substr(0, FindExtension(location)); -} - -wxString::size_type wxFilterClassFactoryBase::FindExtension( - const wxChar *location) const -{ - size_t len = wxStrlen(location); - - for (const wxChar *const *p = GetProtocols(wxSTREAM_FILEEXT); *p; p++) - { - size_t l = wxStrlen(*p); - - if (l <= len && wxStrcmp(*p, location + len - l) == 0) - return len - l; - } - - return wxString::npos; -} - -bool wxFilterClassFactoryBase::CanHandle(const wxChar *protocol, - wxStreamProtocolType type) const -{ - if (type == wxSTREAM_FILEEXT) - return FindExtension(protocol) != wxString::npos; - else - for (const wxChar *const *p = GetProtocols(type); *p; p++) - if (wxStrcmp(*p, protocol) == 0) - return true; - - return false; -} - -// ---------------------------------------------------------------------------- -// wxFilterClassFactory -// ---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory, wxFilterClassFactoryBase) - -wxFilterClassFactory *wxFilterClassFactory::sm_first = NULL; - -void wxFilterClassFactory::Remove() -{ - if (m_next != this) - { - wxFilterClassFactory **pp = &sm_first; - - while (*pp != this) - pp = &(*pp)->m_next; - - *pp = m_next; - - m_next = this; - } -} - -// ---------------------------------------------------------------------------- -// wxBufferedInputStream -// ---------------------------------------------------------------------------- - -wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s, - wxStreamBuffer *buffer) - : wxFilterInputStream(s) -{ - if ( buffer ) - { - // use the buffer provided by the user - m_i_streambuf = buffer; - } - else // create a default buffer - { - m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read); - - m_i_streambuf->SetBufferIO(1024); - } -} - -wxBufferedInputStream::~wxBufferedInputStream() -{ - m_parent_i_stream->SeekI(-(wxFileOffset)m_i_streambuf->GetBytesLeft(), - wxFromCurrent); - - delete m_i_streambuf; -} - -char wxBufferedInputStream::Peek() -{ - return m_i_streambuf->Peek(); -} - -wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size) -{ - // reset the error flag - Reset(); - - // first read from the already cached data - m_lastcount = GetWBack(buf, size); - - // do we have to read anything more? - if ( m_lastcount < size ) - { - size -= m_lastcount; - buf = (char *)buf + m_lastcount; - - // the call to wxStreamBuffer::Read() below may reset our m_lastcount - // (but it also may not do it if the buffer is associated to another - // existing stream and wasn't created by us), so save it - size_t countOld = m_lastcount; - - // the new count of the bytes read is the count of bytes read this time - m_lastcount = m_i_streambuf->Read(buf, size); - - // plus those we had read before - m_lastcount += countOld; - } - - return *this; -} - -wxFileOffset wxBufferedInputStream::SeekI(wxFileOffset pos, wxSeekMode mode) -{ - // RR: Look at wxInputStream for comments. - - if (m_lasterror==wxSTREAM_EOF) - Reset(); - - if (m_wback) - { - wxLogDebug( wxT("Seeking in stream which has data written back to it.") ); - - free(m_wback); - m_wback = NULL; - m_wbacksize = 0; - m_wbackcur = 0; - } - - return m_i_streambuf->Seek(pos, mode); -} - -wxFileOffset wxBufferedInputStream::TellI() const -{ - wxFileOffset pos = m_i_streambuf->Tell(); - - if (pos != wxInvalidOffset) - pos -= (m_wbacksize - m_wbackcur); - - return pos; -} - -size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize) -{ - return m_parent_i_stream->Read(buffer, bufsize).LastRead(); -} - -wxFileOffset wxBufferedInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) -{ - return m_parent_i_stream->SeekI(seek, mode); -} - -wxFileOffset wxBufferedInputStream::OnSysTell() const -{ - return m_parent_i_stream->TellI(); -} - -void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer) -{ - wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") ); - - delete m_i_streambuf; - m_i_streambuf = buffer; -} - -// ---------------------------------------------------------------------------- -// wxBufferedOutputStream -// ---------------------------------------------------------------------------- - -wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s, - wxStreamBuffer *buffer) - : wxFilterOutputStream(s) -{ - if ( buffer ) - { - m_o_streambuf = buffer; - } - else // create a default one - { - m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write); - - m_o_streambuf->SetBufferIO(1024); - } -} - -wxBufferedOutputStream::~wxBufferedOutputStream() -{ - Sync(); - delete m_o_streambuf; -} - -bool wxBufferedOutputStream::Close() -{ - Sync(); - return IsOk(); -} - - -wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size) -{ - m_lastcount = 0; - m_o_streambuf->Write(buffer, size); - return *this; -} - -wxFileOffset wxBufferedOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode) -{ - Sync(); - return m_o_streambuf->Seek(pos, mode); -} - -wxFileOffset wxBufferedOutputStream::TellO() const -{ - return m_o_streambuf->Tell(); -} - -void wxBufferedOutputStream::Sync() -{ - m_o_streambuf->FlushBuffer(); - m_parent_o_stream->Sync(); -} - -size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize) -{ - return m_parent_o_stream->Write(buffer, bufsize).LastWrite(); -} - -wxFileOffset wxBufferedOutputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) -{ - return m_parent_o_stream->SeekO(seek, mode); -} - -wxFileOffset wxBufferedOutputStream::OnSysTell() const -{ - return m_parent_o_stream->TellO(); -} - -wxFileOffset wxBufferedOutputStream::GetLength() const -{ - return m_parent_o_stream->GetLength() + m_o_streambuf->GetIntPosition(); -} - -void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer) -{ - wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") ); - - delete m_o_streambuf; - m_o_streambuf = buffer; -} - -// ---------------------------------------------------------------------------- -// Some IOManip function -// ---------------------------------------------------------------------------- - -wxOutputStream& wxEndL(wxOutputStream& stream) -{ - static const wxChar *eol = wxTextFile::GetEOL(); - - return stream.Write(eol, wxStrlen(eol)); -} - -#endif // wxUSE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/stream.cpp +// Purpose: wxStream base classes +// Author: Guilhem Lavaux +// Modified by: VZ (23.11.00) to fix realloc()ing new[]ed memory, +// general code review +// Created: 11/07/98 +// RCS-ID: $Id: stream.cpp 51662 2008-02-11 20:23:29Z VZ $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#include "wx/stream.h" + +#ifndef WX_PRECOMP + #include "wx/log.h" +#endif + +#include +#include "wx/datstrm.h" +#include "wx/textfile.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// the temporary buffer size used when copying from stream to stream +#define BUF_TEMP_SIZE 4096 + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxStreamBuffer +// ---------------------------------------------------------------------------- + +void wxStreamBuffer::SetError(wxStreamError err) +{ + if ( m_stream && m_stream->m_lasterror == wxSTREAM_NO_ERROR ) + m_stream->m_lasterror = err; +} + +void wxStreamBuffer::InitBuffer() +{ + m_buffer_start = + m_buffer_end = + m_buffer_pos = NULL; + m_buffer_size = 0; + + // if we are going to allocate the buffer, we should free it later as well + m_destroybuf = true; +} + +void wxStreamBuffer::Init() +{ + InitBuffer(); + + m_fixed = true; +} + +wxStreamBuffer::wxStreamBuffer(BufMode mode) +{ + Init(); + + m_stream = NULL; + m_mode = mode; + + m_flushable = false; +} + +wxStreamBuffer::wxStreamBuffer(wxStreamBase& stream, BufMode mode) +{ + Init(); + + m_stream = &stream; + m_mode = mode; + + m_flushable = true; +} + +wxStreamBuffer::wxStreamBuffer(const wxStreamBuffer& buffer) +{ + // doing this has big chances to lead to a crash when the source buffer is + // destroyed (otherwise assume the caller knows what he does) + wxASSERT_MSG( !buffer.m_destroybuf, + _T("it's a bad idea to copy this buffer") ); + + m_buffer_start = buffer.m_buffer_start; + m_buffer_end = buffer.m_buffer_end; + m_buffer_pos = buffer.m_buffer_pos; + m_buffer_size = buffer.m_buffer_size; + m_fixed = buffer.m_fixed; + m_flushable = buffer.m_flushable; + m_stream = buffer.m_stream; + m_mode = buffer.m_mode; + m_destroybuf = false; +} + +void wxStreamBuffer::FreeBuffer() +{ + if ( m_destroybuf ) + { + free(m_buffer_start); + m_buffer_start = NULL; + } +} + +wxStreamBuffer::~wxStreamBuffer() +{ + FreeBuffer(); +} + +wxInputStream *wxStreamBuffer::GetInputStream() const +{ + return m_mode == write ? NULL : (wxInputStream *)m_stream; +} + +wxOutputStream *wxStreamBuffer::GetOutputStream() const +{ + return m_mode == read ? NULL : (wxOutputStream *)m_stream; +} + +void wxStreamBuffer::SetBufferIO(void *buffer_start, + void *buffer_end, + bool takeOwnership) +{ + SetBufferIO(buffer_start, (char *)buffer_end - (char *)buffer_start, + takeOwnership); +} + +void wxStreamBuffer::SetBufferIO(void *start, + size_t len, + bool takeOwnership) +{ + // start by freeing the old buffer + FreeBuffer(); + + m_buffer_start = (char *)start; + m_buffer_end = m_buffer_start + len; + + m_buffer_size = len; + + // if we own it, we free it + m_destroybuf = takeOwnership; + + ResetBuffer(); +} + +void wxStreamBuffer::SetBufferIO(size_t bufsize) +{ + if ( bufsize ) + { + // this will free the old buffer and allocate the new one + SetBufferIO(malloc(bufsize), bufsize, true /* take ownership */); + } + else // no buffer size => no buffer + { + // still free the old one + FreeBuffer(); + InitBuffer(); + } +} + +void wxStreamBuffer::ResetBuffer() +{ + if ( m_stream ) + { + m_stream->Reset(); + m_stream->m_lastcount = 0; + } + + m_buffer_pos = m_mode == read && m_flushable + ? m_buffer_end + : m_buffer_start; +} + +// fill the buffer with as much data as possible (only for read buffers) +bool wxStreamBuffer::FillBuffer() +{ + wxInputStream *inStream = GetInputStream(); + + // It's legal to have no stream, so we don't complain about it just return false + if ( !inStream ) + return false; + + size_t count = inStream->OnSysRead(m_buffer_start, m_buffer_size); + if ( !count ) + return false; + + m_buffer_end = m_buffer_start + count; + m_buffer_pos = m_buffer_start; + + return true; +} + +// write the buffer contents to the stream (only for write buffers) +bool wxStreamBuffer::FlushBuffer() +{ + wxCHECK_MSG( m_flushable, false, _T("can't flush this buffer") ); + + // FIXME: what is this check for? (VZ) + if ( m_buffer_pos == m_buffer_start ) + return false; + + wxOutputStream *outStream = GetOutputStream(); + + wxCHECK_MSG( outStream, false, _T("should have a stream in wxStreamBuffer") ); + + size_t current = m_buffer_pos - m_buffer_start; + size_t count = outStream->OnSysWrite(m_buffer_start, current); + if ( count != current ) + return false; + + m_buffer_pos = m_buffer_start; + + return true; +} + +size_t wxStreamBuffer::GetDataLeft() +{ + /* Why is this done? RR. */ + if ( m_buffer_pos == m_buffer_end && m_flushable) + FillBuffer(); + + return GetBytesLeft(); +} + +// copy up to size bytes from our buffer into the provided one +void wxStreamBuffer::GetFromBuffer(void *buffer, size_t size) +{ + // don't get more bytes than left in the buffer + size_t left = GetBytesLeft(); + + if ( size > left ) + size = left; + + memcpy(buffer, m_buffer_pos, size); + m_buffer_pos += size; +} + +// copy the contents of the provided buffer into this one +void wxStreamBuffer::PutToBuffer(const void *buffer, size_t size) +{ + size_t left = GetBytesLeft(); + + if ( size > left ) + { + if ( m_fixed ) + { + // we can't realloc the buffer, so just copy what we can + size = left; + } + else // !m_fixed + { + // realloc the buffer to have enough space for the data + size_t delta = m_buffer_pos - m_buffer_start; + + char *startOld = m_buffer_start; + m_buffer_size += size; + m_buffer_start = (char *)realloc(m_buffer_start, m_buffer_size); + if ( !m_buffer_start ) + { + // don't leak memory if realloc() failed + m_buffer_start = startOld; + m_buffer_size -= size; + + // what else can we do? + return; + } + + // adjust the pointers invalidated by realloc() + m_buffer_pos = m_buffer_start + delta; + m_buffer_end = m_buffer_start + m_buffer_size; + } + } + + memcpy(m_buffer_pos, buffer, size); + m_buffer_pos += size; +} + +void wxStreamBuffer::PutChar(char c) +{ + wxOutputStream *outStream = GetOutputStream(); + + wxCHECK_RET( outStream, _T("should have a stream in wxStreamBuffer") ); + + // if we don't have buffer at all, just forward this call to the stream, + if ( !HasBuffer() ) + { + outStream->OnSysWrite(&c, sizeof(c)); + } + else + { + // otherwise check we have enough space left + if ( !GetDataLeft() && !FlushBuffer() ) + { + // we don't + SetError(wxSTREAM_WRITE_ERROR); + } + else + { + PutToBuffer(&c, sizeof(c)); + m_stream->m_lastcount = 1; + } + } +} + +char wxStreamBuffer::Peek() +{ + wxCHECK_MSG( m_stream && HasBuffer(), 0, + _T("should have the stream and the buffer in wxStreamBuffer") ); + + if ( !GetDataLeft() ) + { + SetError(wxSTREAM_READ_ERROR); + return 0; + } + + char c; + GetFromBuffer(&c, sizeof(c)); + m_buffer_pos--; + + return c; +} + +char wxStreamBuffer::GetChar() +{ + wxInputStream *inStream = GetInputStream(); + + wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") ); + + char c; + if ( !HasBuffer() ) + { + inStream->OnSysRead(&c, sizeof(c)); + } + else + { + if ( !GetDataLeft() ) + { + SetError(wxSTREAM_READ_ERROR); + c = 0; + } + else + { + GetFromBuffer(&c, sizeof(c)); + m_stream->m_lastcount = 1; + } + } + + return c; +} + +size_t wxStreamBuffer::Read(void *buffer, size_t size) +{ + wxASSERT_MSG( buffer, _T("Warning: Null pointer is about to be used") ); + + /* Clear buffer first */ + memset(buffer, 0x00, size); + + // lasterror is reset before all new IO calls + if ( m_stream ) + m_stream->Reset(); + + size_t readBytes; + if ( !HasBuffer() ) + { + wxInputStream *inStream = GetInputStream(); + + wxCHECK_MSG( inStream, 0, _T("should have a stream in wxStreamBuffer") ); + + readBytes = inStream->OnSysRead(buffer, size); + } + else // we have a buffer, use it + { + size_t orig_size = size; + + while ( size > 0 ) + { + size_t left = GetDataLeft(); + + // if the requested number of bytes if greater than the buffer + // size, read data in chunks + if ( size > left ) + { + GetFromBuffer(buffer, left); + size -= left; + buffer = (char *)buffer + left; + + if ( !FillBuffer() ) + { + SetError(wxSTREAM_EOF); + break; + } + } + else // otherwise just do it in one gulp + { + GetFromBuffer(buffer, size); + size = 0; + } + } + + readBytes = orig_size - size; + } + + if ( m_stream ) + m_stream->m_lastcount = readBytes; + + return readBytes; +} + +// this should really be called "Copy()" +size_t wxStreamBuffer::Read(wxStreamBuffer *dbuf) +{ + wxCHECK_MSG( m_mode != write, 0, _T("can't read from this buffer") ); + + char buf[BUF_TEMP_SIZE]; + size_t nRead, + total = 0; + + do + { + nRead = Read(buf, WXSIZEOF(buf)); + if ( nRead ) + { + nRead = dbuf->Write(buf, nRead); + total += nRead; + } + } + while ( nRead ); + + return total; +} + +size_t wxStreamBuffer::Write(const void *buffer, size_t size) +{ + wxASSERT_MSG( buffer, _T("Warning: Null pointer is about to be send") ); + + if (m_stream) + { + // lasterror is reset before all new IO calls + m_stream->Reset(); + } + + size_t ret; + + if ( !HasBuffer() && m_fixed ) + { + wxOutputStream *outStream = GetOutputStream(); + + wxCHECK_MSG( outStream, 0, _T("should have a stream in wxStreamBuffer") ); + + // no buffer, just forward the call to the stream + ret = outStream->OnSysWrite(buffer, size); + } + else // we [may] have a buffer, use it + { + size_t orig_size = size; + + while ( size > 0 ) + { + size_t left = GetBytesLeft(); + + // if the buffer is too large to fit in the stream buffer, split + // it in smaller parts + // + // NB: If stream buffer isn't fixed (as for wxMemoryOutputStream), + // we always go to the second case. + // + // FIXME: fine, but if it fails we should (re)try writing it by + // chunks as this will (hopefully) always work (VZ) + + if ( size > left && m_fixed ) + { + PutToBuffer(buffer, left); + size -= left; + buffer = (char *)buffer + left; + + if ( !FlushBuffer() ) + { + SetError(wxSTREAM_WRITE_ERROR); + + break; + } + + m_buffer_pos = m_buffer_start; + } + else // we can do it in one gulp + { + PutToBuffer(buffer, size); + size = 0; + } + } + + ret = orig_size - size; + } + + if (m_stream) + { + // i am not entirely sure what we do this for + m_stream->m_lastcount = ret; + } + + return ret; +} + +size_t wxStreamBuffer::Write(wxStreamBuffer *sbuf) +{ + wxCHECK_MSG( m_mode != read, 0, _T("can't write to this buffer") ); + wxCHECK_MSG( sbuf->m_mode != write, 0, _T("can't read from that buffer") ); + + char buf[BUF_TEMP_SIZE]; + size_t nWrite, + total = 0; + + do + { + size_t nRead = sbuf->Read(buf, WXSIZEOF(buf)); + if ( nRead ) + { + nWrite = Write(buf, nRead); + if ( nWrite < nRead ) + { + // put back data we couldn't copy + wxInputStream *in_stream = (wxInputStream *)sbuf->GetStream(); + + in_stream->Ungetch(buf + nWrite, nRead - nWrite); + } + + total += nWrite; + } + else + { + nWrite = 0; + } + } + while ( nWrite == WXSIZEOF(buf) ); + + return total; +} + +wxFileOffset wxStreamBuffer::Seek(wxFileOffset pos, wxSeekMode mode) +{ + wxFileOffset ret_off, diff; + + wxFileOffset last_access = GetLastAccess(); + + if ( !m_flushable ) + { + switch (mode) + { + case wxFromStart: + diff = pos; + break; + + case wxFromCurrent: + diff = pos + GetIntPosition(); + break; + + case wxFromEnd: + diff = pos + last_access; + break; + + default: + wxFAIL_MSG( _T("invalid seek mode") ); + + return wxInvalidOffset; + } + if (diff < 0 || diff > last_access) + return wxInvalidOffset; + size_t int_diff = wx_truncate_cast(size_t, diff); + wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") ); + SetIntPosition(int_diff); + return diff; + } + + switch ( mode ) + { + case wxFromStart: + // We'll try to compute an internal position later ... + ret_off = m_stream->OnSysSeek(pos, wxFromStart); + ResetBuffer(); + return ret_off; + + case wxFromCurrent: + diff = pos + GetIntPosition(); + + if ( (diff > last_access) || (diff < 0) ) + { + // We must take into account the fact that we have read + // something previously. + ret_off = m_stream->OnSysSeek(diff-last_access, wxFromCurrent); + ResetBuffer(); + return ret_off; + } + else + { + size_t int_diff = wx_truncate_cast(size_t, diff); + wxCHECK_MSG( (wxFileOffset)int_diff == diff, wxInvalidOffset, wxT("huge file not supported") ); + SetIntPosition(int_diff); + return pos; + } + + case wxFromEnd: + // Hard to compute: always seek to the requested position. + ret_off = m_stream->OnSysSeek(pos, wxFromEnd); + ResetBuffer(); + return ret_off; + } + + return wxInvalidOffset; +} + +wxFileOffset wxStreamBuffer::Tell() const +{ + wxFileOffset pos; + + // ask the stream for position if we have a real one + if ( m_stream ) + { + pos = m_stream->OnSysTell(); + if ( pos == wxInvalidOffset ) + return wxInvalidOffset; + } + else // no associated stream + { + pos = 0; + } + + pos += GetIntPosition(); + + if ( m_mode == read && m_flushable ) + pos -= GetLastAccess(); + + return pos; +} + +// ---------------------------------------------------------------------------- +// wxStreamBase +// ---------------------------------------------------------------------------- + +wxStreamBase::wxStreamBase() +{ + m_lasterror = wxSTREAM_NO_ERROR; + m_lastcount = 0; +} + +wxStreamBase::~wxStreamBase() +{ +} + +size_t wxStreamBase::GetSize() const +{ + wxFileOffset length = GetLength(); + if ( length == (wxFileOffset)wxInvalidOffset ) + return 0; + + const size_t len = wx_truncate_cast(size_t, length); + wxASSERT_MSG( len == length + size_t(0), _T("large files not supported") ); + + return len; +} + +wxFileOffset wxStreamBase::OnSysSeek(wxFileOffset WXUNUSED(seek), wxSeekMode WXUNUSED(mode)) +{ + return wxInvalidOffset; +} + +wxFileOffset wxStreamBase::OnSysTell() const +{ + return wxInvalidOffset; +} + +// ---------------------------------------------------------------------------- +// wxInputStream +// ---------------------------------------------------------------------------- + +wxInputStream::wxInputStream() +{ + m_wback = NULL; + m_wbacksize = + m_wbackcur = 0; +} + +wxInputStream::~wxInputStream() +{ + free(m_wback); +} + +bool wxInputStream::CanRead() const +{ + // we don't know if there is anything to read or not and by default we + // prefer to be optimistic and try to read data unless we know for sure + // there is no more of it + return m_lasterror != wxSTREAM_EOF; +} + +bool wxInputStream::Eof() const +{ + // the only way the base class can know we're at EOF is when we'd already + // tried to read beyond it in which case last error is set accordingly + return GetLastError() == wxSTREAM_EOF; +} + +char *wxInputStream::AllocSpaceWBack(size_t needed_size) +{ + // get number of bytes left from previous wback buffer + size_t toget = m_wbacksize - m_wbackcur; + + // allocate a buffer large enough to hold prev + new data + char *temp_b = (char *)malloc(needed_size + toget); + + if (!temp_b) + return NULL; + + // copy previous data (and free old buffer) if needed + if (m_wback) + { + memmove(temp_b + needed_size, m_wback + m_wbackcur, toget); + free(m_wback); + } + + // done + m_wback = temp_b; + m_wbackcur = 0; + m_wbacksize = needed_size + toget; + + return m_wback; +} + +size_t wxInputStream::GetWBack(void *buf, size_t size) +{ + wxASSERT_MSG( buf, _T("Warning: Null pointer is about to be used") ); + + /* Clear buffer first */ + memset(buf, 0x00, size); + + if (!m_wback) + return 0; + + // how many bytes do we have in the buffer? + size_t toget = m_wbacksize - m_wbackcur; + + if ( size < toget ) + { + // we won't read everything + toget = size; + } + + // copy the data from the cache + memcpy(buf, m_wback + m_wbackcur, toget); + + m_wbackcur += toget; + if ( m_wbackcur == m_wbacksize ) + { + // TODO: should we really free it here all the time? maybe keep it? + free(m_wback); + m_wback = NULL; + m_wbacksize = 0; + m_wbackcur = 0; + } + + // return the number of bytes copied + return toget; +} + +size_t wxInputStream::Ungetch(const void *buf, size_t bufsize) +{ + wxASSERT_MSG( buf, _T("Warning: Null pointer is about to be used in Ungetch()") ); + + if ( m_lasterror != wxSTREAM_NO_ERROR && m_lasterror != wxSTREAM_EOF ) + { + // can't operate on this stream until the error is cleared + return 0; + } + + char *ptrback = AllocSpaceWBack(bufsize); + if (!ptrback) + return 0; + + // Eof() shouldn't return true any longer + if ( m_lasterror == wxSTREAM_EOF ) + m_lasterror = wxSTREAM_NO_ERROR; + + memcpy(ptrback, buf, bufsize); + return bufsize; +} + +bool wxInputStream::Ungetch(char c) +{ + return Ungetch(&c, sizeof(c)) != 0; +} + +int wxInputStream::GetC() +{ + unsigned char c; + Read(&c, sizeof(c)); + return LastRead() ? c : wxEOF; +} + +wxInputStream& wxInputStream::Read(void *buf, size_t size) +{ + wxASSERT_MSG( buf, _T("Warning: Null pointer is about to be read") ); + + char *p = (char *)buf; + m_lastcount = 0; + + size_t read = GetWBack(buf, size); + for ( ;; ) + { + size -= read; + m_lastcount += read; + p += read; + + if ( !size ) + { + // we read the requested amount of data + break; + } + + if ( p != buf && !CanRead() ) + { + // we have already read something and we would block in OnSysRead() + // now: don't do it but return immediately + break; + } + + read = OnSysRead(p, size); + if ( !read ) + { + // no more data available + break; + } + } + + return *this; +} + +char wxInputStream::Peek() +{ + char c; + Read(&c, sizeof(c)); + if (m_lasterror == wxSTREAM_NO_ERROR) + { + Ungetch(c); + return c; + } + + return 0; +} + +wxInputStream& wxInputStream::Read(wxOutputStream& stream_out) +{ + size_t lastcount = 0; + char buf[BUF_TEMP_SIZE]; + + for ( ;; ) + { + size_t bytes_read = Read(buf, WXSIZEOF(buf)).LastRead(); + if ( !bytes_read ) + break; + + if ( stream_out.Write(buf, bytes_read).LastWrite() != bytes_read ) + break; + + lastcount += bytes_read; + } + + m_lastcount = lastcount; + + return *this; +} + +wxFileOffset wxInputStream::SeekI(wxFileOffset pos, wxSeekMode mode) +{ + // RR: This code is duplicated in wxBufferedInputStream. This is + // not really a good design, but buffered stream are different + // from all other in that they handle two stream-related objects, + // the stream buffer and parent stream. + + // I don't know whether it should be put as well in wxFileInputStream::OnSysSeek + if (m_lasterror==wxSTREAM_EOF) + m_lasterror=wxSTREAM_NO_ERROR; + + /* RR: A call to SeekI() will automatically invalidate any previous + call to Ungetch(), otherwise it would be possible to SeekI() to + one position, unread some bytes there, SeekI() to another position + and the data would be corrupted. + + GRG: Could add code here to try to navigate within the wback + buffer if possible, but is it really needed? It would only work + when seeking in wxFromCurrent mode, else it would invalidate + anyway... */ + + if (m_wback) + { + wxLogDebug( wxT("Seeking in stream which has data written back to it.") ); + + free(m_wback); + m_wback = NULL; + m_wbacksize = 0; + m_wbackcur = 0; + } + + return OnSysSeek(pos, mode); +} + +wxFileOffset wxInputStream::TellI() const +{ + wxFileOffset pos = OnSysTell(); + + if (pos != wxInvalidOffset) + pos -= (m_wbacksize - m_wbackcur); + + return pos; +} + + +// ---------------------------------------------------------------------------- +// wxOutputStream +// ---------------------------------------------------------------------------- + +wxOutputStream::wxOutputStream() +{ +} + +wxOutputStream::~wxOutputStream() +{ +} + +size_t wxOutputStream::OnSysWrite(const void * WXUNUSED(buffer), + size_t WXUNUSED(bufsize)) +{ + return 0; +} + +void wxOutputStream::PutC(char c) +{ + Write(&c, sizeof(c)); +} + +wxOutputStream& wxOutputStream::Write(const void *buffer, size_t size) +{ + m_lastcount = OnSysWrite(buffer, size); + return *this; +} + +wxOutputStream& wxOutputStream::Write(wxInputStream& stream_in) +{ + stream_in.Read(*this); + return *this; +} + +wxFileOffset wxOutputStream::TellO() const +{ + return OnSysTell(); +} + +wxFileOffset wxOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode) +{ + return OnSysSeek(pos, mode); +} + +void wxOutputStream::Sync() +{ +} + + +// ---------------------------------------------------------------------------- +// wxCountingOutputStream +// ---------------------------------------------------------------------------- + +wxCountingOutputStream::wxCountingOutputStream () +{ + m_currentPos = 0; +} + +wxFileOffset wxCountingOutputStream::GetLength() const +{ + return m_lastcount; +} + +size_t wxCountingOutputStream::OnSysWrite(const void *WXUNUSED(buffer), + size_t size) +{ + m_currentPos += size; + if (m_currentPos > m_lastcount) + m_lastcount = m_currentPos; + + return m_currentPos; +} + +wxFileOffset wxCountingOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + ssize_t new_pos = wx_truncate_cast(ssize_t, pos); + + switch ( mode ) + { + case wxFromStart: + wxCHECK_MSG( (wxFileOffset)new_pos == pos, wxInvalidOffset, wxT("huge position not supported") ); + break; + + case wxFromEnd: + new_pos = m_lastcount + new_pos; + wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_lastcount + pos), wxInvalidOffset, wxT("huge position not supported") ); + break; + + case wxFromCurrent: + new_pos = m_currentPos + new_pos; + wxCHECK_MSG( (wxFileOffset)new_pos == (wxFileOffset)(m_currentPos + pos), wxInvalidOffset, wxT("huge position not supported") ); + break; + + default: + wxFAIL_MSG( _T("invalid seek mode") ); + return wxInvalidOffset; + } + + m_currentPos = new_pos; + + if (m_currentPos > m_lastcount) + m_lastcount = m_currentPos; + + return m_currentPos; +} + +wxFileOffset wxCountingOutputStream::OnSysTell() const +{ + return m_currentPos; +} + +// ---------------------------------------------------------------------------- +// wxFilterInputStream +// ---------------------------------------------------------------------------- + +wxFilterInputStream::wxFilterInputStream() + : m_parent_i_stream(NULL), + m_owns(false) +{ +} + +wxFilterInputStream::wxFilterInputStream(wxInputStream& stream) + : m_parent_i_stream(&stream), + m_owns(false) +{ +} + +wxFilterInputStream::wxFilterInputStream(wxInputStream *stream) + : m_parent_i_stream(stream), + m_owns(true) +{ +} + +wxFilterInputStream::~wxFilterInputStream() +{ + if (m_owns) + delete m_parent_i_stream; +} + +// ---------------------------------------------------------------------------- +// wxFilterOutputStream +// ---------------------------------------------------------------------------- + +wxFilterOutputStream::wxFilterOutputStream() + : m_parent_o_stream(NULL), + m_owns(false) +{ +} + +wxFilterOutputStream::wxFilterOutputStream(wxOutputStream& stream) + : m_parent_o_stream(&stream), + m_owns(false) +{ +} + +wxFilterOutputStream::wxFilterOutputStream(wxOutputStream *stream) + : m_parent_o_stream(stream), + m_owns(true) +{ +} + +bool wxFilterOutputStream::Close() +{ + if (m_parent_o_stream && m_owns) + return m_parent_o_stream->Close(); + else + return true; +} + +wxFilterOutputStream::~wxFilterOutputStream() +{ + if (m_owns) + delete m_parent_o_stream; +} + +// ---------------------------------------------------------------------------- +// wxFilterClassFactoryBase +// ---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactoryBase, wxObject) + +wxString wxFilterClassFactoryBase::PopExtension(const wxString& location) const +{ + return location.substr(0, FindExtension(location)); +} + +wxString::size_type wxFilterClassFactoryBase::FindExtension( + const wxChar *location) const +{ + size_t len = wxStrlen(location); + + for (const wxChar *const *p = GetProtocols(wxSTREAM_FILEEXT); *p; p++) + { + size_t l = wxStrlen(*p); + + if (l <= len && wxStrcmp(*p, location + len - l) == 0) + return len - l; + } + + return wxString::npos; +} + +bool wxFilterClassFactoryBase::CanHandle(const wxChar *protocol, + wxStreamProtocolType type) const +{ + if (type == wxSTREAM_FILEEXT) + return FindExtension(protocol) != wxString::npos; + else + for (const wxChar *const *p = GetProtocols(type); *p; p++) + if (wxStrcmp(*p, protocol) == 0) + return true; + + return false; +} + +// ---------------------------------------------------------------------------- +// wxFilterClassFactory +// ---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxFilterClassFactory, wxFilterClassFactoryBase) + +wxFilterClassFactory *wxFilterClassFactory::sm_first = NULL; + +void wxFilterClassFactory::Remove() +{ + if (m_next != this) + { + wxFilterClassFactory **pp = &sm_first; + + while (*pp != this) + pp = &(*pp)->m_next; + + *pp = m_next; + + m_next = this; + } +} + +// ---------------------------------------------------------------------------- +// wxBufferedInputStream +// ---------------------------------------------------------------------------- + +wxBufferedInputStream::wxBufferedInputStream(wxInputStream& s, + wxStreamBuffer *buffer) + : wxFilterInputStream(s) +{ + if ( buffer ) + { + // use the buffer provided by the user + m_i_streambuf = buffer; + } + else // create a default buffer + { + m_i_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::read); + + m_i_streambuf->SetBufferIO(1024); + } +} + +wxBufferedInputStream::~wxBufferedInputStream() +{ + m_parent_i_stream->SeekI(-(wxFileOffset)m_i_streambuf->GetBytesLeft(), + wxFromCurrent); + + delete m_i_streambuf; +} + +char wxBufferedInputStream::Peek() +{ + return m_i_streambuf->Peek(); +} + +wxInputStream& wxBufferedInputStream::Read(void *buf, size_t size) +{ + // reset the error flag + Reset(); + + // first read from the already cached data + m_lastcount = GetWBack(buf, size); + + // do we have to read anything more? + if ( m_lastcount < size ) + { + size -= m_lastcount; + buf = (char *)buf + m_lastcount; + + // the call to wxStreamBuffer::Read() below may reset our m_lastcount + // (but it also may not do it if the buffer is associated to another + // existing stream and wasn't created by us), so save it + size_t countOld = m_lastcount; + + // the new count of the bytes read is the count of bytes read this time + m_lastcount = m_i_streambuf->Read(buf, size); + + // plus those we had read before + m_lastcount += countOld; + } + + return *this; +} + +wxFileOffset wxBufferedInputStream::SeekI(wxFileOffset pos, wxSeekMode mode) +{ + // RR: Look at wxInputStream for comments. + + if (m_lasterror==wxSTREAM_EOF) + Reset(); + + if (m_wback) + { + wxLogDebug( wxT("Seeking in stream which has data written back to it.") ); + + free(m_wback); + m_wback = NULL; + m_wbacksize = 0; + m_wbackcur = 0; + } + + return m_i_streambuf->Seek(pos, mode); +} + +wxFileOffset wxBufferedInputStream::TellI() const +{ + wxFileOffset pos = m_i_streambuf->Tell(); + + if (pos != wxInvalidOffset) + pos -= (m_wbacksize - m_wbackcur); + + return pos; +} + +size_t wxBufferedInputStream::OnSysRead(void *buffer, size_t bufsize) +{ + return m_parent_i_stream->Read(buffer, bufsize).LastRead(); +} + +wxFileOffset wxBufferedInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) +{ + return m_parent_i_stream->SeekI(seek, mode); +} + +wxFileOffset wxBufferedInputStream::OnSysTell() const +{ + return m_parent_i_stream->TellI(); +} + +void wxBufferedInputStream::SetInputStreamBuffer(wxStreamBuffer *buffer) +{ + wxCHECK_RET( buffer, _T("wxBufferedInputStream needs buffer") ); + + delete m_i_streambuf; + m_i_streambuf = buffer; +} + +// ---------------------------------------------------------------------------- +// wxBufferedOutputStream +// ---------------------------------------------------------------------------- + +wxBufferedOutputStream::wxBufferedOutputStream(wxOutputStream& s, + wxStreamBuffer *buffer) + : wxFilterOutputStream(s) +{ + if ( buffer ) + { + m_o_streambuf = buffer; + } + else // create a default one + { + m_o_streambuf = new wxStreamBuffer(*this, wxStreamBuffer::write); + + m_o_streambuf->SetBufferIO(1024); + } +} + +wxBufferedOutputStream::~wxBufferedOutputStream() +{ + Sync(); + delete m_o_streambuf; +} + +bool wxBufferedOutputStream::Close() +{ + Sync(); + return IsOk(); +} + + +wxOutputStream& wxBufferedOutputStream::Write(const void *buffer, size_t size) +{ + m_lastcount = 0; + m_o_streambuf->Write(buffer, size); + return *this; +} + +wxFileOffset wxBufferedOutputStream::SeekO(wxFileOffset pos, wxSeekMode mode) +{ + Sync(); + return m_o_streambuf->Seek(pos, mode); +} + +wxFileOffset wxBufferedOutputStream::TellO() const +{ + return m_o_streambuf->Tell(); +} + +void wxBufferedOutputStream::Sync() +{ + m_o_streambuf->FlushBuffer(); + m_parent_o_stream->Sync(); +} + +size_t wxBufferedOutputStream::OnSysWrite(const void *buffer, size_t bufsize) +{ + return m_parent_o_stream->Write(buffer, bufsize).LastWrite(); +} + +wxFileOffset wxBufferedOutputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) +{ + return m_parent_o_stream->SeekO(seek, mode); +} + +wxFileOffset wxBufferedOutputStream::OnSysTell() const +{ + return m_parent_o_stream->TellO(); +} + +wxFileOffset wxBufferedOutputStream::GetLength() const +{ + return m_parent_o_stream->GetLength() + m_o_streambuf->GetIntPosition(); +} + +void wxBufferedOutputStream::SetOutputStreamBuffer(wxStreamBuffer *buffer) +{ + wxCHECK_RET( buffer, _T("wxBufferedOutputStream needs buffer") ); + + delete m_o_streambuf; + m_o_streambuf = buffer; +} + +// ---------------------------------------------------------------------------- +// Some IOManip function +// ---------------------------------------------------------------------------- + +wxOutputStream& wxEndL(wxOutputStream& stream) +{ + static const wxChar *eol = wxTextFile::GetEOL(); + + return stream.Write(eol, wxStrlen(eol)); +} + +#endif // wxUSE_STREAMS diff --git a/Source/3rd Party/wx/src/common/string.cpp b/Source/3rd Party/wx/src/common/string.cpp index 20774ca44..1bb1052ed 100644 --- a/Source/3rd Party/wx/src/common/string.cpp +++ b/Source/3rd Party/wx/src/common/string.cpp @@ -1,2659 +1,2659 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/string.cpp -// Purpose: wxString class -// Author: Vadim Zeitlin, Ryan Norton -// Modified by: -// Created: 29/01/98 -// RCS-ID: $Id: string.cpp 63008 2009-12-28 20:01:39Z VZ $ -// Copyright: (c) 1998 Vadim Zeitlin -// (c) 2004 Ryan Norton -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -/* - * About ref counting: - * 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init()) - * 2) AllocBuffer() sets nRefs to 1, Lock() increments it by one - * 3) Unlock() decrements nRefs and frees memory if it goes to 0 - */ - -// =========================================================================== -// headers, declarations, constants -// =========================================================================== - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/thread.h" -#endif - -#include - -#ifndef __WXWINCE__ - #include -#endif - -#include -#include - -#ifdef __SALFORDC__ - #include -#endif - -// allocating extra space for each string consumes more memory but speeds up -// the concatenation operations (nLen is the current string's length) -// NB: EXTRA_ALLOC must be >= 0! -#define EXTRA_ALLOC (19 - nLen % 16) - -// --------------------------------------------------------------------------- -// static class variables definition -// --------------------------------------------------------------------------- - -#if !wxUSE_STL - //According to STL _must_ be a -1 size_t - const size_t wxStringBase::npos = (size_t) -1; -#endif - -// ---------------------------------------------------------------------------- -// static data -// ---------------------------------------------------------------------------- - -#if wxUSE_STL - -extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T(""); - -#else - -// for an empty string, GetStringData() will return this address: this -// structure has the same layout as wxStringData and it's data() method will -// return the empty string (dummy pointer) -static const struct -{ - wxStringData data; - wxChar dummy; -} g_strEmpty = { {-1, 0, 0}, wxT('\0') }; - -// empty C style string: points to 'string data' byte of g_strEmpty -extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy; - -#endif - -// ---------------------------------------------------------------------------- -// global functions -// ---------------------------------------------------------------------------- - -#if wxUSE_STD_IOSTREAM - -#include - -wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str) -{ -#ifdef __BORLANDC__ - os << str.mb_str(); -#else - os << str.c_str(); -#endif - return os; -} - -#endif // wxUSE_STD_IOSTREAM - -// ---------------------------------------------------------------------------- -// private classes -// ---------------------------------------------------------------------------- - -// this small class is used to gather statistics for performance tuning -//#define WXSTRING_STATISTICS -#ifdef WXSTRING_STATISTICS - class Averager - { - public: - Averager(const wxChar *sz) { m_sz = sz; m_nTotal = m_nCount = 0; } - ~Averager() - { wxPrintf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); } - - void Add(size_t n) { m_nTotal += n; m_nCount++; } - - private: - size_t m_nCount, m_nTotal; - const wxChar *m_sz; - } g_averageLength("allocation size"), - g_averageSummandLength("summand length"), - g_averageConcatHit("hit probability in concat"), - g_averageInitialLength("initial string length"); - - #define STATISTICS_ADD(av, val) g_average##av.Add(val) -#else - #define STATISTICS_ADD(av, val) -#endif // WXSTRING_STATISTICS - -#if !wxUSE_STL - -// =========================================================================== -// wxStringData class deallocation -// =========================================================================== - -#if defined(__VISUALC__) && defined(_MT) && !defined(_DLL) -# pragma message (__FILE__ ": building with Multithreaded non DLL runtime has a performance impact on wxString!") -void wxStringData::Free() -{ - free(this); -} -#endif - -// =========================================================================== -// wxStringBase -// =========================================================================== - -// takes nLength elements of psz starting at nPos -void wxStringBase::InitWith(const wxChar *psz, size_t nPos, size_t nLength) -{ - Init(); - - // if the length is not given, assume the string to be NUL terminated - if ( nLength == npos ) { - wxASSERT_MSG( nPos <= wxStrlen(psz), _T("index out of bounds") ); - - nLength = wxStrlen(psz + nPos); - } - - STATISTICS_ADD(InitialLength, nLength); - - if ( nLength > 0 ) { - // trailing '\0' is written in AllocBuffer() - if ( !AllocBuffer(nLength) ) { - wxFAIL_MSG( _T("out of memory in wxStringBase::InitWith") ); - return; - } - wxTmemcpy(m_pchData, psz + nPos, nLength); - } -} - -// poor man's iterators are "void *" pointers -wxStringBase::wxStringBase(const void *pStart, const void *pEnd) -{ - if ( pEnd >= pStart ) - { - InitWith((const wxChar *)pStart, 0, - (const wxChar *)pEnd - (const wxChar *)pStart); - } - else - { - wxFAIL_MSG( _T("pStart is not before pEnd") ); - Init(); - } -} - -wxStringBase::wxStringBase(size_type n, wxChar ch) -{ - Init(); - append(n, ch); -} - -// --------------------------------------------------------------------------- -// memory allocation -// --------------------------------------------------------------------------- - -// allocates memory needed to store a C string of length nLen -bool wxStringBase::AllocBuffer(size_t nLen) -{ - // allocating 0 sized buffer doesn't make sense, all empty strings should - // reuse g_strEmpty - wxASSERT( nLen > 0 ); - - // make sure that we don't overflow - wxCHECK( nLen < (INT_MAX / sizeof(wxChar)) - - (sizeof(wxStringData) + EXTRA_ALLOC + 1), false ); - - STATISTICS_ADD(Length, nLen); - - // allocate memory: - // 1) one extra character for '\0' termination - // 2) sizeof(wxStringData) for housekeeping info - wxStringData* pData = (wxStringData*) - malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar)); - - if ( pData == NULL ) { - // allocation failures are handled by the caller - return false; - } - - pData->nRefs = 1; - pData->nDataLength = nLen; - pData->nAllocLength = nLen + EXTRA_ALLOC; - m_pchData = pData->data(); // data starts after wxStringData - m_pchData[nLen] = wxT('\0'); - return true; -} - -// must be called before changing this string -bool wxStringBase::CopyBeforeWrite() -{ - wxStringData* pData = GetStringData(); - - if ( pData->IsShared() ) { - pData->Unlock(); // memory not freed because shared - size_t nLen = pData->nDataLength; - if ( !AllocBuffer(nLen) ) { - // allocation failures are handled by the caller - return false; - } - wxTmemcpy(m_pchData, pData->data(), nLen); - } - - wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner - - return true; -} - -// must be called before replacing contents of this string -bool wxStringBase::AllocBeforeWrite(size_t nLen) -{ - wxASSERT( nLen != 0 ); // doesn't make any sense - - // must not share string and must have enough space - wxStringData* pData = GetStringData(); - if ( pData->IsShared() || pData->IsEmpty() ) { - // can't work with old buffer, get new one - pData->Unlock(); - if ( !AllocBuffer(nLen) ) { - // allocation failures are handled by the caller - return false; - } - } - else { - if ( nLen > pData->nAllocLength ) { - // realloc the buffer instead of calling malloc() again, this is more - // efficient - STATISTICS_ADD(Length, nLen); - - nLen += EXTRA_ALLOC; - - pData = (wxStringData*) - realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); - - if ( pData == NULL ) { - // allocation failures are handled by the caller - // keep previous data since reallocation failed - return false; - } - - pData->nAllocLength = nLen; - m_pchData = pData->data(); - } - } - - wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner - - // it doesn't really matter what the string length is as it's going to be - // overwritten later but, for extra safety, set it to 0 for now as we may - // have some junk in m_pchData - GetStringData()->nDataLength = 0; - - return true; -} - -wxStringBase& wxStringBase::append(size_t n, wxChar ch) -{ - size_type len = length(); - - if ( !Alloc(len + n) || !CopyBeforeWrite() ) { - wxFAIL_MSG( _T("out of memory in wxStringBase::append") ); - } - GetStringData()->nDataLength = len + n; - m_pchData[len + n] = '\0'; - for ( size_t i = 0; i < n; ++i ) - m_pchData[len + i] = ch; - return *this; -} - -void wxStringBase::resize(size_t nSize, wxChar ch) -{ - size_t len = length(); - - if ( nSize < len ) - { - erase(begin() + nSize, end()); - } - else if ( nSize > len ) - { - append(nSize - len, ch); - } - //else: we have exactly the specified length, nothing to do -} - -// allocate enough memory for nLen characters -bool wxStringBase::Alloc(size_t nLen) -{ - wxStringData *pData = GetStringData(); - if ( pData->nAllocLength <= nLen ) { - if ( pData->IsEmpty() ) { - nLen += EXTRA_ALLOC; - - pData = (wxStringData *) - malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); - - if ( pData == NULL ) { - // allocation failure handled by caller - return false; - } - - pData->nRefs = 1; - pData->nDataLength = 0; - pData->nAllocLength = nLen; - m_pchData = pData->data(); // data starts after wxStringData - m_pchData[0u] = wxT('\0'); - } - else if ( pData->IsShared() ) { - pData->Unlock(); // memory not freed because shared - size_t nOldLen = pData->nDataLength; - if ( !AllocBuffer(nLen) ) { - // allocation failure handled by caller - return false; - } - // +1 to copy the terminator, too - memcpy(m_pchData, pData->data(), (nOldLen+1)*sizeof(wxChar)); - GetStringData()->nDataLength = nOldLen; - } - else { - nLen += EXTRA_ALLOC; - - pData = (wxStringData *) - realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); - - if ( pData == NULL ) { - // allocation failure handled by caller - // keep previous data since reallocation failed - return false; - } - - // it's not important if the pointer changed or not (the check for this - // is not faster than assigning to m_pchData in all cases) - pData->nAllocLength = nLen; - m_pchData = pData->data(); - } - } - //else: we've already got enough - return true; -} - -wxStringBase::iterator wxStringBase::begin() -{ - if (length() > 0) - CopyBeforeWrite(); - return m_pchData; -} - -wxStringBase::iterator wxStringBase::end() -{ - if (length() > 0) - CopyBeforeWrite(); - return m_pchData + length(); -} - -wxStringBase::iterator wxStringBase::erase(iterator it) -{ - size_type idx = it - begin(); - erase(idx, 1); - return begin() + idx; -} - -wxStringBase& wxStringBase::erase(size_t nStart, size_t nLen) -{ - wxASSERT(nStart <= length()); - size_t strLen = length() - nStart; - // delete nLen or up to the end of the string characters - nLen = strLen < nLen ? strLen : nLen; - wxString strTmp(c_str(), nStart); - strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen); - - swap(strTmp); - return *this; -} - -wxStringBase& wxStringBase::insert(size_t nPos, const wxChar *sz, size_t n) -{ - wxASSERT( nPos <= length() ); - - if ( n == npos ) n = wxStrlen(sz); - if ( n == 0 ) return *this; - - if ( !Alloc(length() + n) || !CopyBeforeWrite() ) { - wxFAIL_MSG( _T("out of memory in wxStringBase::insert") ); - } - - memmove(m_pchData + nPos + n, m_pchData + nPos, - (length() - nPos) * sizeof(wxChar)); - memcpy(m_pchData + nPos, sz, n * sizeof(wxChar)); - GetStringData()->nDataLength = length() + n; - m_pchData[length()] = '\0'; - - return *this; -} - -void wxStringBase::swap(wxStringBase& str) -{ - wxChar* tmp = str.m_pchData; - str.m_pchData = m_pchData; - m_pchData = tmp; -} - -size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const -{ - // deal with the special case of empty string first - const size_t nLen = length(); - const size_t nLenOther = str.length(); - - if ( !nLenOther ) - { - // empty string is a substring of anything - return 0; - } - - if ( !nLen ) - { - // the other string is non empty so can't be our substring - return npos; - } - - wxASSERT( str.GetStringData()->IsValid() ); - wxASSERT( nStart <= nLen ); - - const wxChar * const other = str.c_str(); - - // anchor - const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart, - *other, - nLen - nStart); - - if ( !p ) - return npos; - - while ( p - c_str() + nLenOther <= nLen && wxTmemcmp(p, other, nLenOther) ) - { - p++; - - // anchor again - p = (const wxChar*)wxTmemchr(p, *other, nLen - (p - c_str())); - - if ( !p ) - return npos; - } - - return p - c_str() + nLenOther <= nLen ? p - c_str() : npos; -} - -size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const -{ - return find(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::find(wxChar ch, size_t nStart) const -{ - wxASSERT( nStart <= length() ); - - const wxChar *p = (const wxChar*)wxTmemchr(c_str() + nStart, ch, length() - nStart); - - return p == NULL ? npos : p - c_str(); -} - -size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const -{ - wxASSERT( str.GetStringData()->IsValid() ); - wxASSERT( nStart == npos || nStart <= length() ); - - if ( length() >= str.length() ) - { - // avoids a corner case later - if ( length() == 0 && str.length() == 0 ) - return 0; - - // "top" is the point where search starts from - size_t top = length() - str.length(); - - if ( nStart == npos ) - nStart = length() - 1; - if ( nStart < top ) - top = nStart; - - const wxChar *cursor = c_str() + top; - do - { - if ( wxTmemcmp(cursor, str.c_str(), - str.length()) == 0 ) - { - return cursor - c_str(); - } - } while ( cursor-- > c_str() ); - } - - return npos; -} - -size_t wxStringBase::rfind(const wxChar* sz, size_t nStart, size_t n) const -{ - return rfind(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::rfind(wxChar ch, size_t nStart) const -{ - if ( nStart == npos ) - { - nStart = length(); - } - else - { - wxASSERT( nStart <= length() ); - } - - const wxChar *actual; - for ( actual = c_str() + ( nStart == npos ? length() : nStart + 1 ); - actual > c_str(); --actual ) - { - if ( *(actual - 1) == ch ) - return (actual - 1) - c_str(); - } - - return npos; -} - -size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart) const -{ - wxASSERT(nStart <= length()); - - size_t len = wxStrlen(sz); - - size_t i; - for(i = nStart; i < this->length(); ++i) - { - if (wxTmemchr(sz, *(c_str() + i), len)) - break; - } - - if(i == this->length()) - return npos; - else - return i; -} - -size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart, - size_t n) const -{ - return find_first_of(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart) const -{ - if ( nStart == npos ) - { - nStart = length() - 1; - } - else - { - wxASSERT_MSG( nStart <= length(), - _T("invalid index in find_last_of()") ); - } - - size_t len = wxStrlen(sz); - - for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) - { - if ( wxTmemchr(sz, *p, len) ) - return p - c_str(); - } - - return npos; -} - -size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart, - size_t n) const -{ - return find_last_of(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart) const -{ - if ( nStart == npos ) - { - nStart = length(); - } - else - { - wxASSERT( nStart <= length() ); - } - - size_t len = wxStrlen(sz); - - size_t i; - for(i = nStart; i < this->length(); ++i) - { - if (!wxTmemchr(sz, *(c_str() + i), len)) - break; - } - - if(i == this->length()) - return npos; - else - return i; -} - -size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart, - size_t n) const -{ - return find_first_not_of(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::find_first_not_of(wxChar ch, size_t nStart) const -{ - wxASSERT( nStart <= length() ); - - for ( const wxChar *p = c_str() + nStart; *p; p++ ) - { - if ( *p != ch ) - return p - c_str(); - } - - return npos; -} - -size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart) const -{ - if ( nStart == npos ) - { - nStart = length() - 1; - } - else - { - wxASSERT( nStart <= length() ); - } - - size_t len = wxStrlen(sz); - - for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) - { - if ( !wxTmemchr(sz, *p,len) ) - return p - c_str(); - } - - return npos; -} - -size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart, - size_t n) const -{ - return find_last_not_of(wxStringBase(sz, n), nStart); -} - -size_t wxStringBase::find_last_not_of(wxChar ch, size_t nStart) const -{ - if ( nStart == npos ) - { - nStart = length() - 1; - } - else - { - wxASSERT( nStart <= length() ); - } - - for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) - { - if ( *p != ch ) - return p - c_str(); - } - - return npos; -} - -wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, - const wxChar *sz) -{ - wxASSERT_MSG( nStart <= length(), - _T("index out of bounds in wxStringBase::replace") ); - size_t strLen = length() - nStart; - nLen = strLen < nLen ? strLen : nLen; - - wxStringBase strTmp; - strTmp.reserve(length()); // micro optimisation to avoid multiple mem allocs - - //This is kind of inefficient, but its pretty good considering... - //we don't want to use character access operators here because on STL - //it will freeze the reference count of strTmp, which means a deep copy - //at the end when swap is called - // - //Also, we can't use append with the full character pointer and must - //do it manually because this string can contain null characters - for(size_t i1 = 0; i1 < nStart; ++i1) - strTmp.append(1, this->c_str()[i1]); - - //its safe to do the full version here because - //sz must be a normal c string - strTmp.append(sz); - - for(size_t i2 = nStart + nLen; i2 < length(); ++i2) - strTmp.append(1, this->c_str()[i2]); - - swap(strTmp); - return *this; -} - -wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, - size_t nCount, wxChar ch) -{ - return replace(nStart, nLen, wxStringBase(nCount, ch).c_str()); -} - -wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, - const wxStringBase& str, - size_t nStart2, size_t nLen2) -{ - return replace(nStart, nLen, str.substr(nStart2, nLen2)); -} - -wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, - const wxChar* sz, size_t nCount) -{ - return replace(nStart, nLen, wxStringBase(sz, nCount).c_str()); -} - -wxStringBase wxStringBase::substr(size_t nStart, size_t nLen) const -{ - if ( nLen == npos ) - nLen = length() - nStart; - return wxStringBase(*this, nStart, nLen); -} - -// assigns one string to another -wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc) -{ - wxASSERT( stringSrc.GetStringData()->IsValid() ); - - // don't copy string over itself - if ( m_pchData != stringSrc.m_pchData ) { - if ( stringSrc.GetStringData()->IsEmpty() ) { - Reinit(); - } - else { - // adjust references - GetStringData()->Unlock(); - m_pchData = stringSrc.m_pchData; - GetStringData()->Lock(); - } - } - - return *this; -} - -// assigns a single character -wxStringBase& wxStringBase::operator=(wxChar ch) -{ - if ( !AssignCopy(1, &ch) ) { - wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") ); - } - return *this; -} - -// assigns C string -wxStringBase& wxStringBase::operator=(const wxChar *psz) -{ - if ( !AssignCopy(wxStrlen(psz), psz) ) { - wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(const wxChar *)") ); - } - return *this; -} - -// helper function: does real copy -bool wxStringBase::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData) -{ - if ( nSrcLen == 0 ) { - Reinit(); - } - else { - if ( !AllocBeforeWrite(nSrcLen) ) { - // allocation failure handled by caller - return false; - } - - // use memmove() and not memcpy() here as we might be copying from our own - // buffer in case of assignment such as "s = s.c_str()" (see #11294) - memmove(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar)); - - GetStringData()->nDataLength = nSrcLen; - m_pchData[nSrcLen] = wxT('\0'); - } - return true; -} - -// --------------------------------------------------------------------------- -// string concatenation -// --------------------------------------------------------------------------- - -// add something to this string -bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData, - size_t nMaxLen) -{ - STATISTICS_ADD(SummandLength, nSrcLen); - - nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen; - - // concatenating an empty string is a NOP - if ( nSrcLen > 0 ) { - wxStringData *pData = GetStringData(); - size_t nLen = pData->nDataLength; - size_t nNewLen = nLen + nSrcLen; - - // take special care when appending part of this string to itself: the code - // below reallocates our buffer and this invalidates pszSrcData pointer so - // we have to copy it in another temporary string in this case (but avoid - // doing this unnecessarily) - if ( pszSrcData >= m_pchData && pszSrcData < m_pchData + nLen ) - { - wxStringBase tmp(pszSrcData, nSrcLen); - return ConcatSelf(nSrcLen, tmp.m_pchData, nSrcLen); - } - - // alloc new buffer if current is too small - if ( pData->IsShared() ) { - STATISTICS_ADD(ConcatHit, 0); - - // we have to allocate another buffer - wxStringData* pOldData = GetStringData(); - if ( !AllocBuffer(nNewLen) ) { - // allocation failure handled by caller - return false; - } - memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar)); - pOldData->Unlock(); - } - else if ( nNewLen > pData->nAllocLength ) { - STATISTICS_ADD(ConcatHit, 0); - - reserve(nNewLen); - // we have to grow the buffer - if ( capacity() < nNewLen ) { - // allocation failure handled by caller - return false; - } - } - else { - STATISTICS_ADD(ConcatHit, 1); - - // the buffer is already big enough - } - - // should be enough space - wxASSERT( nNewLen <= GetStringData()->nAllocLength ); - - // fast concatenation - all is done in our buffer - memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar)); - - m_pchData[nNewLen] = wxT('\0'); // put terminating '\0' - GetStringData()->nDataLength = nNewLen; // and fix the length - } - //else: the string to append was empty - return true; -} - -// --------------------------------------------------------------------------- -// simple sub-string extraction -// --------------------------------------------------------------------------- - -// helper function: clone the data attached to this string -bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const -{ - if ( nCopyLen == 0 ) { - dest.Init(); - } - else { - if ( !dest.AllocBuffer(nCopyLen) ) { - // allocation failure handled by caller - return false; - } - memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar)); - } - return true; -} - -#endif // !wxUSE_STL - -#if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE) - -#if !wxUSE_STL - #define STRINGCLASS wxStringBase -#else - #define STRINGCLASS wxString -#endif - -static inline int wxDoCmp(const wxChar* s1, size_t l1, - const wxChar* s2, size_t l2) -{ - if( l1 == l2 ) - return wxTmemcmp(s1, s2, l1); - else if( l1 < l2 ) - { - int ret = wxTmemcmp(s1, s2, l1); - return ret == 0 ? -1 : ret; - } - else - { - int ret = wxTmemcmp(s1, s2, l2); - return ret == 0 ? +1 : ret; - } -} - -int STRINGCLASS::compare(const wxStringBase& str) const -{ - return ::wxDoCmp(data(), length(), str.data(), str.length()); -} - -int STRINGCLASS::compare(size_t nStart, size_t nLen, - const wxStringBase& str) const -{ - wxASSERT(nStart <= length()); - size_type strLen = length() - nStart; - nLen = strLen < nLen ? strLen : nLen; - return ::wxDoCmp(data() + nStart, nLen, str.data(), str.length()); -} - -int STRINGCLASS::compare(size_t nStart, size_t nLen, - const wxStringBase& str, - size_t nStart2, size_t nLen2) const -{ - wxASSERT(nStart <= length()); - wxASSERT(nStart2 <= str.length()); - size_type strLen = length() - nStart, - strLen2 = str.length() - nStart2; - nLen = strLen < nLen ? strLen : nLen; - nLen2 = strLen2 < nLen2 ? strLen2 : nLen2; - return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2); -} - -int STRINGCLASS::compare(const wxChar* sz) const -{ - size_t nLen = wxStrlen(sz); - return ::wxDoCmp(data(), length(), sz, nLen); -} - -int STRINGCLASS::compare(size_t nStart, size_t nLen, - const wxChar* sz, size_t nCount) const -{ - wxASSERT(nStart <= length()); - size_type strLen = length() - nStart; - nLen = strLen < nLen ? strLen : nLen; - if( nCount == npos ) - nCount = wxStrlen(sz); - - return ::wxDoCmp(data() + nStart, nLen, sz, nCount); -} - -#undef STRINGCLASS - -#endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE) - -// =========================================================================== -// wxString class core -// =========================================================================== - -// --------------------------------------------------------------------------- -// construction and conversion -// --------------------------------------------------------------------------- - -#if wxUSE_UNICODE - -// from multibyte string -wxString::wxString(const char *psz, const wxMBConv& conv, size_t nLength) -{ - // anything to do? - if ( psz && nLength != 0 ) - { - if ( nLength == npos ) - { - nLength = wxNO_LEN; - } - - size_t nLenWide; - wxWCharBuffer wbuf = conv.cMB2WC(psz, nLength, &nLenWide); - - if ( nLenWide ) - assign(wbuf, nLenWide); - } -} - -//Convert wxString in Unicode mode to a multi-byte string -const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const -{ - return conv.cWC2MB(c_str(), length() + 1 /* size, not length */, NULL); -} - -#else // ANSI - -#if wxUSE_WCHAR_T - -// from wide string -wxString::wxString(const wchar_t *pwz, const wxMBConv& conv, size_t nLength) -{ - // anything to do? - if ( pwz && nLength != 0 ) - { - if ( nLength == npos ) - { - nLength = wxNO_LEN; - } - - size_t nLenMB; - wxCharBuffer buf = conv.cWC2MB(pwz, nLength, &nLenMB); - - if ( nLenMB ) - assign(buf, nLenMB); - } -} - -//Converts this string to a wide character string if unicode -//mode is not enabled and wxUSE_WCHAR_T is enabled -const wxWCharBuffer wxString::wc_str(const wxMBConv& conv) const -{ - return conv.cMB2WC(c_str(), length() + 1 /* size, not length */, NULL); -} - -#endif // wxUSE_WCHAR_T - -#endif // Unicode/ANSI - -// shrink to minimal size (releasing extra memory) -bool wxString::Shrink() -{ - wxString tmp(begin(), end()); - swap(tmp); - return tmp.length() == length(); -} - -#if !wxUSE_STL -// get the pointer to writable buffer of (at least) nLen bytes -wxChar *wxString::GetWriteBuf(size_t nLen) -{ - if ( !AllocBeforeWrite(nLen) ) { - // allocation failure handled by caller - return NULL; - } - - wxASSERT( GetStringData()->nRefs == 1 ); - GetStringData()->Validate(false); - - return m_pchData; -} - -// put string back in a reasonable state after GetWriteBuf -void wxString::UngetWriteBuf() -{ - UngetWriteBuf(wxStrlen(m_pchData)); -} - -void wxString::UngetWriteBuf(size_t nLen) -{ - wxStringData * const pData = GetStringData(); - - wxASSERT_MSG( nLen < pData->nAllocLength, _T("buffer overrun") ); - - // the strings we store are always NUL-terminated - pData->data()[nLen] = _T('\0'); - pData->nDataLength = nLen; - pData->Validate(true); -} -#endif // !wxUSE_STL - -// --------------------------------------------------------------------------- -// data access -// --------------------------------------------------------------------------- - -// all functions are inline in string.h - -// --------------------------------------------------------------------------- -// assignment operators -// --------------------------------------------------------------------------- - -#if !wxUSE_UNICODE - -// same as 'signed char' variant -wxString& wxString::operator=(const unsigned char* psz) -{ - *this = (const char *)psz; - return *this; -} - -#if wxUSE_WCHAR_T -wxString& wxString::operator=(const wchar_t *pwz) -{ - wxString str(pwz); - swap(str); - return *this; -} -#endif - -#endif - -/* - * concatenation functions come in 5 flavours: - * string + string - * char + string and string + char - * C str + string and string + C str - */ - -wxString operator+(const wxString& str1, const wxString& str2) -{ -#if !wxUSE_STL - wxASSERT( str1.GetStringData()->IsValid() ); - wxASSERT( str2.GetStringData()->IsValid() ); -#endif - - wxString s = str1; - s += str2; - - return s; -} - -wxString operator+(const wxString& str, wxChar ch) -{ -#if !wxUSE_STL - wxASSERT( str.GetStringData()->IsValid() ); -#endif - - wxString s = str; - s += ch; - - return s; -} - -wxString operator+(wxChar ch, const wxString& str) -{ -#if !wxUSE_STL - wxASSERT( str.GetStringData()->IsValid() ); -#endif - - wxString s = ch; - s += str; - - return s; -} - -wxString operator+(const wxString& str, const wxChar *psz) -{ -#if !wxUSE_STL - wxASSERT( str.GetStringData()->IsValid() ); -#endif - - wxString s; - if ( !s.Alloc(wxStrlen(psz) + str.length()) ) { - wxFAIL_MSG( _T("out of memory in wxString::operator+") ); - } - s += str; - s += psz; - - return s; -} - -wxString operator+(const wxChar *psz, const wxString& str) -{ -#if !wxUSE_STL - wxASSERT( str.GetStringData()->IsValid() ); -#endif - - wxString s; - if ( !s.Alloc(wxStrlen(psz) + str.length()) ) { - wxFAIL_MSG( _T("out of memory in wxString::operator+") ); - } - s = psz; - s += str; - - return s; -} - -// =========================================================================== -// other common string functions -// =========================================================================== - -int wxString::Cmp(const wxString& s) const -{ - return compare(s); -} - -int wxString::Cmp(const wxChar* psz) const -{ - return compare(psz); -} - -static inline int wxDoCmpNoCase(const wxChar* s1, size_t l1, - const wxChar* s2, size_t l2) -{ - size_t i; - - if( l1 == l2 ) - { - for(i = 0; i < l1; ++i) - { - if(wxTolower(s1[i]) != wxTolower(s2[i])) - break; - } - return i == l1 ? 0 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; - } - else if( l1 < l2 ) - { - for(i = 0; i < l1; ++i) - { - if(wxTolower(s1[i]) != wxTolower(s2[i])) - break; - } - return i == l1 ? -1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; - } - else - { - for(i = 0; i < l2; ++i) - { - if(wxTolower(s1[i]) != wxTolower(s2[i])) - break; - } - return i == l2 ? 1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; - } -} - -int wxString::CmpNoCase(const wxString& s) const -{ - return wxDoCmpNoCase(data(), length(), s.data(), s.length()); -} - -int wxString::CmpNoCase(const wxChar* psz) const -{ - int nLen = wxStrlen(psz); - - return wxDoCmpNoCase(data(), length(), psz, nLen); -} - - -#if wxUSE_UNICODE - -#ifdef __MWERKS__ -#ifndef __SCHAR_MAX__ -#define __SCHAR_MAX__ 127 -#endif -#endif - -wxString wxString::FromAscii(const char *ascii) -{ - if (!ascii) - return wxEmptyString; - - size_t len = strlen( ascii ); - wxString res; - - if ( len ) - { - wxStringBuffer buf(res, len); - - wchar_t *dest = buf; - - for ( ;; ) - { - if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' ) - break; - } - } - - return res; -} - -wxString wxString::FromAscii(const char ascii) -{ - // What do we do with '\0' ? - - wxString res; - res += (wchar_t)(unsigned char) ascii; - - return res; -} - -const wxCharBuffer wxString::ToAscii() const -{ - // this will allocate enough space for the terminating NUL too - wxCharBuffer buffer(length()); - - - char *dest = buffer.data(); - - const wchar_t *pwc = c_str(); - for ( ;; ) - { - *dest++ = (char)(*pwc > SCHAR_MAX ? wxT('_') : *pwc); - - // the output string can't have embedded NULs anyhow, so we can safely - // stop at first of them even if we do have any - if ( !*pwc++ ) - break; - } - - return buffer; -} - -#endif // Unicode - -// extract string of length nCount starting at nFirst -wxString wxString::Mid(size_t nFirst, size_t nCount) const -{ - size_t nLen = length(); - - // default value of nCount is npos and means "till the end" - if ( nCount == npos ) - { - nCount = nLen - nFirst; - } - - // out-of-bounds requests return sensible things - if ( nFirst + nCount > nLen ) - { - nCount = nLen - nFirst; - } - - if ( nFirst > nLen ) - { - // AllocCopy() will return empty string - return wxEmptyString; - } - - wxString dest(*this, nFirst, nCount); - if ( dest.length() != nCount ) - { - wxFAIL_MSG( _T("out of memory in wxString::Mid") ); - } - - return dest; -} - -// check that the string starts with prefix and return the rest of the string -// in the provided pointer if it is not NULL, otherwise return false -bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const -{ - wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") ); - - // first check if the beginning of the string matches the prefix: note - // that we don't have to check that we don't run out of this string as - // when we reach the terminating NUL, either prefix string ends too (and - // then it's ok) or we break out of the loop because there is no match - const wxChar *p = c_str(); - while ( *prefix ) - { - if ( *prefix++ != *p++ ) - { - // no match - return false; - } - } - - if ( rest ) - { - // put the rest of the string into provided pointer - *rest = p; - } - - return true; -} - - -// check that the string ends with suffix and return the rest of it in the -// provided pointer if it is not NULL, otherwise return false -bool wxString::EndsWith(const wxChar *suffix, wxString *rest) const -{ - wxASSERT_MSG( suffix, _T("invalid parameter in wxString::EndssWith") ); - - int start = length() - wxStrlen(suffix); - if ( start < 0 || wxStrcmp(c_str() + start, suffix) != 0 ) - return false; - - if ( rest ) - { - // put the rest of the string into provided pointer - rest->assign(*this, 0, start); - } - - return true; -} - - -// extract nCount last (rightmost) characters -wxString wxString::Right(size_t nCount) const -{ - if ( nCount > length() ) - nCount = length(); - - wxString dest(*this, length() - nCount, nCount); - if ( dest.length() != nCount ) { - wxFAIL_MSG( _T("out of memory in wxString::Right") ); - } - return dest; -} - -// get all characters after the last occurence of ch -// (returns the whole string if ch not found) -wxString wxString::AfterLast(wxChar ch) const -{ - wxString str; - int iPos = Find(ch, true); - if ( iPos == wxNOT_FOUND ) - str = *this; - else - str = c_str() + iPos + 1; - - return str; -} - -// extract nCount first (leftmost) characters -wxString wxString::Left(size_t nCount) const -{ - if ( nCount > length() ) - nCount = length(); - - wxString dest(*this, 0, nCount); - if ( dest.length() != nCount ) { - wxFAIL_MSG( _T("out of memory in wxString::Left") ); - } - return dest; -} - -// get all characters before the first occurence of ch -// (returns the whole string if ch not found) -wxString wxString::BeforeFirst(wxChar ch) const -{ - int iPos = Find(ch); - if ( iPos == wxNOT_FOUND ) iPos = length(); - return wxString(*this, 0, iPos); -} - -/// get all characters before the last occurence of ch -/// (returns empty string if ch not found) -wxString wxString::BeforeLast(wxChar ch) const -{ - wxString str; - int iPos = Find(ch, true); - if ( iPos != wxNOT_FOUND && iPos != 0 ) - str = wxString(c_str(), iPos); - - return str; -} - -/// get all characters after the first occurence of ch -/// (returns empty string if ch not found) -wxString wxString::AfterFirst(wxChar ch) const -{ - wxString str; - int iPos = Find(ch); - if ( iPos != wxNOT_FOUND ) - str = c_str() + iPos + 1; - - return str; -} - -// replace first (or all) occurences of some substring with another one -size_t -wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplaceAll) -{ - // if we tried to replace an empty string we'd enter an infinite loop below - wxCHECK_MSG( szOld && *szOld && szNew, 0, - _T("wxString::Replace(): invalid parameter") ); - - size_t uiCount = 0; // count of replacements made - - // optimize the special common case of replacing one character with another - // one - if ( szOld[1] == '\0' && (szNew[0] != '\0' && szNew[1] == '\0') ) - { - // this loop is the simplified version of the one below - for ( size_t pos = 0; ; ) - { - pos = find(*szOld, pos); - if ( pos == npos ) - break; - - (*this)[pos++] = *szNew; - - uiCount++; - - if ( !bReplaceAll ) - break; - } - } - else // general case - { - const size_t uiOldLen = wxStrlen(szOld); - const size_t uiNewLen = wxStrlen(szNew); - - for ( size_t pos = 0; ; ) - { - pos = find(szOld, pos); - if ( pos == npos ) - break; - - // replace this occurrence of the old string with the new one - replace(pos, uiOldLen, szNew, uiNewLen); - - // move past the string that was replaced - pos += uiNewLen; - - // increase replace count - uiCount++; - - // stop now? - if ( !bReplaceAll ) - break; - } - } - - return uiCount; -} - -bool wxString::IsAscii() const -{ - const wxChar *s = (const wxChar*) *this; - while(*s){ - if(!isascii(*s)) return(false); - s++; - } - return(true); -} - -bool wxString::IsWord() const -{ - const wxChar *s = (const wxChar*) *this; - while(*s){ - if(!wxIsalpha(*s)) return(false); - s++; - } - return(true); -} - -bool wxString::IsNumber() const -{ - const wxChar *s = (const wxChar*) *this; - if (wxStrlen(s)) - if ((s[0] == wxT('-')) || (s[0] == wxT('+'))) s++; - while(*s){ - if(!wxIsdigit(*s)) return(false); - s++; - } - return(true); -} - -wxString wxString::Strip(stripType w) const -{ - wxString s = *this; - if ( w & leading ) s.Trim(false); - if ( w & trailing ) s.Trim(true); - return s; -} - -// --------------------------------------------------------------------------- -// case conversion -// --------------------------------------------------------------------------- - -wxString& wxString::MakeUpper() -{ - for ( iterator it = begin(), en = end(); it != en; ++it ) - *it = (wxChar)wxToupper(*it); - - return *this; -} - -wxString& wxString::MakeLower() -{ - for ( iterator it = begin(), en = end(); it != en; ++it ) - *it = (wxChar)wxTolower(*it); - - return *this; -} - -// --------------------------------------------------------------------------- -// trimming and padding -// --------------------------------------------------------------------------- - -// some compilers (VC++ 6.0 not to name them) return true for a call to -// isspace('\xEA') in the C locale which seems to be broken to me, but we have -// to live with this by checking that the character is a 7 bit one - even if -// this may fail to detect some spaces (I don't know if Unicode doesn't have -// space-like symbols somewhere except in the first 128 chars), it is arguably -// still better than trimming away accented letters -inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); } - -// trims spaces (in the sense of isspace) from left or right side -wxString& wxString::Trim(bool bFromRight) -{ - // first check if we're going to modify the string at all - if ( !empty() && - ( - (bFromRight && wxSafeIsspace(GetChar(length() - 1))) || - (!bFromRight && wxSafeIsspace(GetChar(0u))) - ) - ) - { - if ( bFromRight ) - { - // find last non-space character - reverse_iterator psz = rbegin(); - while ( (psz != rend()) && wxSafeIsspace(*psz) ) - psz++; - - // truncate at trailing space start - erase(psz.base(), end()); - } - else - { - // find first non-space character - iterator psz = begin(); - while ( (psz != end()) && wxSafeIsspace(*psz) ) - psz++; - - // fix up data and length - erase(begin(), psz); - } - } - - return *this; -} - -// adds nCount characters chPad to the string from either side -wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight) -{ - wxString s(chPad, nCount); - - if ( bFromRight ) - *this += s; - else - { - s += *this; - swap(s); - } - - return *this; -} - -// truncate the string -wxString& wxString::Truncate(size_t uiLen) -{ - if ( uiLen < length() ) - { - erase(begin() + uiLen, end()); - } - //else: nothing to do, string is already short enough - - return *this; -} - -// --------------------------------------------------------------------------- -// finding (return wxNOT_FOUND if not found and index otherwise) -// --------------------------------------------------------------------------- - -// find a character -int wxString::Find(wxChar ch, bool bFromEnd) const -{ - size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch); - - return (idx == npos) ? wxNOT_FOUND : (int)idx; -} - -// find a sub-string (like strstr) -int wxString::Find(const wxChar *pszSub) const -{ - size_type idx = find(pszSub); - - return (idx == npos) ? wxNOT_FOUND : (int)idx; -} - -// ---------------------------------------------------------------------------- -// conversion to numbers -// ---------------------------------------------------------------------------- - -// the implementation of all the functions below is exactly the same so factor -// it out - -template -bool wxStringToIntType(const wxChar *start, - T *val, - int base, - F func) -{ - wxCHECK_MSG( val, false, _T("NULL output pointer") ); - wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); - -#ifndef __WXWINCE__ - errno = 0; -#endif - - wxChar *end; - *val = (*func)(start, &end, base); - - // return true only if scan was stopped by the terminating NUL and if the - // string was not empty to start with and no under/overflow occurred - return !*end && (end != start) -#ifndef __WXWINCE__ - && (errno != ERANGE) -#endif - ; -} - -bool wxString::ToLong(long *val, int base) const -{ - return wxStringToIntType(c_str(), val, base, wxStrtol); -} - -bool wxString::ToULong(unsigned long *val, int base) const -{ - return wxStringToIntType(c_str(), val, base, wxStrtoul); -} - -bool wxString::ToLongLong(wxLongLong_t *val, int base) const -{ -#ifdef wxHAS_STRTOLL - return wxStringToIntType(c_str(), val, base, wxStrtoll); -#else - // TODO: implement this ourselves - wxUnusedVar(val); - wxUnusedVar(base); - return false; -#endif // wxHAS_STRTOLL -} - -bool wxString::ToULongLong(wxULongLong_t *val, int base) const -{ -#ifdef wxHAS_STRTOLL - return wxStringToIntType(c_str(), val, base, wxStrtoull); -#else - // TODO: implement this ourselves - wxUnusedVar(val); - wxUnusedVar(base); - return false; -#endif -} - -bool wxString::ToDouble(double *val) const -{ - wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToDouble") ); - -#ifndef __WXWINCE__ - errno = 0; -#endif - - const wxChar *start = c_str(); - wxChar *end; - *val = wxStrtod(start, &end); - - // return true only if scan was stopped by the terminating NUL and if the - // string was not empty to start with and no under/overflow occurred - return !*end && (end != start) -#ifndef __WXWINCE__ - && (errno != ERANGE) -#endif - ; -} - -// --------------------------------------------------------------------------- -// formatted output -// --------------------------------------------------------------------------- - -/* static */ -wxString wxString::Format(const wxChar *pszFormat, ...) -{ - va_list argptr; - va_start(argptr, pszFormat); - - wxString s; - s.PrintfV(pszFormat, argptr); - - va_end(argptr); - - return s; -} - -/* static */ -wxString wxString::FormatV(const wxChar *pszFormat, va_list argptr) -{ - wxString s; - s.PrintfV(pszFormat, argptr); - return s; -} - -int wxString::Printf(const wxChar *pszFormat, ...) -{ - va_list argptr; - va_start(argptr, pszFormat); - - int iLen = PrintfV(pszFormat, argptr); - - va_end(argptr); - - return iLen; -} - -/* - Uses wxVsnprintf and places the result into the this string. - - In ANSI build, wxVsnprintf is effectively vsnprintf but in Unicode build - it is vswprintf. Due to a discrepancy between vsnprintf and vswprintf in - the ISO C99 (and thus SUSv3) standard the return value for the case of - an undersized buffer is inconsistent. For conforming vsnprintf - implementations the function must return the number of characters that - would have been printed had the buffer been large enough. For conforming - vswprintf implementations the function must return a negative number - and set errno. - - What vswprintf sets errno to is undefined but Darwin seems to set it to - EOVERFLOW. The only expected errno are EILSEQ and EINVAL. Both of - those are defined in the standard and backed up by several conformance - statements. Note that ENOMEM mentioned in the manual page does not - apply to swprintf, only wprintf and fwprintf. - - Official manual page: - http://www.opengroup.org/onlinepubs/009695399/functions/swprintf.html - - Some conformance statements (AIX, Solaris): - http://www.opengroup.org/csq/view.mhtml?RID=ibm%2FSD1%2F3 - http://www.theopengroup.org/csq/view.mhtml?norationale=1&noreferences=1&RID=Fujitsu%2FSE2%2F10 - - Since EILSEQ and EINVAL are rather common but EOVERFLOW is not and since - EILSEQ and EINVAL are specifically defined to mean the error is other than - an undersized buffer and no other errno are defined we treat those two - as meaning hard errors and everything else gets the old behavior which - is to keep looping and increasing buffer size until the function succeeds. - - In practice it's impossible to determine before compilation which behavior - may be used. The vswprintf function may have vsnprintf-like behavior or - vice-versa. Behavior detected on one release can theoretically change - with an updated release. Not to mention that configure testing for it - would require the test to be run on the host system, not the build system - which makes cross compilation difficult. Therefore, we make no assumptions - about behavior and try our best to handle every known case, including the - case where wxVsnprintf returns a negative number and fails to set errno. - - There is yet one more non-standard implementation and that is our own. - Fortunately, that can be detected at compile-time. - - On top of all that, ISO C99 explicitly defines snprintf to write a null - character to the last position of the specified buffer. That would be at - at the given buffer size minus 1. It is supposed to do this even if it - turns out that the buffer is sized too small. - - Darwin (tested on 10.5) follows the C99 behavior exactly. - - Glibc 2.6 almost follows the C99 behavior except vswprintf never sets - errno even when it fails. However, it only seems to ever fail due - to an undersized buffer. -*/ -int wxString::PrintfV(const wxChar* pszFormat, va_list argptr) -{ - int size = 1024; - - for ( ;; ) - { - // Allocate 1 more character than we tell wxVsnprintf about - // just in case it is buggy. - // FIXME: I have a feeling that the underlying function was not buggy - // and I suspect it was to fix the buf[size] = '\0' line below - wxStringBuffer tmp(*this, size + 1); - wxChar *buf = tmp; - - if ( !buf ) - { - // out of memory - return -1; - } - - // wxVsnprintf() may modify the original arg pointer, so pass it - // only a copy - va_list argptrcopy; - wxVaCopy(argptrcopy, argptr); - -#ifndef __WXWINCE__ - // Set errno to 0 to make it determinate if wxVsnprintf fails to set it. - errno = 0; -#endif - int len = wxVsnprintf(buf, size, pszFormat, argptrcopy); - va_end(argptrcopy); - - // some implementations of vsnprintf() don't NUL terminate - // the string if there is not enough space for it so - // always do it manually - // FIXME: This really seems to be the wrong and would be an off-by-one - // bug except the code above allocates an extra character. - buf[size] = _T('\0'); - - // vsnprintf() may return either -1 (traditional Unix behaviour) or the - // total number of characters which would have been written if the - // buffer were large enough (newer standards such as Unix98) - if ( len < 0 ) - { -#if wxUSE_WXVSNPRINTF - // we know that our own implementation of wxVsnprintf() returns -1 - // only for a format error - thus there's something wrong with - // the user's format string - return -1; -#else // assume that system version only returns error if not enough space -#if !defined(__WXWINCE__) && (!defined(__OS2__) || defined(__INNOTEK_LIBC__)) - if( (errno == EILSEQ) || (errno == EINVAL) ) - // If errno was set to one of the two well-known hard errors - // then fail immediately to avoid an infinite loop. - return -1; - else -#endif // __WXWINCE__ - // still not enough, as we don't know how much we need, double the - // current size of the buffer - size *= 2; -#endif // wxUSE_WXVSNPRINTF/!wxUSE_WXVSNPRINTF - } - else if ( len >= size ) - { -#if wxUSE_WXVSNPRINTF - // we know that our own implementation of wxVsnprintf() returns - // size+1 when there's not enough space but that's not the size - // of the required buffer! - size *= 2; // so we just double the current size of the buffer -#else - // some vsnprintf() implementations NUL-terminate the buffer and - // some don't in len == size case, to be safe always add 1 - // FIXME: I don't quite understand this comment. The vsnprintf - // function is specifically defined to return the number of - // characters printed not including the null terminator. - // So OF COURSE you need to add 1 to get the right buffer size. - // The following line is definitely correct, no question. - size = len + 1; -#endif - } - else // ok, there was enough space - { - break; - } - } - - // we could have overshot - Shrink(); - - return length(); -} - -// ---------------------------------------------------------------------------- -// misc other operations -// ---------------------------------------------------------------------------- - -// returns true if the string matches the pattern which may contain '*' and -// '?' metacharacters (as usual, '?' matches any character and '*' any number -// of them) -bool wxString::Matches(const wxChar *pszMask) const -{ - // I disable this code as it doesn't seem to be faster (in fact, it seems - // to be much slower) than the old, hand-written code below and using it - // here requires always linking with libregex even if the user code doesn't - // use it -#if 0 // wxUSE_REGEX - // first translate the shell-like mask into a regex - wxString pattern; - pattern.reserve(wxStrlen(pszMask)); - - pattern += _T('^'); - while ( *pszMask ) - { - switch ( *pszMask ) - { - case _T('?'): - pattern += _T('.'); - break; - - case _T('*'): - pattern += _T(".*"); - break; - - case _T('^'): - case _T('.'): - case _T('$'): - case _T('('): - case _T(')'): - case _T('|'): - case _T('+'): - case _T('\\'): - // these characters are special in a RE, quote them - // (however note that we don't quote '[' and ']' to allow - // using them for Unix shell like matching) - pattern += _T('\\'); - // fall through - - default: - pattern += *pszMask; - } - - pszMask++; - } - pattern += _T('$'); - - // and now use it - return wxRegEx(pattern, wxRE_NOSUB | wxRE_EXTENDED).Matches(c_str()); -#else // !wxUSE_REGEX - // TODO: this is, of course, awfully inefficient... - - // the char currently being checked - const wxChar *pszTxt = c_str(); - - // the last location where '*' matched - const wxChar *pszLastStarInText = NULL; - const wxChar *pszLastStarInMask = NULL; - -match: - for ( ; *pszMask != wxT('\0'); pszMask++, pszTxt++ ) { - switch ( *pszMask ) { - case wxT('?'): - if ( *pszTxt == wxT('\0') ) - return false; - - // pszTxt and pszMask will be incremented in the loop statement - - break; - - case wxT('*'): - { - // remember where we started to be able to backtrack later - pszLastStarInText = pszTxt; - pszLastStarInMask = pszMask; - - // ignore special chars immediately following this one - // (should this be an error?) - while ( *pszMask == wxT('*') || *pszMask == wxT('?') ) - pszMask++; - - // if there is nothing more, match - if ( *pszMask == wxT('\0') ) - return true; - - // are there any other metacharacters in the mask? - size_t uiLenMask; - const wxChar *pEndMask = wxStrpbrk(pszMask, wxT("*?")); - - if ( pEndMask != NULL ) { - // we have to match the string between two metachars - uiLenMask = pEndMask - pszMask; - } - else { - // we have to match the remainder of the string - uiLenMask = wxStrlen(pszMask); - } - - wxString strToMatch(pszMask, uiLenMask); - const wxChar* pMatch = wxStrstr(pszTxt, strToMatch); - if ( pMatch == NULL ) - return false; - - // -1 to compensate "++" in the loop - pszTxt = pMatch + uiLenMask - 1; - pszMask += uiLenMask - 1; - } - break; - - default: - if ( *pszMask != *pszTxt ) - return false; - break; - } - } - - // match only if nothing left - if ( *pszTxt == wxT('\0') ) - return true; - - // if we failed to match, backtrack if we can - if ( pszLastStarInText ) { - pszTxt = pszLastStarInText + 1; - pszMask = pszLastStarInMask; - - pszLastStarInText = NULL; - - // don't bother resetting pszLastStarInMask, it's unnecessary - - goto match; - } - - return false; -#endif // wxUSE_REGEX/!wxUSE_REGEX -} - -// Count the number of chars -int wxString::Freq(wxChar ch) const -{ - int count = 0; - int len = length(); - for (int i = 0; i < len; i++) - { - if (GetChar(i) == ch) - count ++; - } - return count; -} - -// convert to upper case, return the copy of the string -wxString wxString::Upper() const -{ wxString s(*this); return s.MakeUpper(); } - -// convert to lower case, return the copy of the string -wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); } - -int wxString::sprintf(const wxChar *pszFormat, ...) - { - va_list argptr; - va_start(argptr, pszFormat); - int iLen = PrintfV(pszFormat, argptr); - va_end(argptr); - return iLen; - } - -// ============================================================================ -// ArrayString -// ============================================================================ - -#include "wx/arrstr.h" - -wxArrayString::wxArrayString(size_t sz, const wxChar** a) -{ -#if !wxUSE_STL - Init(false); -#endif - for (size_t i=0; i < sz; i++) - Add(a[i]); -} - -wxArrayString::wxArrayString(size_t sz, const wxString* a) -{ -#if !wxUSE_STL - Init(false); -#endif - for (size_t i=0; i < sz; i++) - Add(a[i]); -} - -#if !wxUSE_STL - -// size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT) -#define ARRAY_MAXSIZE_INCREMENT 4096 - -#ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h -#define ARRAY_DEFAULT_INITIAL_SIZE (16) -#endif - -#define STRING(p) ((wxString *)(&(p))) - -// ctor -void wxArrayString::Init(bool autoSort) -{ - m_nSize = - m_nCount = 0; - m_pItems = (wxChar **) NULL; - m_autoSort = autoSort; -} - -// copy ctor -wxArrayString::wxArrayString(const wxArrayString& src) -{ - Init(src.m_autoSort); - - *this = src; -} - -// assignment operator -wxArrayString& wxArrayString::operator=(const wxArrayString& src) -{ - if ( m_nSize > 0 ) - Clear(); - - Copy(src); - - m_autoSort = src.m_autoSort; - - return *this; -} - -void wxArrayString::Copy(const wxArrayString& src) -{ - if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE ) - Alloc(src.m_nCount); - - for ( size_t n = 0; n < src.m_nCount; n++ ) - Add(src[n]); -} - -// grow the array -void wxArrayString::Grow(size_t nIncrement) -{ - // only do it if no more place - if ( (m_nSize - m_nCount) < nIncrement ) { - // if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would - // be never resized! - #if ARRAY_DEFAULT_INITIAL_SIZE == 0 - #error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!" - #endif - - if ( m_nSize == 0 ) { - // was empty, alloc some memory - m_nSize = ARRAY_DEFAULT_INITIAL_SIZE; - if (m_nSize < nIncrement) - m_nSize = nIncrement; - m_pItems = new wxChar *[m_nSize]; - } - else { - // otherwise when it's called for the first time, nIncrement would be 0 - // and the array would never be expanded - // add 50% but not too much - size_t ndefIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE - ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1; - if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT ) - ndefIncrement = ARRAY_MAXSIZE_INCREMENT; - if ( nIncrement < ndefIncrement ) - nIncrement = ndefIncrement; - m_nSize += nIncrement; - wxChar **pNew = new wxChar *[m_nSize]; - - // copy data to new location - memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *)); - - // delete old memory (but do not release the strings!) - wxDELETEA(m_pItems); - - m_pItems = pNew; - } - } -} - -void wxArrayString::Free() -{ - for ( size_t n = 0; n < m_nCount; n++ ) { - STRING(m_pItems[n])->GetStringData()->Unlock(); - } -} - -// deletes all the strings from the list -void wxArrayString::Empty() -{ - Free(); - - m_nCount = 0; -} - -// as Empty, but also frees memory -void wxArrayString::Clear() -{ - Free(); - - m_nSize = - m_nCount = 0; - - wxDELETEA(m_pItems); -} - -// dtor -wxArrayString::~wxArrayString() -{ - Free(); - - wxDELETEA(m_pItems); -} - -void wxArrayString::reserve(size_t nSize) -{ - Alloc(nSize); -} - -// pre-allocates memory (frees the previous data!) -void wxArrayString::Alloc(size_t nSize) -{ - // only if old buffer was not big enough - if ( nSize > m_nSize ) { - wxChar **pNew = new wxChar *[nSize]; - if ( !pNew ) - return; - - memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *)); - delete [] m_pItems; - - m_pItems = pNew; - m_nSize = nSize; - } -} - -// minimizes the memory usage by freeing unused memory -void wxArrayString::Shrink() -{ - // only do it if we have some memory to free - if( m_nCount < m_nSize ) { - // allocates exactly as much memory as we need - wxChar **pNew = new wxChar *[m_nCount]; - - // copy data to new location - memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *)); - delete [] m_pItems; - m_pItems = pNew; - m_nSize = m_nCount; - } -} - -#if WXWIN_COMPATIBILITY_2_4 - -// return a wxString[] as required for some control ctors. -wxString* wxArrayString::GetStringArray() const -{ - wxString *array = 0; - - if( m_nCount > 0 ) - { - array = new wxString[m_nCount]; - for( size_t i = 0; i < m_nCount; i++ ) - array[i] = m_pItems[i]; - } - - return array; -} - -void wxArrayString::Remove(size_t nIndex, size_t nRemove) -{ - RemoveAt(nIndex, nRemove); -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -// searches the array for an item (forward or backwards) -int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const -{ - if ( m_autoSort ) { - // use binary search in the sorted array - wxASSERT_MSG( bCase && !bFromEnd, - wxT("search parameters ignored for auto sorted array") ); - - size_t i, - lo = 0, - hi = m_nCount; - int res; - while ( lo < hi ) { - i = (lo + hi)/2; - - res = wxStrcmp(sz, m_pItems[i]); - if ( res < 0 ) - hi = i; - else if ( res > 0 ) - lo = i + 1; - else - return i; - } - - return wxNOT_FOUND; - } - else { - // use linear search in unsorted array - if ( bFromEnd ) { - if ( m_nCount > 0 ) { - size_t ui = m_nCount; - do { - if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) ) - return ui; - } - while ( ui != 0 ); - } - } - else { - for( size_t ui = 0; ui < m_nCount; ui++ ) { - if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) ) - return ui; - } - } - } - - return wxNOT_FOUND; -} - -// add item at the end -size_t wxArrayString::Add(const wxString& str, size_t nInsert) -{ - if ( m_autoSort ) { - // insert the string at the correct position to keep the array sorted - size_t i, - lo = 0, - hi = m_nCount; - int res; - while ( lo < hi ) { - i = (lo + hi)/2; - - res = str.Cmp(m_pItems[i]); - if ( res < 0 ) - hi = i; - else if ( res > 0 ) - lo = i + 1; - else { - lo = hi = i; - break; - } - } - - wxASSERT_MSG( lo == hi, wxT("binary search broken") ); - - Insert(str, lo, nInsert); - - return (size_t)lo; - } - else { - wxASSERT( str.GetStringData()->IsValid() ); - - Grow(nInsert); - - for (size_t i = 0; i < nInsert; i++) - { - // the string data must not be deleted! - str.GetStringData()->Lock(); - - // just append - m_pItems[m_nCount + i] = (wxChar *)str.c_str(); // const_cast - } - size_t ret = m_nCount; - m_nCount += nInsert; - return ret; - } -} - -// add item at the given position -void wxArrayString::Insert(const wxString& str, size_t nIndex, size_t nInsert) -{ - wxASSERT( str.GetStringData()->IsValid() ); - - wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") ); - wxCHECK_RET( m_nCount <= m_nCount + nInsert, - wxT("array size overflow in wxArrayString::Insert") ); - - Grow(nInsert); - - memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], - (m_nCount - nIndex)*sizeof(wxChar *)); - - for (size_t i = 0; i < nInsert; i++) - { - str.GetStringData()->Lock(); - m_pItems[nIndex + i] = (wxChar *)str.c_str(); - } - m_nCount += nInsert; -} - -// range insert (STL 23.2.4.3) -void -wxArrayString::insert(iterator it, const_iterator first, const_iterator last) -{ - const int idx = it - begin(); - - // grow it once - Grow(last - first); - - // reset "it" since it can change inside Grow() - it = begin() + idx; - - while ( first != last ) - { - it = insert(it, *first); - - // insert returns an iterator to the last element inserted but we need - // insert the next after this one, that is before the next one - ++it; - - ++first; - } -} - -// expand the array -void wxArrayString::SetCount(size_t count) -{ - Alloc(count); - - wxString s; - while ( m_nCount < count ) - m_pItems[m_nCount++] = (wxChar *)s.c_str(); -} - -// removes item from array (by index) -void wxArrayString::RemoveAt(size_t nIndex, size_t nRemove) -{ - wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArrayString::Remove") ); - wxCHECK_RET( nIndex + nRemove <= m_nCount, - wxT("removing too many elements in wxArrayString::Remove") ); - - // release our lock - for (size_t i = 0; i < nRemove; i++) - Item(nIndex + i).GetStringData()->Unlock(); - - memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove], - (m_nCount - nIndex - nRemove)*sizeof(wxChar *)); - m_nCount -= nRemove; -} - -// removes item from array (by value) -void wxArrayString::Remove(const wxChar *sz) -{ - int iIndex = Index(sz); - - wxCHECK_RET( iIndex != wxNOT_FOUND, - wxT("removing inexistent element in wxArrayString::Remove") ); - - RemoveAt(iIndex); -} - -void wxArrayString::assign(const_iterator first, const_iterator last) -{ - reserve(last - first); - for(; first != last; ++first) - push_back(*first); -} - -// ---------------------------------------------------------------------------- -// sorting -// ---------------------------------------------------------------------------- - -// we can only sort one array at a time with the quick-sort based -// implementation -#if wxUSE_THREADS - // need a critical section to protect access to gs_compareFunction and - // gs_sortAscending variables - static wxCriticalSection gs_critsectStringSort; -#endif // wxUSE_THREADS - -// function to use for string comparaison -static wxArrayString::CompareFunction gs_compareFunction = NULL; - -// if we don't use the compare function, this flag tells us if we sort the -// array in ascending or descending order -static bool gs_sortAscending = true; - -// function which is called by quick sort -extern "C" int wxC_CALLING_CONV // LINKAGEMODE -wxStringCompareFunction(const void *first, const void *second) -{ - wxString *strFirst = (wxString *)first; - wxString *strSecond = (wxString *)second; - - if ( gs_compareFunction ) { - return gs_compareFunction(*strFirst, *strSecond); - } - else { - // maybe we should use wxStrcoll - int result = strFirst->Cmp(*strSecond); - - return gs_sortAscending ? result : -result; - } -} - -// sort array elements using passed comparaison function -void wxArrayString::Sort(CompareFunction compareFunction) -{ - wxCRIT_SECT_LOCKER(lockCmpFunc, gs_critsectStringSort); - - wxASSERT( !gs_compareFunction ); // must have been reset to NULL - gs_compareFunction = compareFunction; - - DoSort(); - - // reset it to NULL so that Sort(bool) will work the next time - gs_compareFunction = NULL; -} - -extern "C" -{ - typedef int (wxC_CALLING_CONV * wxStringCompareFn)(const void *first, - const void *second); -} - -void wxArrayString::Sort(CompareFunction2 compareFunction) -{ - qsort(m_pItems, m_nCount, sizeof(wxChar *), (wxStringCompareFn)compareFunction); -} - -void wxArrayString::Sort(bool reverseOrder) -{ - Sort(reverseOrder ? wxStringSortDescending : wxStringSortAscending); -} - -void wxArrayString::DoSort() -{ - wxCHECK_RET( !m_autoSort, wxT("can't use this method with sorted arrays") ); - - // just sort the pointers using qsort() - of course it only works because - // wxString() *is* a pointer to its data - qsort(m_pItems, m_nCount, sizeof(wxChar *), wxStringCompareFunction); -} - -bool wxArrayString::operator==(const wxArrayString& a) const -{ - if ( m_nCount != a.m_nCount ) - return false; - - for ( size_t n = 0; n < m_nCount; n++ ) - { - if ( Item(n) != a[n] ) - return false; - } - - return true; -} - -#endif // !wxUSE_STL - -int wxCMPFUNC_CONV wxStringSortAscending(wxString* s1, wxString* s2) -{ - return s1->Cmp(*s2); -} - -int wxCMPFUNC_CONV wxStringSortDescending(wxString* s1, wxString* s2) -{ - return -s1->Cmp(*s2); -} - -wxString* wxCArrayString::Release() -{ - wxString *r = GetStrings(); - m_strings = NULL; - return r; -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/string.cpp +// Purpose: wxString class +// Author: Vadim Zeitlin, Ryan Norton +// Modified by: +// Created: 29/01/98 +// RCS-ID: $Id: string.cpp 63008 2009-12-28 20:01:39Z VZ $ +// Copyright: (c) 1998 Vadim Zeitlin +// (c) 2004 Ryan Norton +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +/* + * About ref counting: + * 1) all empty strings use g_strEmpty, nRefs = -1 (set in Init()) + * 2) AllocBuffer() sets nRefs to 1, Lock() increments it by one + * 3) Unlock() decrements nRefs and frees memory if it goes to 0 + */ + +// =========================================================================== +// headers, declarations, constants +// =========================================================================== + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/thread.h" +#endif + +#include + +#ifndef __WXWINCE__ + #include +#endif + +#include +#include + +#ifdef __SALFORDC__ + #include +#endif + +// allocating extra space for each string consumes more memory but speeds up +// the concatenation operations (nLen is the current string's length) +// NB: EXTRA_ALLOC must be >= 0! +#define EXTRA_ALLOC (19 - nLen % 16) + +// --------------------------------------------------------------------------- +// static class variables definition +// --------------------------------------------------------------------------- + +#if !wxUSE_STL + //According to STL _must_ be a -1 size_t + const size_t wxStringBase::npos = (size_t) -1; +#endif + +// ---------------------------------------------------------------------------- +// static data +// ---------------------------------------------------------------------------- + +#if wxUSE_STL + +extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = _T(""); + +#else + +// for an empty string, GetStringData() will return this address: this +// structure has the same layout as wxStringData and it's data() method will +// return the empty string (dummy pointer) +static const struct +{ + wxStringData data; + wxChar dummy; +} g_strEmpty = { {-1, 0, 0}, wxT('\0') }; + +// empty C style string: points to 'string data' byte of g_strEmpty +extern const wxChar WXDLLIMPEXP_BASE *wxEmptyString = &g_strEmpty.dummy; + +#endif + +// ---------------------------------------------------------------------------- +// global functions +// ---------------------------------------------------------------------------- + +#if wxUSE_STD_IOSTREAM + +#include + +wxSTD ostream& operator<<(wxSTD ostream& os, const wxString& str) +{ +#ifdef __BORLANDC__ + os << str.mb_str(); +#else + os << str.c_str(); +#endif + return os; +} + +#endif // wxUSE_STD_IOSTREAM + +// ---------------------------------------------------------------------------- +// private classes +// ---------------------------------------------------------------------------- + +// this small class is used to gather statistics for performance tuning +//#define WXSTRING_STATISTICS +#ifdef WXSTRING_STATISTICS + class Averager + { + public: + Averager(const wxChar *sz) { m_sz = sz; m_nTotal = m_nCount = 0; } + ~Averager() + { wxPrintf("wxString: average %s = %f\n", m_sz, ((float)m_nTotal)/m_nCount); } + + void Add(size_t n) { m_nTotal += n; m_nCount++; } + + private: + size_t m_nCount, m_nTotal; + const wxChar *m_sz; + } g_averageLength("allocation size"), + g_averageSummandLength("summand length"), + g_averageConcatHit("hit probability in concat"), + g_averageInitialLength("initial string length"); + + #define STATISTICS_ADD(av, val) g_average##av.Add(val) +#else + #define STATISTICS_ADD(av, val) +#endif // WXSTRING_STATISTICS + +#if !wxUSE_STL + +// =========================================================================== +// wxStringData class deallocation +// =========================================================================== + +#if defined(__VISUALC__) && defined(_MT) && !defined(_DLL) +# pragma message (__FILE__ ": building with Multithreaded non DLL runtime has a performance impact on wxString!") +void wxStringData::Free() +{ + free(this); +} +#endif + +// =========================================================================== +// wxStringBase +// =========================================================================== + +// takes nLength elements of psz starting at nPos +void wxStringBase::InitWith(const wxChar *psz, size_t nPos, size_t nLength) +{ + Init(); + + // if the length is not given, assume the string to be NUL terminated + if ( nLength == npos ) { + wxASSERT_MSG( nPos <= wxStrlen(psz), _T("index out of bounds") ); + + nLength = wxStrlen(psz + nPos); + } + + STATISTICS_ADD(InitialLength, nLength); + + if ( nLength > 0 ) { + // trailing '\0' is written in AllocBuffer() + if ( !AllocBuffer(nLength) ) { + wxFAIL_MSG( _T("out of memory in wxStringBase::InitWith") ); + return; + } + wxTmemcpy(m_pchData, psz + nPos, nLength); + } +} + +// poor man's iterators are "void *" pointers +wxStringBase::wxStringBase(const void *pStart, const void *pEnd) +{ + if ( pEnd >= pStart ) + { + InitWith((const wxChar *)pStart, 0, + (const wxChar *)pEnd - (const wxChar *)pStart); + } + else + { + wxFAIL_MSG( _T("pStart is not before pEnd") ); + Init(); + } +} + +wxStringBase::wxStringBase(size_type n, wxChar ch) +{ + Init(); + append(n, ch); +} + +// --------------------------------------------------------------------------- +// memory allocation +// --------------------------------------------------------------------------- + +// allocates memory needed to store a C string of length nLen +bool wxStringBase::AllocBuffer(size_t nLen) +{ + // allocating 0 sized buffer doesn't make sense, all empty strings should + // reuse g_strEmpty + wxASSERT( nLen > 0 ); + + // make sure that we don't overflow + wxCHECK( nLen < (INT_MAX / sizeof(wxChar)) - + (sizeof(wxStringData) + EXTRA_ALLOC + 1), false ); + + STATISTICS_ADD(Length, nLen); + + // allocate memory: + // 1) one extra character for '\0' termination + // 2) sizeof(wxStringData) for housekeeping info + wxStringData* pData = (wxStringData*) + malloc(sizeof(wxStringData) + (nLen + EXTRA_ALLOC + 1)*sizeof(wxChar)); + + if ( pData == NULL ) { + // allocation failures are handled by the caller + return false; + } + + pData->nRefs = 1; + pData->nDataLength = nLen; + pData->nAllocLength = nLen + EXTRA_ALLOC; + m_pchData = pData->data(); // data starts after wxStringData + m_pchData[nLen] = wxT('\0'); + return true; +} + +// must be called before changing this string +bool wxStringBase::CopyBeforeWrite() +{ + wxStringData* pData = GetStringData(); + + if ( pData->IsShared() ) { + pData->Unlock(); // memory not freed because shared + size_t nLen = pData->nDataLength; + if ( !AllocBuffer(nLen) ) { + // allocation failures are handled by the caller + return false; + } + wxTmemcpy(m_pchData, pData->data(), nLen); + } + + wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner + + return true; +} + +// must be called before replacing contents of this string +bool wxStringBase::AllocBeforeWrite(size_t nLen) +{ + wxASSERT( nLen != 0 ); // doesn't make any sense + + // must not share string and must have enough space + wxStringData* pData = GetStringData(); + if ( pData->IsShared() || pData->IsEmpty() ) { + // can't work with old buffer, get new one + pData->Unlock(); + if ( !AllocBuffer(nLen) ) { + // allocation failures are handled by the caller + return false; + } + } + else { + if ( nLen > pData->nAllocLength ) { + // realloc the buffer instead of calling malloc() again, this is more + // efficient + STATISTICS_ADD(Length, nLen); + + nLen += EXTRA_ALLOC; + + pData = (wxStringData*) + realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); + + if ( pData == NULL ) { + // allocation failures are handled by the caller + // keep previous data since reallocation failed + return false; + } + + pData->nAllocLength = nLen; + m_pchData = pData->data(); + } + } + + wxASSERT( !GetStringData()->IsShared() ); // we must be the only owner + + // it doesn't really matter what the string length is as it's going to be + // overwritten later but, for extra safety, set it to 0 for now as we may + // have some junk in m_pchData + GetStringData()->nDataLength = 0; + + return true; +} + +wxStringBase& wxStringBase::append(size_t n, wxChar ch) +{ + size_type len = length(); + + if ( !Alloc(len + n) || !CopyBeforeWrite() ) { + wxFAIL_MSG( _T("out of memory in wxStringBase::append") ); + } + GetStringData()->nDataLength = len + n; + m_pchData[len + n] = '\0'; + for ( size_t i = 0; i < n; ++i ) + m_pchData[len + i] = ch; + return *this; +} + +void wxStringBase::resize(size_t nSize, wxChar ch) +{ + size_t len = length(); + + if ( nSize < len ) + { + erase(begin() + nSize, end()); + } + else if ( nSize > len ) + { + append(nSize - len, ch); + } + //else: we have exactly the specified length, nothing to do +} + +// allocate enough memory for nLen characters +bool wxStringBase::Alloc(size_t nLen) +{ + wxStringData *pData = GetStringData(); + if ( pData->nAllocLength <= nLen ) { + if ( pData->IsEmpty() ) { + nLen += EXTRA_ALLOC; + + pData = (wxStringData *) + malloc(sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); + + if ( pData == NULL ) { + // allocation failure handled by caller + return false; + } + + pData->nRefs = 1; + pData->nDataLength = 0; + pData->nAllocLength = nLen; + m_pchData = pData->data(); // data starts after wxStringData + m_pchData[0u] = wxT('\0'); + } + else if ( pData->IsShared() ) { + pData->Unlock(); // memory not freed because shared + size_t nOldLen = pData->nDataLength; + if ( !AllocBuffer(nLen) ) { + // allocation failure handled by caller + return false; + } + // +1 to copy the terminator, too + memcpy(m_pchData, pData->data(), (nOldLen+1)*sizeof(wxChar)); + GetStringData()->nDataLength = nOldLen; + } + else { + nLen += EXTRA_ALLOC; + + pData = (wxStringData *) + realloc(pData, sizeof(wxStringData) + (nLen + 1)*sizeof(wxChar)); + + if ( pData == NULL ) { + // allocation failure handled by caller + // keep previous data since reallocation failed + return false; + } + + // it's not important if the pointer changed or not (the check for this + // is not faster than assigning to m_pchData in all cases) + pData->nAllocLength = nLen; + m_pchData = pData->data(); + } + } + //else: we've already got enough + return true; +} + +wxStringBase::iterator wxStringBase::begin() +{ + if (length() > 0) + CopyBeforeWrite(); + return m_pchData; +} + +wxStringBase::iterator wxStringBase::end() +{ + if (length() > 0) + CopyBeforeWrite(); + return m_pchData + length(); +} + +wxStringBase::iterator wxStringBase::erase(iterator it) +{ + size_type idx = it - begin(); + erase(idx, 1); + return begin() + idx; +} + +wxStringBase& wxStringBase::erase(size_t nStart, size_t nLen) +{ + wxASSERT(nStart <= length()); + size_t strLen = length() - nStart; + // delete nLen or up to the end of the string characters + nLen = strLen < nLen ? strLen : nLen; + wxString strTmp(c_str(), nStart); + strTmp.append(c_str() + nStart + nLen, length() - nStart - nLen); + + swap(strTmp); + return *this; +} + +wxStringBase& wxStringBase::insert(size_t nPos, const wxChar *sz, size_t n) +{ + wxASSERT( nPos <= length() ); + + if ( n == npos ) n = wxStrlen(sz); + if ( n == 0 ) return *this; + + if ( !Alloc(length() + n) || !CopyBeforeWrite() ) { + wxFAIL_MSG( _T("out of memory in wxStringBase::insert") ); + } + + memmove(m_pchData + nPos + n, m_pchData + nPos, + (length() - nPos) * sizeof(wxChar)); + memcpy(m_pchData + nPos, sz, n * sizeof(wxChar)); + GetStringData()->nDataLength = length() + n; + m_pchData[length()] = '\0'; + + return *this; +} + +void wxStringBase::swap(wxStringBase& str) +{ + wxChar* tmp = str.m_pchData; + str.m_pchData = m_pchData; + m_pchData = tmp; +} + +size_t wxStringBase::find(const wxStringBase& str, size_t nStart) const +{ + // deal with the special case of empty string first + const size_t nLen = length(); + const size_t nLenOther = str.length(); + + if ( !nLenOther ) + { + // empty string is a substring of anything + return 0; + } + + if ( !nLen ) + { + // the other string is non empty so can't be our substring + return npos; + } + + wxASSERT( str.GetStringData()->IsValid() ); + wxASSERT( nStart <= nLen ); + + const wxChar * const other = str.c_str(); + + // anchor + const wxChar* p = (const wxChar*)wxTmemchr(c_str() + nStart, + *other, + nLen - nStart); + + if ( !p ) + return npos; + + while ( p - c_str() + nLenOther <= nLen && wxTmemcmp(p, other, nLenOther) ) + { + p++; + + // anchor again + p = (const wxChar*)wxTmemchr(p, *other, nLen - (p - c_str())); + + if ( !p ) + return npos; + } + + return p - c_str() + nLenOther <= nLen ? p - c_str() : npos; +} + +size_t wxStringBase::find(const wxChar* sz, size_t nStart, size_t n) const +{ + return find(wxStringBase(sz, n), nStart); +} + +size_t wxStringBase::find(wxChar ch, size_t nStart) const +{ + wxASSERT( nStart <= length() ); + + const wxChar *p = (const wxChar*)wxTmemchr(c_str() + nStart, ch, length() - nStart); + + return p == NULL ? npos : p - c_str(); +} + +size_t wxStringBase::rfind(const wxStringBase& str, size_t nStart) const +{ + wxASSERT( str.GetStringData()->IsValid() ); + wxASSERT( nStart == npos || nStart <= length() ); + + if ( length() >= str.length() ) + { + // avoids a corner case later + if ( length() == 0 && str.length() == 0 ) + return 0; + + // "top" is the point where search starts from + size_t top = length() - str.length(); + + if ( nStart == npos ) + nStart = length() - 1; + if ( nStart < top ) + top = nStart; + + const wxChar *cursor = c_str() + top; + do + { + if ( wxTmemcmp(cursor, str.c_str(), + str.length()) == 0 ) + { + return cursor - c_str(); + } + } while ( cursor-- > c_str() ); + } + + return npos; +} + +size_t wxStringBase::rfind(const wxChar* sz, size_t nStart, size_t n) const +{ + return rfind(wxStringBase(sz, n), nStart); +} + +size_t wxStringBase::rfind(wxChar ch, size_t nStart) const +{ + if ( nStart == npos ) + { + nStart = length(); + } + else + { + wxASSERT( nStart <= length() ); + } + + const wxChar *actual; + for ( actual = c_str() + ( nStart == npos ? length() : nStart + 1 ); + actual > c_str(); --actual ) + { + if ( *(actual - 1) == ch ) + return (actual - 1) - c_str(); + } + + return npos; +} + +size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart) const +{ + wxASSERT(nStart <= length()); + + size_t len = wxStrlen(sz); + + size_t i; + for(i = nStart; i < this->length(); ++i) + { + if (wxTmemchr(sz, *(c_str() + i), len)) + break; + } + + if(i == this->length()) + return npos; + else + return i; +} + +size_t wxStringBase::find_first_of(const wxChar* sz, size_t nStart, + size_t n) const +{ + return find_first_of(wxStringBase(sz, n), nStart); +} + +size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart) const +{ + if ( nStart == npos ) + { + nStart = length() - 1; + } + else + { + wxASSERT_MSG( nStart <= length(), + _T("invalid index in find_last_of()") ); + } + + size_t len = wxStrlen(sz); + + for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) + { + if ( wxTmemchr(sz, *p, len) ) + return p - c_str(); + } + + return npos; +} + +size_t wxStringBase::find_last_of(const wxChar* sz, size_t nStart, + size_t n) const +{ + return find_last_of(wxStringBase(sz, n), nStart); +} + +size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart) const +{ + if ( nStart == npos ) + { + nStart = length(); + } + else + { + wxASSERT( nStart <= length() ); + } + + size_t len = wxStrlen(sz); + + size_t i; + for(i = nStart; i < this->length(); ++i) + { + if (!wxTmemchr(sz, *(c_str() + i), len)) + break; + } + + if(i == this->length()) + return npos; + else + return i; +} + +size_t wxStringBase::find_first_not_of(const wxChar* sz, size_t nStart, + size_t n) const +{ + return find_first_not_of(wxStringBase(sz, n), nStart); +} + +size_t wxStringBase::find_first_not_of(wxChar ch, size_t nStart) const +{ + wxASSERT( nStart <= length() ); + + for ( const wxChar *p = c_str() + nStart; *p; p++ ) + { + if ( *p != ch ) + return p - c_str(); + } + + return npos; +} + +size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart) const +{ + if ( nStart == npos ) + { + nStart = length() - 1; + } + else + { + wxASSERT( nStart <= length() ); + } + + size_t len = wxStrlen(sz); + + for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) + { + if ( !wxTmemchr(sz, *p,len) ) + return p - c_str(); + } + + return npos; +} + +size_t wxStringBase::find_last_not_of(const wxChar* sz, size_t nStart, + size_t n) const +{ + return find_last_not_of(wxStringBase(sz, n), nStart); +} + +size_t wxStringBase::find_last_not_of(wxChar ch, size_t nStart) const +{ + if ( nStart == npos ) + { + nStart = length() - 1; + } + else + { + wxASSERT( nStart <= length() ); + } + + for ( const wxChar *p = c_str() + nStart; p >= c_str(); --p ) + { + if ( *p != ch ) + return p - c_str(); + } + + return npos; +} + +wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, + const wxChar *sz) +{ + wxASSERT_MSG( nStart <= length(), + _T("index out of bounds in wxStringBase::replace") ); + size_t strLen = length() - nStart; + nLen = strLen < nLen ? strLen : nLen; + + wxStringBase strTmp; + strTmp.reserve(length()); // micro optimisation to avoid multiple mem allocs + + //This is kind of inefficient, but its pretty good considering... + //we don't want to use character access operators here because on STL + //it will freeze the reference count of strTmp, which means a deep copy + //at the end when swap is called + // + //Also, we can't use append with the full character pointer and must + //do it manually because this string can contain null characters + for(size_t i1 = 0; i1 < nStart; ++i1) + strTmp.append(1, this->c_str()[i1]); + + //its safe to do the full version here because + //sz must be a normal c string + strTmp.append(sz); + + for(size_t i2 = nStart + nLen; i2 < length(); ++i2) + strTmp.append(1, this->c_str()[i2]); + + swap(strTmp); + return *this; +} + +wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, + size_t nCount, wxChar ch) +{ + return replace(nStart, nLen, wxStringBase(nCount, ch).c_str()); +} + +wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, + const wxStringBase& str, + size_t nStart2, size_t nLen2) +{ + return replace(nStart, nLen, str.substr(nStart2, nLen2)); +} + +wxStringBase& wxStringBase::replace(size_t nStart, size_t nLen, + const wxChar* sz, size_t nCount) +{ + return replace(nStart, nLen, wxStringBase(sz, nCount).c_str()); +} + +wxStringBase wxStringBase::substr(size_t nStart, size_t nLen) const +{ + if ( nLen == npos ) + nLen = length() - nStart; + return wxStringBase(*this, nStart, nLen); +} + +// assigns one string to another +wxStringBase& wxStringBase::operator=(const wxStringBase& stringSrc) +{ + wxASSERT( stringSrc.GetStringData()->IsValid() ); + + // don't copy string over itself + if ( m_pchData != stringSrc.m_pchData ) { + if ( stringSrc.GetStringData()->IsEmpty() ) { + Reinit(); + } + else { + // adjust references + GetStringData()->Unlock(); + m_pchData = stringSrc.m_pchData; + GetStringData()->Lock(); + } + } + + return *this; +} + +// assigns a single character +wxStringBase& wxStringBase::operator=(wxChar ch) +{ + if ( !AssignCopy(1, &ch) ) { + wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(wxChar)") ); + } + return *this; +} + +// assigns C string +wxStringBase& wxStringBase::operator=(const wxChar *psz) +{ + if ( !AssignCopy(wxStrlen(psz), psz) ) { + wxFAIL_MSG( _T("out of memory in wxStringBase::operator=(const wxChar *)") ); + } + return *this; +} + +// helper function: does real copy +bool wxStringBase::AssignCopy(size_t nSrcLen, const wxChar *pszSrcData) +{ + if ( nSrcLen == 0 ) { + Reinit(); + } + else { + if ( !AllocBeforeWrite(nSrcLen) ) { + // allocation failure handled by caller + return false; + } + + // use memmove() and not memcpy() here as we might be copying from our own + // buffer in case of assignment such as "s = s.c_str()" (see #11294) + memmove(m_pchData, pszSrcData, nSrcLen*sizeof(wxChar)); + + GetStringData()->nDataLength = nSrcLen; + m_pchData[nSrcLen] = wxT('\0'); + } + return true; +} + +// --------------------------------------------------------------------------- +// string concatenation +// --------------------------------------------------------------------------- + +// add something to this string +bool wxStringBase::ConcatSelf(size_t nSrcLen, const wxChar *pszSrcData, + size_t nMaxLen) +{ + STATISTICS_ADD(SummandLength, nSrcLen); + + nSrcLen = nSrcLen < nMaxLen ? nSrcLen : nMaxLen; + + // concatenating an empty string is a NOP + if ( nSrcLen > 0 ) { + wxStringData *pData = GetStringData(); + size_t nLen = pData->nDataLength; + size_t nNewLen = nLen + nSrcLen; + + // take special care when appending part of this string to itself: the code + // below reallocates our buffer and this invalidates pszSrcData pointer so + // we have to copy it in another temporary string in this case (but avoid + // doing this unnecessarily) + if ( pszSrcData >= m_pchData && pszSrcData < m_pchData + nLen ) + { + wxStringBase tmp(pszSrcData, nSrcLen); + return ConcatSelf(nSrcLen, tmp.m_pchData, nSrcLen); + } + + // alloc new buffer if current is too small + if ( pData->IsShared() ) { + STATISTICS_ADD(ConcatHit, 0); + + // we have to allocate another buffer + wxStringData* pOldData = GetStringData(); + if ( !AllocBuffer(nNewLen) ) { + // allocation failure handled by caller + return false; + } + memcpy(m_pchData, pOldData->data(), nLen*sizeof(wxChar)); + pOldData->Unlock(); + } + else if ( nNewLen > pData->nAllocLength ) { + STATISTICS_ADD(ConcatHit, 0); + + reserve(nNewLen); + // we have to grow the buffer + if ( capacity() < nNewLen ) { + // allocation failure handled by caller + return false; + } + } + else { + STATISTICS_ADD(ConcatHit, 1); + + // the buffer is already big enough + } + + // should be enough space + wxASSERT( nNewLen <= GetStringData()->nAllocLength ); + + // fast concatenation - all is done in our buffer + memcpy(m_pchData + nLen, pszSrcData, nSrcLen*sizeof(wxChar)); + + m_pchData[nNewLen] = wxT('\0'); // put terminating '\0' + GetStringData()->nDataLength = nNewLen; // and fix the length + } + //else: the string to append was empty + return true; +} + +// --------------------------------------------------------------------------- +// simple sub-string extraction +// --------------------------------------------------------------------------- + +// helper function: clone the data attached to this string +bool wxStringBase::AllocCopy(wxString& dest, int nCopyLen, int nCopyIndex) const +{ + if ( nCopyLen == 0 ) { + dest.Init(); + } + else { + if ( !dest.AllocBuffer(nCopyLen) ) { + // allocation failure handled by caller + return false; + } + memcpy(dest.m_pchData, m_pchData + nCopyIndex, nCopyLen*sizeof(wxChar)); + } + return true; +} + +#endif // !wxUSE_STL + +#if !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE) + +#if !wxUSE_STL + #define STRINGCLASS wxStringBase +#else + #define STRINGCLASS wxString +#endif + +static inline int wxDoCmp(const wxChar* s1, size_t l1, + const wxChar* s2, size_t l2) +{ + if( l1 == l2 ) + return wxTmemcmp(s1, s2, l1); + else if( l1 < l2 ) + { + int ret = wxTmemcmp(s1, s2, l1); + return ret == 0 ? -1 : ret; + } + else + { + int ret = wxTmemcmp(s1, s2, l2); + return ret == 0 ? +1 : ret; + } +} + +int STRINGCLASS::compare(const wxStringBase& str) const +{ + return ::wxDoCmp(data(), length(), str.data(), str.length()); +} + +int STRINGCLASS::compare(size_t nStart, size_t nLen, + const wxStringBase& str) const +{ + wxASSERT(nStart <= length()); + size_type strLen = length() - nStart; + nLen = strLen < nLen ? strLen : nLen; + return ::wxDoCmp(data() + nStart, nLen, str.data(), str.length()); +} + +int STRINGCLASS::compare(size_t nStart, size_t nLen, + const wxStringBase& str, + size_t nStart2, size_t nLen2) const +{ + wxASSERT(nStart <= length()); + wxASSERT(nStart2 <= str.length()); + size_type strLen = length() - nStart, + strLen2 = str.length() - nStart2; + nLen = strLen < nLen ? strLen : nLen; + nLen2 = strLen2 < nLen2 ? strLen2 : nLen2; + return ::wxDoCmp(data() + nStart, nLen, str.data() + nStart2, nLen2); +} + +int STRINGCLASS::compare(const wxChar* sz) const +{ + size_t nLen = wxStrlen(sz); + return ::wxDoCmp(data(), length(), sz, nLen); +} + +int STRINGCLASS::compare(size_t nStart, size_t nLen, + const wxChar* sz, size_t nCount) const +{ + wxASSERT(nStart <= length()); + size_type strLen = length() - nStart; + nLen = strLen < nLen ? strLen : nLen; + if( nCount == npos ) + nCount = wxStrlen(sz); + + return ::wxDoCmp(data() + nStart, nLen, sz, nCount); +} + +#undef STRINGCLASS + +#endif // !wxUSE_STL || !defined(HAVE_STD_STRING_COMPARE) + +// =========================================================================== +// wxString class core +// =========================================================================== + +// --------------------------------------------------------------------------- +// construction and conversion +// --------------------------------------------------------------------------- + +#if wxUSE_UNICODE + +// from multibyte string +wxString::wxString(const char *psz, const wxMBConv& conv, size_t nLength) +{ + // anything to do? + if ( psz && nLength != 0 ) + { + if ( nLength == npos ) + { + nLength = wxNO_LEN; + } + + size_t nLenWide; + wxWCharBuffer wbuf = conv.cMB2WC(psz, nLength, &nLenWide); + + if ( nLenWide ) + assign(wbuf, nLenWide); + } +} + +//Convert wxString in Unicode mode to a multi-byte string +const wxCharBuffer wxString::mb_str(const wxMBConv& conv) const +{ + return conv.cWC2MB(c_str(), length() + 1 /* size, not length */, NULL); +} + +#else // ANSI + +#if wxUSE_WCHAR_T + +// from wide string +wxString::wxString(const wchar_t *pwz, const wxMBConv& conv, size_t nLength) +{ + // anything to do? + if ( pwz && nLength != 0 ) + { + if ( nLength == npos ) + { + nLength = wxNO_LEN; + } + + size_t nLenMB; + wxCharBuffer buf = conv.cWC2MB(pwz, nLength, &nLenMB); + + if ( nLenMB ) + assign(buf, nLenMB); + } +} + +//Converts this string to a wide character string if unicode +//mode is not enabled and wxUSE_WCHAR_T is enabled +const wxWCharBuffer wxString::wc_str(const wxMBConv& conv) const +{ + return conv.cMB2WC(c_str(), length() + 1 /* size, not length */, NULL); +} + +#endif // wxUSE_WCHAR_T + +#endif // Unicode/ANSI + +// shrink to minimal size (releasing extra memory) +bool wxString::Shrink() +{ + wxString tmp(begin(), end()); + swap(tmp); + return tmp.length() == length(); +} + +#if !wxUSE_STL +// get the pointer to writable buffer of (at least) nLen bytes +wxChar *wxString::GetWriteBuf(size_t nLen) +{ + if ( !AllocBeforeWrite(nLen) ) { + // allocation failure handled by caller + return NULL; + } + + wxASSERT( GetStringData()->nRefs == 1 ); + GetStringData()->Validate(false); + + return m_pchData; +} + +// put string back in a reasonable state after GetWriteBuf +void wxString::UngetWriteBuf() +{ + UngetWriteBuf(wxStrlen(m_pchData)); +} + +void wxString::UngetWriteBuf(size_t nLen) +{ + wxStringData * const pData = GetStringData(); + + wxASSERT_MSG( nLen < pData->nAllocLength, _T("buffer overrun") ); + + // the strings we store are always NUL-terminated + pData->data()[nLen] = _T('\0'); + pData->nDataLength = nLen; + pData->Validate(true); +} +#endif // !wxUSE_STL + +// --------------------------------------------------------------------------- +// data access +// --------------------------------------------------------------------------- + +// all functions are inline in string.h + +// --------------------------------------------------------------------------- +// assignment operators +// --------------------------------------------------------------------------- + +#if !wxUSE_UNICODE + +// same as 'signed char' variant +wxString& wxString::operator=(const unsigned char* psz) +{ + *this = (const char *)psz; + return *this; +} + +#if wxUSE_WCHAR_T +wxString& wxString::operator=(const wchar_t *pwz) +{ + wxString str(pwz); + swap(str); + return *this; +} +#endif + +#endif + +/* + * concatenation functions come in 5 flavours: + * string + string + * char + string and string + char + * C str + string and string + C str + */ + +wxString operator+(const wxString& str1, const wxString& str2) +{ +#if !wxUSE_STL + wxASSERT( str1.GetStringData()->IsValid() ); + wxASSERT( str2.GetStringData()->IsValid() ); +#endif + + wxString s = str1; + s += str2; + + return s; +} + +wxString operator+(const wxString& str, wxChar ch) +{ +#if !wxUSE_STL + wxASSERT( str.GetStringData()->IsValid() ); +#endif + + wxString s = str; + s += ch; + + return s; +} + +wxString operator+(wxChar ch, const wxString& str) +{ +#if !wxUSE_STL + wxASSERT( str.GetStringData()->IsValid() ); +#endif + + wxString s = ch; + s += str; + + return s; +} + +wxString operator+(const wxString& str, const wxChar *psz) +{ +#if !wxUSE_STL + wxASSERT( str.GetStringData()->IsValid() ); +#endif + + wxString s; + if ( !s.Alloc(wxStrlen(psz) + str.length()) ) { + wxFAIL_MSG( _T("out of memory in wxString::operator+") ); + } + s += str; + s += psz; + + return s; +} + +wxString operator+(const wxChar *psz, const wxString& str) +{ +#if !wxUSE_STL + wxASSERT( str.GetStringData()->IsValid() ); +#endif + + wxString s; + if ( !s.Alloc(wxStrlen(psz) + str.length()) ) { + wxFAIL_MSG( _T("out of memory in wxString::operator+") ); + } + s = psz; + s += str; + + return s; +} + +// =========================================================================== +// other common string functions +// =========================================================================== + +int wxString::Cmp(const wxString& s) const +{ + return compare(s); +} + +int wxString::Cmp(const wxChar* psz) const +{ + return compare(psz); +} + +static inline int wxDoCmpNoCase(const wxChar* s1, size_t l1, + const wxChar* s2, size_t l2) +{ + size_t i; + + if( l1 == l2 ) + { + for(i = 0; i < l1; ++i) + { + if(wxTolower(s1[i]) != wxTolower(s2[i])) + break; + } + return i == l1 ? 0 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; + } + else if( l1 < l2 ) + { + for(i = 0; i < l1; ++i) + { + if(wxTolower(s1[i]) != wxTolower(s2[i])) + break; + } + return i == l1 ? -1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; + } + else + { + for(i = 0; i < l2; ++i) + { + if(wxTolower(s1[i]) != wxTolower(s2[i])) + break; + } + return i == l2 ? 1 : wxTolower(s1[i]) < wxTolower(s2[i]) ? -1 : 1; + } +} + +int wxString::CmpNoCase(const wxString& s) const +{ + return wxDoCmpNoCase(data(), length(), s.data(), s.length()); +} + +int wxString::CmpNoCase(const wxChar* psz) const +{ + int nLen = wxStrlen(psz); + + return wxDoCmpNoCase(data(), length(), psz, nLen); +} + + +#if wxUSE_UNICODE + +#ifdef __MWERKS__ +#ifndef __SCHAR_MAX__ +#define __SCHAR_MAX__ 127 +#endif +#endif + +wxString wxString::FromAscii(const char *ascii) +{ + if (!ascii) + return wxEmptyString; + + size_t len = strlen( ascii ); + wxString res; + + if ( len ) + { + wxStringBuffer buf(res, len); + + wchar_t *dest = buf; + + for ( ;; ) + { + if ( (*dest++ = (wchar_t)(unsigned char)*ascii++) == L'\0' ) + break; + } + } + + return res; +} + +wxString wxString::FromAscii(const char ascii) +{ + // What do we do with '\0' ? + + wxString res; + res += (wchar_t)(unsigned char) ascii; + + return res; +} + +const wxCharBuffer wxString::ToAscii() const +{ + // this will allocate enough space for the terminating NUL too + wxCharBuffer buffer(length()); + + + char *dest = buffer.data(); + + const wchar_t *pwc = c_str(); + for ( ;; ) + { + *dest++ = (char)(*pwc > SCHAR_MAX ? wxT('_') : *pwc); + + // the output string can't have embedded NULs anyhow, so we can safely + // stop at first of them even if we do have any + if ( !*pwc++ ) + break; + } + + return buffer; +} + +#endif // Unicode + +// extract string of length nCount starting at nFirst +wxString wxString::Mid(size_t nFirst, size_t nCount) const +{ + size_t nLen = length(); + + // default value of nCount is npos and means "till the end" + if ( nCount == npos ) + { + nCount = nLen - nFirst; + } + + // out-of-bounds requests return sensible things + if ( nFirst + nCount > nLen ) + { + nCount = nLen - nFirst; + } + + if ( nFirst > nLen ) + { + // AllocCopy() will return empty string + return wxEmptyString; + } + + wxString dest(*this, nFirst, nCount); + if ( dest.length() != nCount ) + { + wxFAIL_MSG( _T("out of memory in wxString::Mid") ); + } + + return dest; +} + +// check that the string starts with prefix and return the rest of the string +// in the provided pointer if it is not NULL, otherwise return false +bool wxString::StartsWith(const wxChar *prefix, wxString *rest) const +{ + wxASSERT_MSG( prefix, _T("invalid parameter in wxString::StartsWith") ); + + // first check if the beginning of the string matches the prefix: note + // that we don't have to check that we don't run out of this string as + // when we reach the terminating NUL, either prefix string ends too (and + // then it's ok) or we break out of the loop because there is no match + const wxChar *p = c_str(); + while ( *prefix ) + { + if ( *prefix++ != *p++ ) + { + // no match + return false; + } + } + + if ( rest ) + { + // put the rest of the string into provided pointer + *rest = p; + } + + return true; +} + + +// check that the string ends with suffix and return the rest of it in the +// provided pointer if it is not NULL, otherwise return false +bool wxString::EndsWith(const wxChar *suffix, wxString *rest) const +{ + wxASSERT_MSG( suffix, _T("invalid parameter in wxString::EndssWith") ); + + int start = length() - wxStrlen(suffix); + if ( start < 0 || wxStrcmp(c_str() + start, suffix) != 0 ) + return false; + + if ( rest ) + { + // put the rest of the string into provided pointer + rest->assign(*this, 0, start); + } + + return true; +} + + +// extract nCount last (rightmost) characters +wxString wxString::Right(size_t nCount) const +{ + if ( nCount > length() ) + nCount = length(); + + wxString dest(*this, length() - nCount, nCount); + if ( dest.length() != nCount ) { + wxFAIL_MSG( _T("out of memory in wxString::Right") ); + } + return dest; +} + +// get all characters after the last occurence of ch +// (returns the whole string if ch not found) +wxString wxString::AfterLast(wxChar ch) const +{ + wxString str; + int iPos = Find(ch, true); + if ( iPos == wxNOT_FOUND ) + str = *this; + else + str = c_str() + iPos + 1; + + return str; +} + +// extract nCount first (leftmost) characters +wxString wxString::Left(size_t nCount) const +{ + if ( nCount > length() ) + nCount = length(); + + wxString dest(*this, 0, nCount); + if ( dest.length() != nCount ) { + wxFAIL_MSG( _T("out of memory in wxString::Left") ); + } + return dest; +} + +// get all characters before the first occurence of ch +// (returns the whole string if ch not found) +wxString wxString::BeforeFirst(wxChar ch) const +{ + int iPos = Find(ch); + if ( iPos == wxNOT_FOUND ) iPos = length(); + return wxString(*this, 0, iPos); +} + +/// get all characters before the last occurence of ch +/// (returns empty string if ch not found) +wxString wxString::BeforeLast(wxChar ch) const +{ + wxString str; + int iPos = Find(ch, true); + if ( iPos != wxNOT_FOUND && iPos != 0 ) + str = wxString(c_str(), iPos); + + return str; +} + +/// get all characters after the first occurence of ch +/// (returns empty string if ch not found) +wxString wxString::AfterFirst(wxChar ch) const +{ + wxString str; + int iPos = Find(ch); + if ( iPos != wxNOT_FOUND ) + str = c_str() + iPos + 1; + + return str; +} + +// replace first (or all) occurences of some substring with another one +size_t +wxString::Replace(const wxChar *szOld, const wxChar *szNew, bool bReplaceAll) +{ + // if we tried to replace an empty string we'd enter an infinite loop below + wxCHECK_MSG( szOld && *szOld && szNew, 0, + _T("wxString::Replace(): invalid parameter") ); + + size_t uiCount = 0; // count of replacements made + + // optimize the special common case of replacing one character with another + // one + if ( szOld[1] == '\0' && (szNew[0] != '\0' && szNew[1] == '\0') ) + { + // this loop is the simplified version of the one below + for ( size_t pos = 0; ; ) + { + pos = find(*szOld, pos); + if ( pos == npos ) + break; + + (*this)[pos++] = *szNew; + + uiCount++; + + if ( !bReplaceAll ) + break; + } + } + else // general case + { + const size_t uiOldLen = wxStrlen(szOld); + const size_t uiNewLen = wxStrlen(szNew); + + for ( size_t pos = 0; ; ) + { + pos = find(szOld, pos); + if ( pos == npos ) + break; + + // replace this occurrence of the old string with the new one + replace(pos, uiOldLen, szNew, uiNewLen); + + // move past the string that was replaced + pos += uiNewLen; + + // increase replace count + uiCount++; + + // stop now? + if ( !bReplaceAll ) + break; + } + } + + return uiCount; +} + +bool wxString::IsAscii() const +{ + const wxChar *s = (const wxChar*) *this; + while(*s){ + if(!isascii(*s)) return(false); + s++; + } + return(true); +} + +bool wxString::IsWord() const +{ + const wxChar *s = (const wxChar*) *this; + while(*s){ + if(!wxIsalpha(*s)) return(false); + s++; + } + return(true); +} + +bool wxString::IsNumber() const +{ + const wxChar *s = (const wxChar*) *this; + if (wxStrlen(s)) + if ((s[0] == wxT('-')) || (s[0] == wxT('+'))) s++; + while(*s){ + if(!wxIsdigit(*s)) return(false); + s++; + } + return(true); +} + +wxString wxString::Strip(stripType w) const +{ + wxString s = *this; + if ( w & leading ) s.Trim(false); + if ( w & trailing ) s.Trim(true); + return s; +} + +// --------------------------------------------------------------------------- +// case conversion +// --------------------------------------------------------------------------- + +wxString& wxString::MakeUpper() +{ + for ( iterator it = begin(), en = end(); it != en; ++it ) + *it = (wxChar)wxToupper(*it); + + return *this; +} + +wxString& wxString::MakeLower() +{ + for ( iterator it = begin(), en = end(); it != en; ++it ) + *it = (wxChar)wxTolower(*it); + + return *this; +} + +// --------------------------------------------------------------------------- +// trimming and padding +// --------------------------------------------------------------------------- + +// some compilers (VC++ 6.0 not to name them) return true for a call to +// isspace('\xEA') in the C locale which seems to be broken to me, but we have +// to live with this by checking that the character is a 7 bit one - even if +// this may fail to detect some spaces (I don't know if Unicode doesn't have +// space-like symbols somewhere except in the first 128 chars), it is arguably +// still better than trimming away accented letters +inline int wxSafeIsspace(wxChar ch) { return (ch < 127) && wxIsspace(ch); } + +// trims spaces (in the sense of isspace) from left or right side +wxString& wxString::Trim(bool bFromRight) +{ + // first check if we're going to modify the string at all + if ( !empty() && + ( + (bFromRight && wxSafeIsspace(GetChar(length() - 1))) || + (!bFromRight && wxSafeIsspace(GetChar(0u))) + ) + ) + { + if ( bFromRight ) + { + // find last non-space character + reverse_iterator psz = rbegin(); + while ( (psz != rend()) && wxSafeIsspace(*psz) ) + psz++; + + // truncate at trailing space start + erase(psz.base(), end()); + } + else + { + // find first non-space character + iterator psz = begin(); + while ( (psz != end()) && wxSafeIsspace(*psz) ) + psz++; + + // fix up data and length + erase(begin(), psz); + } + } + + return *this; +} + +// adds nCount characters chPad to the string from either side +wxString& wxString::Pad(size_t nCount, wxChar chPad, bool bFromRight) +{ + wxString s(chPad, nCount); + + if ( bFromRight ) + *this += s; + else + { + s += *this; + swap(s); + } + + return *this; +} + +// truncate the string +wxString& wxString::Truncate(size_t uiLen) +{ + if ( uiLen < length() ) + { + erase(begin() + uiLen, end()); + } + //else: nothing to do, string is already short enough + + return *this; +} + +// --------------------------------------------------------------------------- +// finding (return wxNOT_FOUND if not found and index otherwise) +// --------------------------------------------------------------------------- + +// find a character +int wxString::Find(wxChar ch, bool bFromEnd) const +{ + size_type idx = bFromEnd ? find_last_of(ch) : find_first_of(ch); + + return (idx == npos) ? wxNOT_FOUND : (int)idx; +} + +// find a sub-string (like strstr) +int wxString::Find(const wxChar *pszSub) const +{ + size_type idx = find(pszSub); + + return (idx == npos) ? wxNOT_FOUND : (int)idx; +} + +// ---------------------------------------------------------------------------- +// conversion to numbers +// ---------------------------------------------------------------------------- + +// the implementation of all the functions below is exactly the same so factor +// it out + +template +bool wxStringToIntType(const wxChar *start, + T *val, + int base, + F func) +{ + wxCHECK_MSG( val, false, _T("NULL output pointer") ); + wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); + +#ifndef __WXWINCE__ + errno = 0; +#endif + + wxChar *end; + *val = (*func)(start, &end, base); + + // return true only if scan was stopped by the terminating NUL and if the + // string was not empty to start with and no under/overflow occurred + return !*end && (end != start) +#ifndef __WXWINCE__ + && (errno != ERANGE) +#endif + ; +} + +bool wxString::ToLong(long *val, int base) const +{ + return wxStringToIntType(c_str(), val, base, wxStrtol); +} + +bool wxString::ToULong(unsigned long *val, int base) const +{ + return wxStringToIntType(c_str(), val, base, wxStrtoul); +} + +bool wxString::ToLongLong(wxLongLong_t *val, int base) const +{ +#ifdef wxHAS_STRTOLL + return wxStringToIntType(c_str(), val, base, wxStrtoll); +#else + // TODO: implement this ourselves + wxUnusedVar(val); + wxUnusedVar(base); + return false; +#endif // wxHAS_STRTOLL +} + +bool wxString::ToULongLong(wxULongLong_t *val, int base) const +{ +#ifdef wxHAS_STRTOLL + return wxStringToIntType(c_str(), val, base, wxStrtoull); +#else + // TODO: implement this ourselves + wxUnusedVar(val); + wxUnusedVar(base); + return false; +#endif +} + +bool wxString::ToDouble(double *val) const +{ + wxCHECK_MSG( val, false, _T("NULL pointer in wxString::ToDouble") ); + +#ifndef __WXWINCE__ + errno = 0; +#endif + + const wxChar *start = c_str(); + wxChar *end; + *val = wxStrtod(start, &end); + + // return true only if scan was stopped by the terminating NUL and if the + // string was not empty to start with and no under/overflow occurred + return !*end && (end != start) +#ifndef __WXWINCE__ + && (errno != ERANGE) +#endif + ; +} + +// --------------------------------------------------------------------------- +// formatted output +// --------------------------------------------------------------------------- + +/* static */ +wxString wxString::Format(const wxChar *pszFormat, ...) +{ + va_list argptr; + va_start(argptr, pszFormat); + + wxString s; + s.PrintfV(pszFormat, argptr); + + va_end(argptr); + + return s; +} + +/* static */ +wxString wxString::FormatV(const wxChar *pszFormat, va_list argptr) +{ + wxString s; + s.PrintfV(pszFormat, argptr); + return s; +} + +int wxString::Printf(const wxChar *pszFormat, ...) +{ + va_list argptr; + va_start(argptr, pszFormat); + + int iLen = PrintfV(pszFormat, argptr); + + va_end(argptr); + + return iLen; +} + +/* + Uses wxVsnprintf and places the result into the this string. + + In ANSI build, wxVsnprintf is effectively vsnprintf but in Unicode build + it is vswprintf. Due to a discrepancy between vsnprintf and vswprintf in + the ISO C99 (and thus SUSv3) standard the return value for the case of + an undersized buffer is inconsistent. For conforming vsnprintf + implementations the function must return the number of characters that + would have been printed had the buffer been large enough. For conforming + vswprintf implementations the function must return a negative number + and set errno. + + What vswprintf sets errno to is undefined but Darwin seems to set it to + EOVERFLOW. The only expected errno are EILSEQ and EINVAL. Both of + those are defined in the standard and backed up by several conformance + statements. Note that ENOMEM mentioned in the manual page does not + apply to swprintf, only wprintf and fwprintf. + + Official manual page: + http://www.opengroup.org/onlinepubs/009695399/functions/swprintf.html + + Some conformance statements (AIX, Solaris): + http://www.opengroup.org/csq/view.mhtml?RID=ibm%2FSD1%2F3 + http://www.theopengroup.org/csq/view.mhtml?norationale=1&noreferences=1&RID=Fujitsu%2FSE2%2F10 + + Since EILSEQ and EINVAL are rather common but EOVERFLOW is not and since + EILSEQ and EINVAL are specifically defined to mean the error is other than + an undersized buffer and no other errno are defined we treat those two + as meaning hard errors and everything else gets the old behavior which + is to keep looping and increasing buffer size until the function succeeds. + + In practice it's impossible to determine before compilation which behavior + may be used. The vswprintf function may have vsnprintf-like behavior or + vice-versa. Behavior detected on one release can theoretically change + with an updated release. Not to mention that configure testing for it + would require the test to be run on the host system, not the build system + which makes cross compilation difficult. Therefore, we make no assumptions + about behavior and try our best to handle every known case, including the + case where wxVsnprintf returns a negative number and fails to set errno. + + There is yet one more non-standard implementation and that is our own. + Fortunately, that can be detected at compile-time. + + On top of all that, ISO C99 explicitly defines snprintf to write a null + character to the last position of the specified buffer. That would be at + at the given buffer size minus 1. It is supposed to do this even if it + turns out that the buffer is sized too small. + + Darwin (tested on 10.5) follows the C99 behavior exactly. + + Glibc 2.6 almost follows the C99 behavior except vswprintf never sets + errno even when it fails. However, it only seems to ever fail due + to an undersized buffer. +*/ +int wxString::PrintfV(const wxChar* pszFormat, va_list argptr) +{ + int size = 1024; + + for ( ;; ) + { + // Allocate 1 more character than we tell wxVsnprintf about + // just in case it is buggy. + // FIXME: I have a feeling that the underlying function was not buggy + // and I suspect it was to fix the buf[size] = '\0' line below + wxStringBuffer tmp(*this, size + 1); + wxChar *buf = tmp; + + if ( !buf ) + { + // out of memory + return -1; + } + + // wxVsnprintf() may modify the original arg pointer, so pass it + // only a copy + va_list argptrcopy; + wxVaCopy(argptrcopy, argptr); + +#ifndef __WXWINCE__ + // Set errno to 0 to make it determinate if wxVsnprintf fails to set it. + errno = 0; +#endif + int len = wxVsnprintf(buf, size, pszFormat, argptrcopy); + va_end(argptrcopy); + + // some implementations of vsnprintf() don't NUL terminate + // the string if there is not enough space for it so + // always do it manually + // FIXME: This really seems to be the wrong and would be an off-by-one + // bug except the code above allocates an extra character. + buf[size] = _T('\0'); + + // vsnprintf() may return either -1 (traditional Unix behaviour) or the + // total number of characters which would have been written if the + // buffer were large enough (newer standards such as Unix98) + if ( len < 0 ) + { +#if wxUSE_WXVSNPRINTF + // we know that our own implementation of wxVsnprintf() returns -1 + // only for a format error - thus there's something wrong with + // the user's format string + return -1; +#else // assume that system version only returns error if not enough space +#if !defined(__WXWINCE__) && (!defined(__OS2__) || defined(__INNOTEK_LIBC__)) + if( (errno == EILSEQ) || (errno == EINVAL) ) + // If errno was set to one of the two well-known hard errors + // then fail immediately to avoid an infinite loop. + return -1; + else +#endif // __WXWINCE__ + // still not enough, as we don't know how much we need, double the + // current size of the buffer + size *= 2; +#endif // wxUSE_WXVSNPRINTF/!wxUSE_WXVSNPRINTF + } + else if ( len >= size ) + { +#if wxUSE_WXVSNPRINTF + // we know that our own implementation of wxVsnprintf() returns + // size+1 when there's not enough space but that's not the size + // of the required buffer! + size *= 2; // so we just double the current size of the buffer +#else + // some vsnprintf() implementations NUL-terminate the buffer and + // some don't in len == size case, to be safe always add 1 + // FIXME: I don't quite understand this comment. The vsnprintf + // function is specifically defined to return the number of + // characters printed not including the null terminator. + // So OF COURSE you need to add 1 to get the right buffer size. + // The following line is definitely correct, no question. + size = len + 1; +#endif + } + else // ok, there was enough space + { + break; + } + } + + // we could have overshot + Shrink(); + + return length(); +} + +// ---------------------------------------------------------------------------- +// misc other operations +// ---------------------------------------------------------------------------- + +// returns true if the string matches the pattern which may contain '*' and +// '?' metacharacters (as usual, '?' matches any character and '*' any number +// of them) +bool wxString::Matches(const wxChar *pszMask) const +{ + // I disable this code as it doesn't seem to be faster (in fact, it seems + // to be much slower) than the old, hand-written code below and using it + // here requires always linking with libregex even if the user code doesn't + // use it +#if 0 // wxUSE_REGEX + // first translate the shell-like mask into a regex + wxString pattern; + pattern.reserve(wxStrlen(pszMask)); + + pattern += _T('^'); + while ( *pszMask ) + { + switch ( *pszMask ) + { + case _T('?'): + pattern += _T('.'); + break; + + case _T('*'): + pattern += _T(".*"); + break; + + case _T('^'): + case _T('.'): + case _T('$'): + case _T('('): + case _T(')'): + case _T('|'): + case _T('+'): + case _T('\\'): + // these characters are special in a RE, quote them + // (however note that we don't quote '[' and ']' to allow + // using them for Unix shell like matching) + pattern += _T('\\'); + // fall through + + default: + pattern += *pszMask; + } + + pszMask++; + } + pattern += _T('$'); + + // and now use it + return wxRegEx(pattern, wxRE_NOSUB | wxRE_EXTENDED).Matches(c_str()); +#else // !wxUSE_REGEX + // TODO: this is, of course, awfully inefficient... + + // the char currently being checked + const wxChar *pszTxt = c_str(); + + // the last location where '*' matched + const wxChar *pszLastStarInText = NULL; + const wxChar *pszLastStarInMask = NULL; + +match: + for ( ; *pszMask != wxT('\0'); pszMask++, pszTxt++ ) { + switch ( *pszMask ) { + case wxT('?'): + if ( *pszTxt == wxT('\0') ) + return false; + + // pszTxt and pszMask will be incremented in the loop statement + + break; + + case wxT('*'): + { + // remember where we started to be able to backtrack later + pszLastStarInText = pszTxt; + pszLastStarInMask = pszMask; + + // ignore special chars immediately following this one + // (should this be an error?) + while ( *pszMask == wxT('*') || *pszMask == wxT('?') ) + pszMask++; + + // if there is nothing more, match + if ( *pszMask == wxT('\0') ) + return true; + + // are there any other metacharacters in the mask? + size_t uiLenMask; + const wxChar *pEndMask = wxStrpbrk(pszMask, wxT("*?")); + + if ( pEndMask != NULL ) { + // we have to match the string between two metachars + uiLenMask = pEndMask - pszMask; + } + else { + // we have to match the remainder of the string + uiLenMask = wxStrlen(pszMask); + } + + wxString strToMatch(pszMask, uiLenMask); + const wxChar* pMatch = wxStrstr(pszTxt, strToMatch); + if ( pMatch == NULL ) + return false; + + // -1 to compensate "++" in the loop + pszTxt = pMatch + uiLenMask - 1; + pszMask += uiLenMask - 1; + } + break; + + default: + if ( *pszMask != *pszTxt ) + return false; + break; + } + } + + // match only if nothing left + if ( *pszTxt == wxT('\0') ) + return true; + + // if we failed to match, backtrack if we can + if ( pszLastStarInText ) { + pszTxt = pszLastStarInText + 1; + pszMask = pszLastStarInMask; + + pszLastStarInText = NULL; + + // don't bother resetting pszLastStarInMask, it's unnecessary + + goto match; + } + + return false; +#endif // wxUSE_REGEX/!wxUSE_REGEX +} + +// Count the number of chars +int wxString::Freq(wxChar ch) const +{ + int count = 0; + int len = length(); + for (int i = 0; i < len; i++) + { + if (GetChar(i) == ch) + count ++; + } + return count; +} + +// convert to upper case, return the copy of the string +wxString wxString::Upper() const +{ wxString s(*this); return s.MakeUpper(); } + +// convert to lower case, return the copy of the string +wxString wxString::Lower() const { wxString s(*this); return s.MakeLower(); } + +int wxString::sprintf(const wxChar *pszFormat, ...) + { + va_list argptr; + va_start(argptr, pszFormat); + int iLen = PrintfV(pszFormat, argptr); + va_end(argptr); + return iLen; + } + +// ============================================================================ +// ArrayString +// ============================================================================ + +#include "wx/arrstr.h" + +wxArrayString::wxArrayString(size_t sz, const wxChar** a) +{ +#if !wxUSE_STL + Init(false); +#endif + for (size_t i=0; i < sz; i++) + Add(a[i]); +} + +wxArrayString::wxArrayString(size_t sz, const wxString* a) +{ +#if !wxUSE_STL + Init(false); +#endif + for (size_t i=0; i < sz; i++) + Add(a[i]); +} + +#if !wxUSE_STL + +// size increment = min(50% of current size, ARRAY_MAXSIZE_INCREMENT) +#define ARRAY_MAXSIZE_INCREMENT 4096 + +#ifndef ARRAY_DEFAULT_INITIAL_SIZE // also defined in dynarray.h +#define ARRAY_DEFAULT_INITIAL_SIZE (16) +#endif + +#define STRING(p) ((wxString *)(&(p))) + +// ctor +void wxArrayString::Init(bool autoSort) +{ + m_nSize = + m_nCount = 0; + m_pItems = (wxChar **) NULL; + m_autoSort = autoSort; +} + +// copy ctor +wxArrayString::wxArrayString(const wxArrayString& src) +{ + Init(src.m_autoSort); + + *this = src; +} + +// assignment operator +wxArrayString& wxArrayString::operator=(const wxArrayString& src) +{ + if ( m_nSize > 0 ) + Clear(); + + Copy(src); + + m_autoSort = src.m_autoSort; + + return *this; +} + +void wxArrayString::Copy(const wxArrayString& src) +{ + if ( src.m_nCount > ARRAY_DEFAULT_INITIAL_SIZE ) + Alloc(src.m_nCount); + + for ( size_t n = 0; n < src.m_nCount; n++ ) + Add(src[n]); +} + +// grow the array +void wxArrayString::Grow(size_t nIncrement) +{ + // only do it if no more place + if ( (m_nSize - m_nCount) < nIncrement ) { + // if ARRAY_DEFAULT_INITIAL_SIZE were set to 0, the initially empty would + // be never resized! + #if ARRAY_DEFAULT_INITIAL_SIZE == 0 + #error "ARRAY_DEFAULT_INITIAL_SIZE must be > 0!" + #endif + + if ( m_nSize == 0 ) { + // was empty, alloc some memory + m_nSize = ARRAY_DEFAULT_INITIAL_SIZE; + if (m_nSize < nIncrement) + m_nSize = nIncrement; + m_pItems = new wxChar *[m_nSize]; + } + else { + // otherwise when it's called for the first time, nIncrement would be 0 + // and the array would never be expanded + // add 50% but not too much + size_t ndefIncrement = m_nSize < ARRAY_DEFAULT_INITIAL_SIZE + ? ARRAY_DEFAULT_INITIAL_SIZE : m_nSize >> 1; + if ( ndefIncrement > ARRAY_MAXSIZE_INCREMENT ) + ndefIncrement = ARRAY_MAXSIZE_INCREMENT; + if ( nIncrement < ndefIncrement ) + nIncrement = ndefIncrement; + m_nSize += nIncrement; + wxChar **pNew = new wxChar *[m_nSize]; + + // copy data to new location + memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *)); + + // delete old memory (but do not release the strings!) + wxDELETEA(m_pItems); + + m_pItems = pNew; + } + } +} + +void wxArrayString::Free() +{ + for ( size_t n = 0; n < m_nCount; n++ ) { + STRING(m_pItems[n])->GetStringData()->Unlock(); + } +} + +// deletes all the strings from the list +void wxArrayString::Empty() +{ + Free(); + + m_nCount = 0; +} + +// as Empty, but also frees memory +void wxArrayString::Clear() +{ + Free(); + + m_nSize = + m_nCount = 0; + + wxDELETEA(m_pItems); +} + +// dtor +wxArrayString::~wxArrayString() +{ + Free(); + + wxDELETEA(m_pItems); +} + +void wxArrayString::reserve(size_t nSize) +{ + Alloc(nSize); +} + +// pre-allocates memory (frees the previous data!) +void wxArrayString::Alloc(size_t nSize) +{ + // only if old buffer was not big enough + if ( nSize > m_nSize ) { + wxChar **pNew = new wxChar *[nSize]; + if ( !pNew ) + return; + + memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *)); + delete [] m_pItems; + + m_pItems = pNew; + m_nSize = nSize; + } +} + +// minimizes the memory usage by freeing unused memory +void wxArrayString::Shrink() +{ + // only do it if we have some memory to free + if( m_nCount < m_nSize ) { + // allocates exactly as much memory as we need + wxChar **pNew = new wxChar *[m_nCount]; + + // copy data to new location + memcpy(pNew, m_pItems, m_nCount*sizeof(wxChar *)); + delete [] m_pItems; + m_pItems = pNew; + m_nSize = m_nCount; + } +} + +#if WXWIN_COMPATIBILITY_2_4 + +// return a wxString[] as required for some control ctors. +wxString* wxArrayString::GetStringArray() const +{ + wxString *array = 0; + + if( m_nCount > 0 ) + { + array = new wxString[m_nCount]; + for( size_t i = 0; i < m_nCount; i++ ) + array[i] = m_pItems[i]; + } + + return array; +} + +void wxArrayString::Remove(size_t nIndex, size_t nRemove) +{ + RemoveAt(nIndex, nRemove); +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +// searches the array for an item (forward or backwards) +int wxArrayString::Index(const wxChar *sz, bool bCase, bool bFromEnd) const +{ + if ( m_autoSort ) { + // use binary search in the sorted array + wxASSERT_MSG( bCase && !bFromEnd, + wxT("search parameters ignored for auto sorted array") ); + + size_t i, + lo = 0, + hi = m_nCount; + int res; + while ( lo < hi ) { + i = (lo + hi)/2; + + res = wxStrcmp(sz, m_pItems[i]); + if ( res < 0 ) + hi = i; + else if ( res > 0 ) + lo = i + 1; + else + return i; + } + + return wxNOT_FOUND; + } + else { + // use linear search in unsorted array + if ( bFromEnd ) { + if ( m_nCount > 0 ) { + size_t ui = m_nCount; + do { + if ( STRING(m_pItems[--ui])->IsSameAs(sz, bCase) ) + return ui; + } + while ( ui != 0 ); + } + } + else { + for( size_t ui = 0; ui < m_nCount; ui++ ) { + if( STRING(m_pItems[ui])->IsSameAs(sz, bCase) ) + return ui; + } + } + } + + return wxNOT_FOUND; +} + +// add item at the end +size_t wxArrayString::Add(const wxString& str, size_t nInsert) +{ + if ( m_autoSort ) { + // insert the string at the correct position to keep the array sorted + size_t i, + lo = 0, + hi = m_nCount; + int res; + while ( lo < hi ) { + i = (lo + hi)/2; + + res = str.Cmp(m_pItems[i]); + if ( res < 0 ) + hi = i; + else if ( res > 0 ) + lo = i + 1; + else { + lo = hi = i; + break; + } + } + + wxASSERT_MSG( lo == hi, wxT("binary search broken") ); + + Insert(str, lo, nInsert); + + return (size_t)lo; + } + else { + wxASSERT( str.GetStringData()->IsValid() ); + + Grow(nInsert); + + for (size_t i = 0; i < nInsert; i++) + { + // the string data must not be deleted! + str.GetStringData()->Lock(); + + // just append + m_pItems[m_nCount + i] = (wxChar *)str.c_str(); // const_cast + } + size_t ret = m_nCount; + m_nCount += nInsert; + return ret; + } +} + +// add item at the given position +void wxArrayString::Insert(const wxString& str, size_t nIndex, size_t nInsert) +{ + wxASSERT( str.GetStringData()->IsValid() ); + + wxCHECK_RET( nIndex <= m_nCount, wxT("bad index in wxArrayString::Insert") ); + wxCHECK_RET( m_nCount <= m_nCount + nInsert, + wxT("array size overflow in wxArrayString::Insert") ); + + Grow(nInsert); + + memmove(&m_pItems[nIndex + nInsert], &m_pItems[nIndex], + (m_nCount - nIndex)*sizeof(wxChar *)); + + for (size_t i = 0; i < nInsert; i++) + { + str.GetStringData()->Lock(); + m_pItems[nIndex + i] = (wxChar *)str.c_str(); + } + m_nCount += nInsert; +} + +// range insert (STL 23.2.4.3) +void +wxArrayString::insert(iterator it, const_iterator first, const_iterator last) +{ + const int idx = it - begin(); + + // grow it once + Grow(last - first); + + // reset "it" since it can change inside Grow() + it = begin() + idx; + + while ( first != last ) + { + it = insert(it, *first); + + // insert returns an iterator to the last element inserted but we need + // insert the next after this one, that is before the next one + ++it; + + ++first; + } +} + +// expand the array +void wxArrayString::SetCount(size_t count) +{ + Alloc(count); + + wxString s; + while ( m_nCount < count ) + m_pItems[m_nCount++] = (wxChar *)s.c_str(); +} + +// removes item from array (by index) +void wxArrayString::RemoveAt(size_t nIndex, size_t nRemove) +{ + wxCHECK_RET( nIndex < m_nCount, wxT("bad index in wxArrayString::Remove") ); + wxCHECK_RET( nIndex + nRemove <= m_nCount, + wxT("removing too many elements in wxArrayString::Remove") ); + + // release our lock + for (size_t i = 0; i < nRemove; i++) + Item(nIndex + i).GetStringData()->Unlock(); + + memmove(&m_pItems[nIndex], &m_pItems[nIndex + nRemove], + (m_nCount - nIndex - nRemove)*sizeof(wxChar *)); + m_nCount -= nRemove; +} + +// removes item from array (by value) +void wxArrayString::Remove(const wxChar *sz) +{ + int iIndex = Index(sz); + + wxCHECK_RET( iIndex != wxNOT_FOUND, + wxT("removing inexistent element in wxArrayString::Remove") ); + + RemoveAt(iIndex); +} + +void wxArrayString::assign(const_iterator first, const_iterator last) +{ + reserve(last - first); + for(; first != last; ++first) + push_back(*first); +} + +// ---------------------------------------------------------------------------- +// sorting +// ---------------------------------------------------------------------------- + +// we can only sort one array at a time with the quick-sort based +// implementation +#if wxUSE_THREADS + // need a critical section to protect access to gs_compareFunction and + // gs_sortAscending variables + static wxCriticalSection gs_critsectStringSort; +#endif // wxUSE_THREADS + +// function to use for string comparaison +static wxArrayString::CompareFunction gs_compareFunction = NULL; + +// if we don't use the compare function, this flag tells us if we sort the +// array in ascending or descending order +static bool gs_sortAscending = true; + +// function which is called by quick sort +extern "C" int wxC_CALLING_CONV // LINKAGEMODE +wxStringCompareFunction(const void *first, const void *second) +{ + wxString *strFirst = (wxString *)first; + wxString *strSecond = (wxString *)second; + + if ( gs_compareFunction ) { + return gs_compareFunction(*strFirst, *strSecond); + } + else { + // maybe we should use wxStrcoll + int result = strFirst->Cmp(*strSecond); + + return gs_sortAscending ? result : -result; + } +} + +// sort array elements using passed comparaison function +void wxArrayString::Sort(CompareFunction compareFunction) +{ + wxCRIT_SECT_LOCKER(lockCmpFunc, gs_critsectStringSort); + + wxASSERT( !gs_compareFunction ); // must have been reset to NULL + gs_compareFunction = compareFunction; + + DoSort(); + + // reset it to NULL so that Sort(bool) will work the next time + gs_compareFunction = NULL; +} + +extern "C" +{ + typedef int (wxC_CALLING_CONV * wxStringCompareFn)(const void *first, + const void *second); +} + +void wxArrayString::Sort(CompareFunction2 compareFunction) +{ + qsort(m_pItems, m_nCount, sizeof(wxChar *), (wxStringCompareFn)compareFunction); +} + +void wxArrayString::Sort(bool reverseOrder) +{ + Sort(reverseOrder ? wxStringSortDescending : wxStringSortAscending); +} + +void wxArrayString::DoSort() +{ + wxCHECK_RET( !m_autoSort, wxT("can't use this method with sorted arrays") ); + + // just sort the pointers using qsort() - of course it only works because + // wxString() *is* a pointer to its data + qsort(m_pItems, m_nCount, sizeof(wxChar *), wxStringCompareFunction); +} + +bool wxArrayString::operator==(const wxArrayString& a) const +{ + if ( m_nCount != a.m_nCount ) + return false; + + for ( size_t n = 0; n < m_nCount; n++ ) + { + if ( Item(n) != a[n] ) + return false; + } + + return true; +} + +#endif // !wxUSE_STL + +int wxCMPFUNC_CONV wxStringSortAscending(wxString* s1, wxString* s2) +{ + return s1->Cmp(*s2); +} + +int wxCMPFUNC_CONV wxStringSortDescending(wxString* s1, wxString* s2) +{ + return -s1->Cmp(*s2); +} + +wxString* wxCArrayString::Release() +{ + wxString *r = GetStrings(); + m_strings = NULL; + return r; +} diff --git a/Source/3rd Party/wx/src/common/sysopt.cpp b/Source/3rd Party/wx/src/common/sysopt.cpp index 93a503966..7a61ad01b 100644 --- a/Source/3rd Party/wx/src/common/sysopt.cpp +++ b/Source/3rd Party/wx/src/common/sysopt.cpp @@ -1,111 +1,111 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/sysopt.cpp -// Purpose: wxSystemOptions -// Author: Julian Smart -// Modified by: -// Created: 2001-07-10 -// RCS-ID: $Id: sysopt.cpp 39851 2006-06-27 14:33:14Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#if defined(__BORLANDC__) - #pragma hdrstop -#endif - -#if wxUSE_SYSTEM_OPTIONS - -#include "wx/sysopt.h" - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/list.h" - #include "wx/string.h" - #include "wx/arrstr.h" -#endif - -// ---------------------------------------------------------------------------- -// private globals -// ---------------------------------------------------------------------------- - -static wxArrayString gs_optionNames, - gs_optionValues; - -// ============================================================================ -// wxSystemOptions implementation -// ============================================================================ - -// Option functions (arbitrary name/value mapping) -void wxSystemOptions::SetOption(const wxString& name, const wxString& value) -{ - int idx = gs_optionNames.Index(name, false); - if (idx == wxNOT_FOUND) - { - gs_optionNames.Add(name); - gs_optionValues.Add(value); - } - else - { - gs_optionNames[idx] = name; - gs_optionValues[idx] = value; - } -} - -void wxSystemOptions::SetOption(const wxString& name, int value) -{ - SetOption(name, wxString::Format(wxT("%d"), value)); -} - -wxString wxSystemOptions::GetOption(const wxString& name) -{ - wxString val; - - int idx = gs_optionNames.Index(name, false); - if ( idx != wxNOT_FOUND ) - { - val = gs_optionValues[idx]; - } - else // not set explicitely - { - // look in the environment: first for a variable named "wx_appname_name" - // which can be set to affect the behaviour or just this application - // and then for "wx_name" which can be set to change the option globally - wxString var(name); - var.Replace(_T("."), _T("_")); // '.'s not allowed in env var names - - wxString appname; - if ( wxTheApp ) - appname = wxTheApp->GetAppName(); - - if ( !appname.empty() ) - val = wxGetenv(_T("wx_") + appname + _T('_') + var); - - if ( val.empty() ) - val = wxGetenv(_T("wx_") + var); - } - - return val; -} - -int wxSystemOptions::GetOptionInt(const wxString& name) -{ - return wxAtoi(GetOption(name)); -} - -bool wxSystemOptions::HasOption(const wxString& name) -{ - return !GetOption(name).empty(); -} - -#endif // wxUSE_SYSTEM_OPTIONS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/sysopt.cpp +// Purpose: wxSystemOptions +// Author: Julian Smart +// Modified by: +// Created: 2001-07-10 +// RCS-ID: $Id: sysopt.cpp 39851 2006-06-27 14:33:14Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#if defined(__BORLANDC__) + #pragma hdrstop +#endif + +#if wxUSE_SYSTEM_OPTIONS + +#include "wx/sysopt.h" + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/list.h" + #include "wx/string.h" + #include "wx/arrstr.h" +#endif + +// ---------------------------------------------------------------------------- +// private globals +// ---------------------------------------------------------------------------- + +static wxArrayString gs_optionNames, + gs_optionValues; + +// ============================================================================ +// wxSystemOptions implementation +// ============================================================================ + +// Option functions (arbitrary name/value mapping) +void wxSystemOptions::SetOption(const wxString& name, const wxString& value) +{ + int idx = gs_optionNames.Index(name, false); + if (idx == wxNOT_FOUND) + { + gs_optionNames.Add(name); + gs_optionValues.Add(value); + } + else + { + gs_optionNames[idx] = name; + gs_optionValues[idx] = value; + } +} + +void wxSystemOptions::SetOption(const wxString& name, int value) +{ + SetOption(name, wxString::Format(wxT("%d"), value)); +} + +wxString wxSystemOptions::GetOption(const wxString& name) +{ + wxString val; + + int idx = gs_optionNames.Index(name, false); + if ( idx != wxNOT_FOUND ) + { + val = gs_optionValues[idx]; + } + else // not set explicitely + { + // look in the environment: first for a variable named "wx_appname_name" + // which can be set to affect the behaviour or just this application + // and then for "wx_name" which can be set to change the option globally + wxString var(name); + var.Replace(_T("."), _T("_")); // '.'s not allowed in env var names + + wxString appname; + if ( wxTheApp ) + appname = wxTheApp->GetAppName(); + + if ( !appname.empty() ) + val = wxGetenv(_T("wx_") + appname + _T('_') + var); + + if ( val.empty() ) + val = wxGetenv(_T("wx_") + var); + } + + return val; +} + +int wxSystemOptions::GetOptionInt(const wxString& name) +{ + return wxAtoi(GetOption(name)); +} + +bool wxSystemOptions::HasOption(const wxString& name) +{ + return !GetOption(name).empty(); +} + +#endif // wxUSE_SYSTEM_OPTIONS diff --git a/Source/3rd Party/wx/src/common/tarstrm.cpp b/Source/3rd Party/wx/src/common/tarstrm.cpp index a92687bb7..5315a996c 100644 --- a/Source/3rd Party/wx/src/common/tarstrm.cpp +++ b/Source/3rd Party/wx/src/common/tarstrm.cpp @@ -1,1534 +1,1534 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: tarstrm.cpp -// Purpose: Streams for Tar files -// Author: Mike Wetherell -// RCS-ID: $Id: tarstrm.cpp 63302 2010-01-28 21:46:09Z MW $ -// Copyright: (c) 2004 Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_TARSTREAM - -#include "wx/tarstrm.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" -#endif - -#include "wx/buffer.h" -#include "wx/datetime.h" -#include "wx/ptr_scpd.h" -#include "wx/filename.h" -#include "wx/thread.h" - -#include - -#ifdef __UNIX__ -#include -#include -#endif - - -///////////////////////////////////////////////////////////////////////////// -// constants - -enum { - TAR_NAME, - TAR_MODE, - TAR_UID, - TAR_GID, - TAR_SIZE, - TAR_MTIME, - TAR_CHKSUM, - TAR_TYPEFLAG, - TAR_LINKNAME, - TAR_MAGIC, - TAR_VERSION, - TAR_UNAME, - TAR_GNAME, - TAR_DEVMAJOR, - TAR_DEVMINOR, - TAR_PREFIX, - TAR_UNUSED, - TAR_NUMFIELDS -}; - -enum { - TAR_BLOCKSIZE = 512 -}; - -// checksum type -enum { - SUM_UNKNOWN, - SUM_UNSIGNED, - SUM_SIGNED -}; - -// type of input tar -enum { - TYPE_OLDTAR, // fields after TAR_LINKNAME are invalid - TYPE_GNUTAR, // all fields except TAR_PREFIX are valid - TYPE_USTAR // all fields are valid -}; - -// signatures -static const char *USTAR_MAGIC = "ustar"; -static const char *USTAR_VERSION = "00"; -static const char *GNU_MAGIC = "ustar "; -static const char *GNU_VERION = " "; - -IMPLEMENT_DYNAMIC_CLASS(wxTarEntry, wxArchiveEntry) -IMPLEMENT_DYNAMIC_CLASS(wxTarClassFactory, wxArchiveClassFactory) - - -///////////////////////////////////////////////////////////////////////////// -// Class factory - -static wxTarClassFactory g_wxTarClassFactory; - -wxTarClassFactory::wxTarClassFactory() -{ - if (this == &g_wxTarClassFactory) - PushFront(); -} - -const wxChar * const * -wxTarClassFactory::GetProtocols(wxStreamProtocolType type) const -{ - static const wxChar *protocols[] = { _T("tar"), NULL }; - static const wxChar *mimetypes[] = { _T("application/x-tar"), NULL }; - static const wxChar *fileexts[] = { _T(".tar"), NULL }; - static const wxChar *empty[] = { NULL }; - - switch (type) { - case wxSTREAM_PROTOCOL: return protocols; - case wxSTREAM_MIMETYPE: return mimetypes; - case wxSTREAM_FILEEXT: return fileexts; - default: return empty; - } -} - - -///////////////////////////////////////////////////////////////////////////// -// tar header block - -typedef wxFileOffset wxTarNumber; - -struct wxTarField { const wxChar *name; int pos; }; - -class wxTarHeaderBlock -{ -public: - wxTarHeaderBlock() - { memset(data, 0, sizeof(data)); } - wxTarHeaderBlock(const wxTarHeaderBlock& hb) - { memcpy(data, hb.data, sizeof(data)); } - - bool Read(wxInputStream& in); - bool Write(wxOutputStream& out); - inline bool WriteField(wxOutputStream& out, int id); - - bool IsAllZeros() const; - wxUint32 Sum(bool SignedSum = false); - wxUint32 SumField(int id); - - char *Get(int id) { return data + fields[id].pos + id; } - static size_t Len(int id) { return fields[id + 1].pos - fields[id].pos; } - static const wxChar *Name(int id) { return fields[id].name; } - static size_t Offset(int id) { return fields[id].pos; } - - bool SetOctal(int id, wxTarNumber n); - wxTarNumber GetOctal(int id); - bool SetPath(const wxString& name, wxMBConv& conv); - -private: - char data[TAR_BLOCKSIZE + TAR_NUMFIELDS]; - static const wxTarField fields[]; - static void check(); -}; - -wxDEFINE_SCOPED_PTR_TYPE(wxTarHeaderBlock) - -// A table giving the field names and offsets in a tar header block -const wxTarField wxTarHeaderBlock::fields[] = -{ - { _T("name"), 0 }, // 100 - { _T("mode"), 100 }, // 8 - { _T("uid"), 108 }, // 8 - { _T("gid"), 116 }, // 8 - { _T("size"), 124 }, // 12 - { _T("mtime"), 136 }, // 12 - { _T("chksum"), 148 }, // 8 - { _T("typeflag"), 156 }, // 1 - { _T("linkname"), 157 }, // 100 - { _T("magic"), 257 }, // 6 - { _T("version"), 263 }, // 2 - { _T("uname"), 265 }, // 32 - { _T("gname"), 297 }, // 32 - { _T("devmajor"), 329 }, // 8 - { _T("devminor"), 337 }, // 8 - { _T("prefix"), 345 }, // 155 - { _T("unused"), 500 }, // 12 - { NULL, TAR_BLOCKSIZE } -}; - -void wxTarHeaderBlock::check() -{ -#if 0 - wxCOMPILE_TIME_ASSERT( - WXSIZEOF(fields) == TAR_NUMFIELDS + 1, - Wrong_number_of_elements_in_fields_table - ); -#endif -} - -bool wxTarHeaderBlock::IsAllZeros() const -{ - const char *p = data; - for (size_t i = 0; i < sizeof(data); i++) - if (p[i]) - return false; - return true; -} - -wxUint32 wxTarHeaderBlock::Sum(bool SignedSum /*=false*/) -{ - // the chksum field itself should be blanks during the calculation - memset(Get(TAR_CHKSUM), ' ', Len(TAR_CHKSUM)); - const char *p = data; - wxUint32 n = 0; - - if (SignedSum) - for (size_t i = 0; i < sizeof(data); i++) - n += (signed char)p[i]; - else - for (size_t i = 0; i < sizeof(data); i++) - n += (unsigned char)p[i]; - - return n; -} - -wxUint32 wxTarHeaderBlock::SumField(int id) -{ - unsigned char *p = (unsigned char*)Get(id); - unsigned char *q = p + Len(id); - wxUint32 n = 0; - - while (p < q) - n += *p++; - - return n; -} - -bool wxTarHeaderBlock::Read(wxInputStream& in) -{ - bool ok = true; - - for (int id = 0; id < TAR_NUMFIELDS && ok; id++) - ok = in.Read(Get(id), Len(id)).LastRead() == Len(id); - - return ok; -} - -bool wxTarHeaderBlock::Write(wxOutputStream& out) -{ - bool ok = true; - - for (int id = 0; id < TAR_NUMFIELDS && ok; id++) - ok = WriteField(out, id); - - return ok; -} - -inline bool wxTarHeaderBlock::WriteField(wxOutputStream& out, int id) -{ - return out.Write(Get(id), Len(id)).LastWrite() == Len(id); -} - -wxTarNumber wxTarHeaderBlock::GetOctal(int id) -{ - wxTarNumber n = 0; - const char *p = Get(id); - while (*p == ' ') - p++; - while (*p >= '0' && *p < '8') - n = (n << 3) | (*p++ - '0'); - return n; -} - -bool wxTarHeaderBlock::SetOctal(int id, wxTarNumber n) -{ - // set an octal field, return true if the number fits - char *field = Get(id); - char *p = field + Len(id); - *--p = 0; - while (p > field) { - *--p = char('0' + (n & 7)); - n >>= 3; - } - return n == 0; -} - -bool wxTarHeaderBlock::SetPath(const wxString& name, wxMBConv& conv) -{ - bool badconv = false; - -#if wxUSE_UNICODE - wxCharBuffer nameBuf = name.mb_str(conv); - - // if the conversion fails make an approximation - if (!nameBuf) { - badconv = true; - size_t len = name.length(); - wxCharBuffer approx(len); - for (size_t i = 0; i < len; i++) - approx.data()[i] = name[i] & ~0x7F ? '_' : name[i]; - nameBuf = approx; - } - - const char *mbName = nameBuf; -#else - const char *mbName = name.c_str(); - (void)conv; -#endif - - bool fits; - bool notGoingToFit = false; - size_t len = strlen(mbName); - size_t maxname = Len(TAR_NAME); - size_t maxprefix = Len(TAR_PREFIX); - size_t i = 0; - size_t nexti = 0; - - for (;;) { - fits = i < maxprefix && len - i <= maxname; - - if (!fits) { - const char *p = strchr(mbName + i, '/'); - if (p) - nexti = p - mbName + 1; - if (!p || nexti - 1 > maxprefix) - notGoingToFit = true; - } - - if (fits || notGoingToFit) { - strncpy(Get(TAR_NAME), mbName + i, maxname); - if (i > 0) - strncpy(Get(TAR_PREFIX), mbName, i - 1); - break; - } - - i = nexti; - } - - return fits && !badconv; -} - - -///////////////////////////////////////////////////////////////////////////// -// Some helpers - -static wxFileOffset RoundUpSize(wxFileOffset size, int factor = 1) -{ - wxFileOffset chunk = TAR_BLOCKSIZE * factor; - return ((size + chunk - 1) / chunk) * chunk; -} - -#ifdef __UNIX__ - -static wxString wxTarUserName(int uid) -{ - struct passwd *ppw; - -#ifdef HAVE_GETPWUID_R -#if defined HAVE_SYSCONF && defined _SC_GETPW_R_SIZE_MAX - long pwsize = sysconf(_SC_GETPW_R_SIZE_MAX); - size_t bufsize(wxMin(wxMax(1024l, pwsize), 32768l)); -#else - size_t bufsize = 1024; -#endif - wxCharBuffer buf(bufsize); - struct passwd pw; - - memset(&pw, 0, sizeof(pw)); - if (getpwuid_r(uid, &pw, buf.data(), bufsize, &ppw) == 0 && pw.pw_name) - return wxString(pw.pw_name, wxConvLibc); -#else - if ((ppw = getpwuid(uid)) != NULL) - return wxString(ppw->pw_name, wxConvLibc); -#endif - return _("unknown"); -} - -static wxString wxTarGroupName(int gid) -{ - struct group *pgr; -#ifdef HAVE_GETGRGID_R -#if defined HAVE_SYSCONF && defined _SC_GETGR_R_SIZE_MAX - long grsize = sysconf(_SC_GETGR_R_SIZE_MAX); - size_t bufsize(wxMin(wxMax(1024l, grsize), 32768l)); -#else - size_t bufsize = 1024; -#endif - wxCharBuffer buf(bufsize); - struct group gr; - - memset(&gr, 0, sizeof(gr)); - if (getgrgid_r(gid, &gr, buf.data(), bufsize, &pgr) == 0 && gr.gr_name) - return wxString(gr.gr_name, wxConvLibc); -#else - if ((pgr = getgrgid(gid)) != NULL) - return wxString(pgr->gr_name, wxConvLibc); -#endif - return _("unknown"); -} - -#endif // __UNIX__ - -// Cache the user and group names since getting them can be expensive, -// get both names and ids at the same time. -// -struct wxTarUser -{ - wxTarUser(); - ~wxTarUser() { delete [] uname; delete [] gname; } - - int uid; - int gid; - - wxChar *uname; - wxChar *gname; -}; - -wxTarUser::wxTarUser() -{ -#ifdef __UNIX__ - uid = getuid(); - gid = getgid(); - wxString usr = wxTarUserName(uid); - wxString grp = wxTarGroupName(gid); -#else - uid = 0; - gid = 0; - wxString usr = wxGetUserId(); - wxString grp = _("unknown"); -#endif - - uname = new wxChar[usr.length() + 1]; - wxStrcpy(uname, usr.c_str()); - - gname = new wxChar[grp.length() + 1]; - wxStrcpy(gname, grp.c_str()); -} - -static const wxTarUser& wxGetTarUser() -{ -#if wxUSE_THREADS - static wxCriticalSection cs; - wxCriticalSectionLocker lock(cs); -#endif - static wxTarUser tu; - return tu; -} - -// ignore the size field for entry types 3, 4, 5 and 6 -// -static inline wxFileOffset GetDataSize(const wxTarEntry& entry) -{ - switch (entry.GetTypeFlag()) { - case wxTAR_CHRTYPE: - case wxTAR_BLKTYPE: - case wxTAR_DIRTYPE: - case wxTAR_FIFOTYPE: - return 0; - default: - return entry.GetSize(); - } -} - - -///////////////////////////////////////////////////////////////////////////// -// Tar Entry -// Holds all the meta-data for a file in the tar - -wxTarEntry::wxTarEntry(const wxString& name /*=wxEmptyString*/, - const wxDateTime& dt /*=wxDateTime::Now()*/, - wxFileOffset size /*=0*/) - : m_Mode(0644), - m_IsModeSet(false), - m_UserId(wxGetTarUser().uid), - m_GroupId(wxGetTarUser().gid), - m_Size(size), - m_Offset(wxInvalidOffset), - m_ModifyTime(dt), - m_TypeFlag(wxTAR_REGTYPE), - m_UserName(wxGetTarUser().uname), - m_GroupName(wxGetTarUser().gname), - m_DevMajor(~0), - m_DevMinor(~0) -{ - if (!name.empty()) - SetName(name); -} - -wxTarEntry::~wxTarEntry() -{ -} - -wxTarEntry::wxTarEntry(const wxTarEntry& e) - : wxArchiveEntry(), - m_Name(e.m_Name), - m_Mode(e.m_Mode), - m_IsModeSet(e.m_IsModeSet), - m_UserId(e.m_UserId), - m_GroupId(e.m_GroupId), - m_Size(e.m_Size), - m_Offset(e.m_Offset), - m_ModifyTime(e.m_ModifyTime), - m_AccessTime(e.m_AccessTime), - m_CreateTime(e.m_CreateTime), - m_TypeFlag(e.m_TypeFlag), - m_LinkName(e.m_LinkName), - m_UserName(e.m_UserName), - m_GroupName(e.m_GroupName), - m_DevMajor(e.m_DevMajor), - m_DevMinor(e.m_DevMinor) -{ -} - -wxTarEntry& wxTarEntry::operator=(const wxTarEntry& e) -{ - if (&e != this) { - m_Name = e.m_Name; - m_Mode = e.m_Mode; - m_IsModeSet = e.m_IsModeSet; - m_UserId = e.m_UserId; - m_GroupId = e.m_GroupId; - m_Size = e.m_Size; - m_Offset = e.m_Offset; - m_ModifyTime = e.m_ModifyTime; - m_AccessTime = e.m_AccessTime; - m_CreateTime = e.m_CreateTime; - m_TypeFlag = e.m_TypeFlag; - m_LinkName = e.m_LinkName; - m_UserName = e.m_UserName; - m_GroupName = e.m_GroupName; - m_DevMajor = e.m_DevMajor; - m_DevMinor = e.m_DevMinor; - } - return *this; -} - -wxString wxTarEntry::GetName(wxPathFormat format /*=wxPATH_NATIVE*/) const -{ - bool isDir = IsDir() && !m_Name.empty(); - - // optimisations for common (and easy) cases - switch (wxFileName::GetFormat(format)) { - case wxPATH_DOS: - { - wxString name(isDir ? m_Name + _T("\\") : m_Name); - for (size_t i = 0; i < name.length(); i++) - if (name[i] == _T('/')) - name[i] = _T('\\'); - return name; - } - - case wxPATH_UNIX: - return isDir ? m_Name + _T("/") : m_Name; - - default: - ; - } - - wxFileName fn; - - if (isDir) - fn.AssignDir(m_Name, wxPATH_UNIX); - else - fn.Assign(m_Name, wxPATH_UNIX); - - return fn.GetFullPath(format); -} - -void wxTarEntry::SetName(const wxString& name, wxPathFormat format) -{ - bool isDir; - m_Name = GetInternalName(name, format, &isDir); - SetIsDir(isDir); -} - -// Static - Internally tars and zips use forward slashes for the path -// separator, absolute paths aren't allowed, and directory names have a -// trailing slash. This function converts a path into this internal format, -// but without a trailing slash for a directory. -// -wxString wxTarEntry::GetInternalName(const wxString& name, - wxPathFormat format /*=wxPATH_NATIVE*/, - bool *pIsDir /*=NULL*/) -{ - wxString internal; - - if (wxFileName::GetFormat(format) != wxPATH_UNIX) - internal = wxFileName(name, format).GetFullPath(wxPATH_UNIX); - else - internal = name; - - bool isDir = !internal.empty() && internal.Last() == '/'; - if (pIsDir) - *pIsDir = isDir; - if (isDir) - internal.erase(internal.length() - 1); - - while (!internal.empty() && *internal.begin() == '/') - internal.erase(0, 1); - while (!internal.empty() && internal.compare(0, 2, _T("./")) == 0) - internal.erase(0, 2); - if (internal == _T(".") || internal == _T("..")) - internal = wxEmptyString; - - return internal; -} - -bool wxTarEntry::IsDir() const -{ - return m_TypeFlag == wxTAR_DIRTYPE; -} - -void wxTarEntry::SetIsDir(bool isDir) -{ - if (isDir) - m_TypeFlag = wxTAR_DIRTYPE; - else if (m_TypeFlag == wxTAR_DIRTYPE) - m_TypeFlag = wxTAR_REGTYPE; -} - -void wxTarEntry::SetIsReadOnly(bool isReadOnly) -{ - if (isReadOnly) - m_Mode &= ~0222; - else - m_Mode |= 0200; -} - -int wxTarEntry::GetMode() const -{ - if (m_IsModeSet || !IsDir()) - return m_Mode; - else - return m_Mode | 0111; - -} - -void wxTarEntry::SetMode(int mode) -{ - m_Mode = mode & 07777; - m_IsModeSet = true; -} - - -///////////////////////////////////////////////////////////////////////////// -// Input stream - -wxDECLARE_SCOPED_PTR(wxTarEntry, wxTarEntryPtr_) -wxDEFINE_SCOPED_PTR (wxTarEntry, wxTarEntryPtr_) - -wxTarInputStream::wxTarInputStream(wxInputStream& stream, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveInputStream(stream, conv) -{ - Init(); -} - -wxTarInputStream::wxTarInputStream(wxInputStream *stream, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveInputStream(stream, conv) -{ - Init(); -} - -void wxTarInputStream::Init() -{ - m_pos = wxInvalidOffset; - m_offset = 0; - m_size = wxInvalidOffset; - m_sumType = SUM_UNKNOWN; - m_tarType = TYPE_USTAR; - m_hdr = new wxTarHeaderBlock; - m_HeaderRecs = NULL; - m_GlobalHeaderRecs = NULL; - m_lasterror = m_parent_i_stream->GetLastError(); -} - -wxTarInputStream::~wxTarInputStream() -{ - delete m_hdr; - delete m_HeaderRecs; - delete m_GlobalHeaderRecs; -} - -wxTarEntry *wxTarInputStream::GetNextEntry() -{ - m_lasterror = ReadHeaders(); - - if (!IsOk()) - return NULL; - - wxTarEntryPtr_ entry(new wxTarEntry); - - entry->SetMode(GetHeaderNumber(TAR_MODE)); - entry->SetUserId(GetHeaderNumber(TAR_UID)); - entry->SetGroupId(GetHeaderNumber(TAR_UID)); - entry->SetSize(GetHeaderNumber(TAR_SIZE)); - - entry->SetOffset(m_offset); - - entry->SetDateTime(GetHeaderDate(_T("mtime"))); - entry->SetAccessTime(GetHeaderDate(_T("atime"))); - entry->SetCreateTime(GetHeaderDate(_T("ctime"))); - - entry->SetTypeFlag(*m_hdr->Get(TAR_TYPEFLAG)); - bool isDir = entry->IsDir(); - - entry->SetLinkName(GetHeaderString(TAR_LINKNAME)); - - if (m_tarType != TYPE_OLDTAR) { - entry->SetUserName(GetHeaderString(TAR_UNAME)); - entry->SetGroupName(GetHeaderString(TAR_GNAME)); - - entry->SetDevMajor(GetHeaderNumber(TAR_DEVMAJOR)); - entry->SetDevMinor(GetHeaderNumber(TAR_DEVMINOR)); - } - - entry->SetName(GetHeaderPath(), wxPATH_UNIX); - if (isDir) - entry->SetIsDir(); - - if (m_HeaderRecs) - m_HeaderRecs->clear(); - - m_size = GetDataSize(*entry); - m_pos = 0; - - return entry.release(); -} - -bool wxTarInputStream::OpenEntry(wxTarEntry& entry) -{ - wxFileOffset offset = entry.GetOffset(); - - if (GetLastError() != wxSTREAM_READ_ERROR - && m_parent_i_stream->IsSeekable() - && m_parent_i_stream->SeekI(offset) == offset) - { - m_offset = offset; - m_size = GetDataSize(entry); - m_pos = 0; - m_lasterror = wxSTREAM_NO_ERROR; - return true; - } else { - m_lasterror = wxSTREAM_READ_ERROR; - return false; - } -} - -bool wxTarInputStream::OpenEntry(wxArchiveEntry& entry) -{ - wxTarEntry *tarEntry = wxStaticCast(&entry, wxTarEntry); - return tarEntry ? OpenEntry(*tarEntry) : false; -} - -bool wxTarInputStream::CloseEntry() -{ - if (m_lasterror == wxSTREAM_READ_ERROR) - return false; - if (!IsOpened()) - return true; - - wxFileOffset size = RoundUpSize(m_size); - wxFileOffset remainder = size - m_pos; - - if (remainder && m_parent_i_stream->IsSeekable()) { - wxLogNull nolog; - if (m_parent_i_stream->SeekI(remainder, wxFromCurrent) - != wxInvalidOffset) - remainder = 0; - } - - if (remainder) { - const int BUFSIZE = 8192; - wxCharBuffer buf(BUFSIZE); - - while (remainder > 0 && m_parent_i_stream->IsOk()) - remainder -= m_parent_i_stream->Read( - buf.data(), wxMin(BUFSIZE, remainder)).LastRead(); - } - - m_pos = wxInvalidOffset; - m_offset += size; - m_lasterror = m_parent_i_stream->GetLastError(); - - return IsOk(); -} - -wxStreamError wxTarInputStream::ReadHeaders() -{ - if (!CloseEntry()) - return wxSTREAM_READ_ERROR; - - bool done = false; - - while (!done) { - m_hdr->Read(*m_parent_i_stream); - if (m_parent_i_stream->Eof()) - wxLogError(_("incomplete header block in tar")); - if (!*m_parent_i_stream) - return wxSTREAM_READ_ERROR; - m_offset += TAR_BLOCKSIZE; - - // an all-zero header marks the end of the tar - if (m_hdr->IsAllZeros()) - return wxSTREAM_EOF; - - // the checksum is supposed to be the unsigned sum of the header bytes, - // but there have been versions of tar that used the signed sum, so - // accept that too, but only if used throughout. - wxUint32 chksum = m_hdr->GetOctal(TAR_CHKSUM); - bool ok = false; - - if (m_sumType != SUM_SIGNED) { - ok = chksum == m_hdr->Sum(); - if (m_sumType == SUM_UNKNOWN) - m_sumType = ok ? SUM_UNSIGNED : SUM_SIGNED; - } - if (m_sumType == SUM_SIGNED) - ok = chksum == m_hdr->Sum(true); - if (!ok) { - wxLogError(_("checksum failure reading tar header block")); - return wxSTREAM_READ_ERROR; - } - - if (strcmp(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC) == 0) - m_tarType = TYPE_USTAR; - else if (strcmp(m_hdr->Get(TAR_MAGIC), GNU_MAGIC) == 0 && - strcmp(m_hdr->Get(TAR_VERSION), GNU_VERION) == 0) - m_tarType = TYPE_GNUTAR; - else - m_tarType = TYPE_OLDTAR; - - if (m_tarType != TYPE_USTAR) - break; - - switch (*m_hdr->Get(TAR_TYPEFLAG)) { - case 'g': ReadExtendedHeader(m_GlobalHeaderRecs); break; - case 'x': ReadExtendedHeader(m_HeaderRecs); break; - default: done = true; - } - } - - return wxSTREAM_NO_ERROR; -} - -wxString wxTarInputStream::GetExtendedHeader(const wxString& key) const -{ - wxTarHeaderRecords::iterator it; - - // look at normal extended header records first - if (m_HeaderRecs) { - it = m_HeaderRecs->find(key); - if (it != m_HeaderRecs->end()) - return wxString(it->second.wc_str(wxConvUTF8), GetConv()); - } - - // if not found, look at the global header records - if (m_GlobalHeaderRecs) { - it = m_GlobalHeaderRecs->find(key); - if (it != m_GlobalHeaderRecs->end()) - return wxString(it->second.wc_str(wxConvUTF8), GetConv()); - } - - return wxEmptyString; -} - -wxString wxTarInputStream::GetHeaderPath() const -{ - wxString path; - - if ((path = GetExtendedHeader(_T("path"))) != wxEmptyString) - return path; - - path = wxString(m_hdr->Get(TAR_NAME), GetConv()); - if (m_tarType != TYPE_USTAR) - return path; - - const char *prefix = m_hdr->Get(TAR_PREFIX); - return *prefix ? wxString(prefix, GetConv()) + _T("/") + path : path; -} - -wxDateTime wxTarInputStream::GetHeaderDate(const wxString& key) const -{ - wxString value; - - // try extended header, stored as decimal seconds since the epoch - if ((value = GetExtendedHeader(key)) != wxEmptyString) { - wxLongLong ll; - ll.Assign(wxAtof(value) * 1000.0); - return ll; - } - - if (key == _T("mtime")) - return wxLongLong(m_hdr->GetOctal(TAR_MTIME)) * 1000L; - - return wxDateTime(); -} - -wxTarNumber wxTarInputStream::GetHeaderNumber(int id) const -{ - wxString value; - - if ((value = GetExtendedHeader(m_hdr->Name(id))) != wxEmptyString) { - wxTarNumber n = 0; - const wxChar *p = value; - while (*p == ' ') - p++; - while (isdigit(*p)) - n = n * 10 + (*p++ - '0'); - return n; - } else { - return m_hdr->GetOctal(id); - } -} - -wxString wxTarInputStream::GetHeaderString(int id) const -{ - wxString value; - - if ((value = GetExtendedHeader(m_hdr->Name(id))) != wxEmptyString) - return value; - - return wxString(m_hdr->Get(id), GetConv()); -} - -// An extended header consists of one or more records, each constructed: -// "%d %s=%s\n", , , -// is the byte length, and are UTF-8 - -bool wxTarInputStream::ReadExtendedHeader(wxTarHeaderRecords*& recs) -{ - if (!recs) - recs = new wxTarHeaderRecords; - - // round length up to a whole number of blocks - size_t len = m_hdr->GetOctal(TAR_SIZE); - size_t size = RoundUpSize(len); - - // read in the whole header since it should be small - wxCharBuffer buf(size); - size_t lastread = m_parent_i_stream->Read(buf.data(), size).LastRead(); - if (lastread < len) - len = lastread; - buf.data()[len] = 0; - m_offset += lastread; - - size_t recPos, recSize; - bool ok = true; - - for (recPos = 0; recPos < len; recPos += recSize) { - char *pRec = buf.data() + recPos; - char *p = pRec; - - // read the record size (byte count in ascii decimal) - recSize = 0; - while (isdigit((unsigned char) *p)) - recSize = recSize * 10 + *p++ - '0'; - - // validity checks - if (recPos + recSize > len) - break; - if (recSize < p - pRec + (size_t)3 || *p != ' ' - || pRec[recSize - 1] != '\012') { - ok = false; - continue; - } - - // replace the final '\n' with a nul, to terminate value - pRec[recSize - 1] = 0; - // the key is here, following the space - char *pKey = ++p; - - // look forward for the '=', the value follows - while (*p && *p != '=') - p++; - if (!*p) { - ok = false; - continue; - } - // replace the '=' with a nul, to terminate the key - *p++ = 0; - - wxString key(wxConvUTF8.cMB2WC(pKey), GetConv()); - wxString value(wxConvUTF8.cMB2WC(p), GetConv()); - - // an empty value unsets a previously given value - if (value.empty()) - recs->erase(key); - else - (*recs)[key] = value; - } - - if (!ok || recPos < len || size != lastread) { - wxLogWarning(_("invalid data in extended tar header")); - return false; - } - - return true; -} - -wxFileOffset wxTarInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - if (!IsOpened()) { - wxLogError(_("tar entry not open")); - m_lasterror = wxSTREAM_READ_ERROR; - } - if (!IsOk()) - return wxInvalidOffset; - - switch (mode) { - case wxFromStart: break; - case wxFromCurrent: pos += m_pos; break; - case wxFromEnd: pos += m_size; break; - } - - if (pos < 0 || m_parent_i_stream->SeekI(m_offset + pos) == wxInvalidOffset) - return wxInvalidOffset; - - m_pos = pos; - return m_pos; -} - -size_t wxTarInputStream::OnSysRead(void *buffer, size_t size) -{ - if (!IsOpened()) { - wxLogError(_("tar entry not open")); - m_lasterror = wxSTREAM_READ_ERROR; - } - if (!IsOk() || !size) - return 0; - - if (m_pos >= m_size) - size = 0; - else if (m_pos + size > m_size + (size_t)0) - size = m_size - m_pos; - - size_t lastread = m_parent_i_stream->Read(buffer, size).LastRead(); - m_pos += lastread; - - if (m_pos >= m_size) { - m_lasterror = wxSTREAM_EOF; - } else if (!m_parent_i_stream->IsOk()) { - // any other error will have been reported by the underlying stream - if (m_parent_i_stream->Eof()) - wxLogError(_("unexpected end of file")); - m_lasterror = wxSTREAM_READ_ERROR; - } - - return lastread; -} - - -///////////////////////////////////////////////////////////////////////////// -// Output stream - -wxTarOutputStream::wxTarOutputStream(wxOutputStream& stream, - wxTarFormat format /*=wxTAR_PAX*/, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveOutputStream(stream, conv) -{ - Init(format); -} - -wxTarOutputStream::wxTarOutputStream(wxOutputStream *stream, - wxTarFormat format /*=wxTAR_PAX*/, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveOutputStream(stream, conv) -{ - Init(format); -} - -void wxTarOutputStream::Init(wxTarFormat format) -{ - m_pos = wxInvalidOffset; - m_maxpos = wxInvalidOffset; - m_size = wxInvalidOffset; - m_headpos = wxInvalidOffset; - m_datapos = wxInvalidOffset; - m_tarstart = wxInvalidOffset; - m_tarsize = 0; - m_pax = format == wxTAR_PAX; - m_BlockingFactor = m_pax ? 10 : 20; - m_chksum = 0; - m_large = false; - m_hdr = new wxTarHeaderBlock; - m_hdr2 = NULL; - m_extendedHdr = NULL; - m_extendedSize = 0; - m_lasterror = m_parent_o_stream->GetLastError(); -} - -wxTarOutputStream::~wxTarOutputStream() -{ - if (m_tarsize) - Close(); - delete m_hdr; - delete m_hdr2; - delete [] m_extendedHdr; -} - -bool wxTarOutputStream::PutNextEntry(wxTarEntry *entry) -{ - wxTarEntryPtr_ e(entry); - - if (!CloseEntry()) - return false; - - if (!m_tarsize) { - wxLogNull nolog; - m_tarstart = m_parent_o_stream->TellO(); - } - - if (m_tarstart != wxInvalidOffset) - m_headpos = m_tarstart + m_tarsize; - - if (WriteHeaders(*e)) { - m_pos = 0; - m_maxpos = 0; - m_size = GetDataSize(*e); - if (m_tarstart != wxInvalidOffset) - m_datapos = m_tarstart + m_tarsize; - - // types that are not allowd any data - const char nodata[] = { - wxTAR_LNKTYPE, wxTAR_SYMTYPE, wxTAR_CHRTYPE, wxTAR_BLKTYPE, - wxTAR_DIRTYPE, wxTAR_FIFOTYPE, 0 - }; - int typeflag = e->GetTypeFlag(); - - // pax does now allow data for wxTAR_LNKTYPE - if (!m_pax || typeflag != wxTAR_LNKTYPE) - if (strchr(nodata, typeflag) != NULL) - CloseEntry(); - } - - return IsOk(); -} - -bool wxTarOutputStream::PutNextEntry(const wxString& name, - const wxDateTime& dt, - wxFileOffset size) -{ - return PutNextEntry(new wxTarEntry(name, dt, size)); -} - -bool wxTarOutputStream::PutNextDirEntry(const wxString& name, - const wxDateTime& dt) -{ - wxTarEntry *entry = new wxTarEntry(name, dt); - entry->SetIsDir(); - return PutNextEntry(entry); -} - -bool wxTarOutputStream::PutNextEntry(wxArchiveEntry *entry) -{ - wxTarEntry *tarEntry = wxStaticCast(entry, wxTarEntry); - if (!tarEntry) - delete entry; - return PutNextEntry(tarEntry); -} - -bool wxTarOutputStream::CopyEntry(wxTarEntry *entry, - wxTarInputStream& inputStream) -{ - if (PutNextEntry(entry)) - Write(inputStream); - return IsOk() && inputStream.Eof(); -} - -bool wxTarOutputStream::CopyEntry(wxArchiveEntry *entry, - wxArchiveInputStream& inputStream) -{ - if (PutNextEntry(entry)) - Write(inputStream); - return IsOk() && inputStream.Eof(); -} - -bool wxTarOutputStream::CloseEntry() -{ - if (!IsOpened()) - return true; - - if (m_pos < m_maxpos) { - wxASSERT(m_parent_o_stream->IsSeekable()); - m_parent_o_stream->SeekO(m_datapos + m_maxpos); - m_lasterror = m_parent_o_stream->GetLastError(); - m_pos = m_maxpos; - } - - if (IsOk()) { - wxFileOffset size = RoundUpSize(m_pos); - if (size > m_pos) { - memset(m_hdr, 0, size - m_pos); - m_parent_o_stream->Write(m_hdr, size - m_pos); - m_lasterror = m_parent_o_stream->GetLastError(); - } - m_tarsize += size; - } - - if (IsOk() && m_pos != m_size) - ModifyHeader(); - - m_pos = wxInvalidOffset; - m_maxpos = wxInvalidOffset; - m_size = wxInvalidOffset; - m_headpos = wxInvalidOffset; - m_datapos = wxInvalidOffset; - - return IsOk(); -} - -bool wxTarOutputStream::Close() -{ - if (!CloseEntry()) - return false; - - memset(m_hdr, 0, sizeof(*m_hdr)); - int count = (RoundUpSize(m_tarsize + 2 * TAR_BLOCKSIZE, m_BlockingFactor) - - m_tarsize) / TAR_BLOCKSIZE; - while (count--) - m_parent_o_stream->Write(m_hdr, TAR_BLOCKSIZE); - - m_tarsize = 0; - m_tarstart = wxInvalidOffset; - m_lasterror = m_parent_o_stream->GetLastError(); - return IsOk(); -} - -bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry) -{ - memset(m_hdr, 0, sizeof(*m_hdr)); - - SetHeaderPath(entry.GetName(wxPATH_UNIX)); - - SetHeaderNumber(TAR_MODE, entry.GetMode()); - SetHeaderNumber(TAR_UID, entry.GetUserId()); - SetHeaderNumber(TAR_GID, entry.GetGroupId()); - - if (entry.GetSize() == wxInvalidOffset) - entry.SetSize(0); - m_large = !SetHeaderNumber(TAR_SIZE, entry.GetSize()); - - SetHeaderDate(_T("mtime"), entry.GetDateTime()); - if (entry.GetAccessTime().IsValid()) - SetHeaderDate(_T("atime"), entry.GetAccessTime()); - if (entry.GetCreateTime().IsValid()) - SetHeaderDate(_T("ctime"), entry.GetCreateTime()); - - *m_hdr->Get(TAR_TYPEFLAG) = char(entry.GetTypeFlag()); - - strcpy(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC); - strcpy(m_hdr->Get(TAR_VERSION), USTAR_VERSION); - - SetHeaderString(TAR_LINKNAME, entry.GetLinkName()); - SetHeaderString(TAR_UNAME, entry.GetUserName()); - SetHeaderString(TAR_GNAME, entry.GetGroupName()); - - if (~entry.GetDevMajor()) - SetHeaderNumber(TAR_DEVMAJOR, entry.GetDevMajor()); - if (~entry.GetDevMinor()) - SetHeaderNumber(TAR_DEVMINOR, entry.GetDevMinor()); - - m_chksum = m_hdr->Sum(); - m_hdr->SetOctal(TAR_CHKSUM, m_chksum); - if (!m_large) - m_chksum -= m_hdr->SumField(TAR_SIZE); - - // The main header is now fully prepared so we know what extended headers - // (if any) will be needed. Output any extended headers before writing - // the main header. - if (m_extendedHdr && *m_extendedHdr) { - wxASSERT(m_pax); - // the extended headers are written to the tar as a file entry, - // so prepare a regular header block for the pseudo-file. - if (!m_hdr2) - m_hdr2 = new wxTarHeaderBlock; - memset(m_hdr2, 0, sizeof(*m_hdr2)); - - // an old tar that doesn't understand extended headers will - // extract it as a file, so give these fields reasonable values - // so that the user will have access to read and remove it. - m_hdr2->SetPath(PaxHeaderPath(_T("%d/PaxHeaders.%p/%f"), - entry.GetName(wxPATH_UNIX)), GetConv()); - m_hdr2->SetOctal(TAR_MODE, 0600); - strcpy(m_hdr2->Get(TAR_UID), m_hdr->Get(TAR_UID)); - strcpy(m_hdr2->Get(TAR_GID), m_hdr->Get(TAR_GID)); - size_t length = strlen(m_extendedHdr); - m_hdr2->SetOctal(TAR_SIZE, length); - strcpy(m_hdr2->Get(TAR_MTIME), m_hdr->Get(TAR_MTIME)); - *m_hdr2->Get(TAR_TYPEFLAG) = 'x'; - strcpy(m_hdr2->Get(TAR_MAGIC), USTAR_MAGIC); - strcpy(m_hdr2->Get(TAR_VERSION), USTAR_VERSION); - strcpy(m_hdr2->Get(TAR_UNAME), m_hdr->Get(TAR_UNAME)); - strcpy(m_hdr2->Get(TAR_GNAME), m_hdr->Get(TAR_GNAME)); - - m_hdr2->SetOctal(TAR_CHKSUM, m_hdr2->Sum()); - - m_hdr2->Write(*m_parent_o_stream); - m_tarsize += TAR_BLOCKSIZE; - - size_t rounded = RoundUpSize(length); - memset(m_extendedHdr + length, 0, rounded - length); - m_parent_o_stream->Write(m_extendedHdr, rounded); - m_tarsize += rounded; - - *m_extendedHdr = 0; - - // update m_headpos which is used to seek back to fix up the file - // length if it is not known in advance - if (m_tarstart != wxInvalidOffset) - m_headpos = m_tarstart + m_tarsize; - } - - // if don't have extended headers just report error - if (!m_badfit.empty()) { - wxASSERT(!m_pax); - wxLogWarning(_("%s did not fit the tar header for entry '%s'"), - m_badfit.c_str(), entry.GetName().c_str()); - m_badfit.clear(); - } - - m_hdr->Write(*m_parent_o_stream); - m_tarsize += TAR_BLOCKSIZE; - m_lasterror = m_parent_o_stream->GetLastError(); - - return IsOk(); -} - -wxString wxTarOutputStream::PaxHeaderPath(const wxString& format, - const wxString& path) -{ - wxString d = path.BeforeLast(_T('/')); - wxString f = path.AfterLast(_T('/')); - wxString ret; - - if (d.empty()) - d = _T("."); - - ret.reserve(format.length() + path.length() + 16); - - size_t begin = 0; - size_t end; - - for (;;) { - end = format.find('%', begin); - if (end == wxString::npos || end + 1 >= format.length()) - break; - ret << format.substr(begin, end - begin); - switch (format[end + 1]) { - case 'd': ret << d; break; - case 'f': ret << f; break; - case 'p': ret << wxGetProcessId(); break; - case '%': ret << _T("%"); break; - } - begin = end + 2; - } - - ret << format.substr(begin); - - return ret; -} - -bool wxTarOutputStream::ModifyHeader() -{ - wxFileOffset originalPos = wxInvalidOffset; - wxFileOffset sizePos = wxInvalidOffset; - - if (!m_large && m_headpos != wxInvalidOffset - && m_parent_o_stream->IsSeekable()) - { - wxLogNull nolog; - originalPos = m_parent_o_stream->TellO(); - if (originalPos != wxInvalidOffset) - sizePos = - m_parent_o_stream->SeekO(m_headpos + m_hdr->Offset(TAR_SIZE)); - } - - if (sizePos == wxInvalidOffset || !m_hdr->SetOctal(TAR_SIZE, m_pos)) { - wxLogError(_("incorrect size given for tar entry")); - m_lasterror = wxSTREAM_WRITE_ERROR; - return false; - } - - m_chksum += m_hdr->SumField(TAR_SIZE); - m_hdr->SetOctal(TAR_CHKSUM, m_chksum); - wxFileOffset sumPos = m_headpos + m_hdr->Offset(TAR_CHKSUM); - - return - m_hdr->WriteField(*m_parent_o_stream, TAR_SIZE) && - m_parent_o_stream->SeekO(sumPos) == sumPos && - m_hdr->WriteField(*m_parent_o_stream, TAR_CHKSUM) && - m_parent_o_stream->SeekO(originalPos) == originalPos; -} - -void wxTarOutputStream::SetHeaderPath(const wxString& name) -{ - if (!m_hdr->SetPath(name, GetConv()) || (m_pax && !name.IsAscii())) - SetExtendedHeader(_T("path"), name); -} - -bool wxTarOutputStream::SetHeaderNumber(int id, wxTarNumber n) -{ - if (m_hdr->SetOctal(id, n)) { - return true; - } else { - SetExtendedHeader(m_hdr->Name(id), wxLongLong(n).ToString()); - return false; - } -} - -void wxTarOutputStream::SetHeaderString(int id, const wxString& str) -{ - strncpy(m_hdr->Get(id), str.mb_str(GetConv()), m_hdr->Len(id)); - if (str.length() > m_hdr->Len(id)) - SetExtendedHeader(m_hdr->Name(id), str); -} - -void wxTarOutputStream::SetHeaderDate(const wxString& key, - const wxDateTime& datetime) -{ - wxLongLong ll = datetime.IsValid() ? datetime.GetValue() : wxLongLong(0); - wxLongLong secs = ll / 1000L; - - if (key != _T("mtime") - || !m_hdr->SetOctal(TAR_MTIME, wxTarNumber(secs.GetValue())) - || secs <= 0 || secs >= 0x7fffffff) - { - wxString str; - if (ll >= LONG_MIN && ll <= LONG_MAX) { - str.Printf(_T("%g"), ll.ToLong() / 1000.0); - } else { - str = ll.ToString(); - str.insert(str.end() - 3, '.'); - } - SetExtendedHeader(key, str); - } -} - -void wxTarOutputStream::SetExtendedHeader(const wxString& key, - const wxString& value) -{ - if (m_pax) { - const wxWX2WCbuf wide_key = key.wc_str(GetConv()); - const wxCharBuffer utf_key = wxConvUTF8.cWC2MB(wide_key); - - const wxWX2WCbuf wide_value = value.wc_str(GetConv()); - const wxCharBuffer utf_value = wxConvUTF8.cWC2MB(wide_value); - - // a small buffer to format the length field in - char buf[32]; - // length of "99=\n" - unsigned long length = strlen(utf_value) + strlen(utf_key) + 5; - sprintf(buf, "%lu", length); - // the length includes itself - size_t lenlen = strlen(buf); - if (lenlen != 2) { - length += lenlen - 2; - sprintf(buf, "%lu", length); - if (strlen(buf) > lenlen) - sprintf(buf, "%lu", ++length); - } - - // reallocate m_extendedHdr if it's not big enough - if (m_extendedSize < length) { - size_t rounded = RoundUpSize(length); - m_extendedSize <<= 1; - if (rounded > m_extendedSize) - m_extendedSize = rounded; - char *oldHdr = m_extendedHdr; - m_extendedHdr = new char[m_extendedSize]; - if (oldHdr) { - strcpy(m_extendedHdr, oldHdr); - delete oldHdr; - } else { - *m_extendedHdr = 0; - } - } - - // append the new record - char *append = strchr(m_extendedHdr, 0); - sprintf(append, "%s %s=%s\012", buf, - (const char*)utf_key, (const char*)utf_value); - } - else { - // if not pax then make a list of fields to report as errors - if (!m_badfit.empty()) - m_badfit += _T(", "); - m_badfit += key; - } -} - -void wxTarOutputStream::Sync() -{ - m_parent_o_stream->Sync(); -} - -wxFileOffset wxTarOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - if (!IsOpened()) { - wxLogError(_("tar entry not open")); - m_lasterror = wxSTREAM_WRITE_ERROR; - } - if (!IsOk() || m_datapos == wxInvalidOffset) - return wxInvalidOffset; - - switch (mode) { - case wxFromStart: break; - case wxFromCurrent: pos += m_pos; break; - case wxFromEnd: pos += m_maxpos; break; - } - - if (pos < 0 || m_parent_o_stream->SeekO(m_datapos + pos) == wxInvalidOffset) - return wxInvalidOffset; - - m_pos = pos; - return m_pos; -} - -size_t wxTarOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - if (!IsOpened()) { - wxLogError(_("tar entry not open")); - m_lasterror = wxSTREAM_WRITE_ERROR; - } - if (!IsOk() || !size) - return 0; - - size_t lastwrite = m_parent_o_stream->Write(buffer, size).LastWrite(); - m_pos += lastwrite; - if (m_pos > m_maxpos) - m_maxpos = m_pos; - - if (lastwrite != size) - m_lasterror = wxSTREAM_WRITE_ERROR; - - return lastwrite; -} - -#endif // wxUSE_TARSTREAM +///////////////////////////////////////////////////////////////////////////// +// Name: tarstrm.cpp +// Purpose: Streams for Tar files +// Author: Mike Wetherell +// RCS-ID: $Id: tarstrm.cpp 63302 2010-01-28 21:46:09Z MW $ +// Copyright: (c) 2004 Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TARSTREAM + +#include "wx/tarstrm.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" +#endif + +#include "wx/buffer.h" +#include "wx/datetime.h" +#include "wx/ptr_scpd.h" +#include "wx/filename.h" +#include "wx/thread.h" + +#include + +#ifdef __UNIX__ +#include +#include +#endif + + +///////////////////////////////////////////////////////////////////////////// +// constants + +enum { + TAR_NAME, + TAR_MODE, + TAR_UID, + TAR_GID, + TAR_SIZE, + TAR_MTIME, + TAR_CHKSUM, + TAR_TYPEFLAG, + TAR_LINKNAME, + TAR_MAGIC, + TAR_VERSION, + TAR_UNAME, + TAR_GNAME, + TAR_DEVMAJOR, + TAR_DEVMINOR, + TAR_PREFIX, + TAR_UNUSED, + TAR_NUMFIELDS +}; + +enum { + TAR_BLOCKSIZE = 512 +}; + +// checksum type +enum { + SUM_UNKNOWN, + SUM_UNSIGNED, + SUM_SIGNED +}; + +// type of input tar +enum { + TYPE_OLDTAR, // fields after TAR_LINKNAME are invalid + TYPE_GNUTAR, // all fields except TAR_PREFIX are valid + TYPE_USTAR // all fields are valid +}; + +// signatures +static const char *USTAR_MAGIC = "ustar"; +static const char *USTAR_VERSION = "00"; +static const char *GNU_MAGIC = "ustar "; +static const char *GNU_VERION = " "; + +IMPLEMENT_DYNAMIC_CLASS(wxTarEntry, wxArchiveEntry) +IMPLEMENT_DYNAMIC_CLASS(wxTarClassFactory, wxArchiveClassFactory) + + +///////////////////////////////////////////////////////////////////////////// +// Class factory + +static wxTarClassFactory g_wxTarClassFactory; + +wxTarClassFactory::wxTarClassFactory() +{ + if (this == &g_wxTarClassFactory) + PushFront(); +} + +const wxChar * const * +wxTarClassFactory::GetProtocols(wxStreamProtocolType type) const +{ + static const wxChar *protocols[] = { _T("tar"), NULL }; + static const wxChar *mimetypes[] = { _T("application/x-tar"), NULL }; + static const wxChar *fileexts[] = { _T(".tar"), NULL }; + static const wxChar *empty[] = { NULL }; + + switch (type) { + case wxSTREAM_PROTOCOL: return protocols; + case wxSTREAM_MIMETYPE: return mimetypes; + case wxSTREAM_FILEEXT: return fileexts; + default: return empty; + } +} + + +///////////////////////////////////////////////////////////////////////////// +// tar header block + +typedef wxFileOffset wxTarNumber; + +struct wxTarField { const wxChar *name; int pos; }; + +class wxTarHeaderBlock +{ +public: + wxTarHeaderBlock() + { memset(data, 0, sizeof(data)); } + wxTarHeaderBlock(const wxTarHeaderBlock& hb) + { memcpy(data, hb.data, sizeof(data)); } + + bool Read(wxInputStream& in); + bool Write(wxOutputStream& out); + inline bool WriteField(wxOutputStream& out, int id); + + bool IsAllZeros() const; + wxUint32 Sum(bool SignedSum = false); + wxUint32 SumField(int id); + + char *Get(int id) { return data + fields[id].pos + id; } + static size_t Len(int id) { return fields[id + 1].pos - fields[id].pos; } + static const wxChar *Name(int id) { return fields[id].name; } + static size_t Offset(int id) { return fields[id].pos; } + + bool SetOctal(int id, wxTarNumber n); + wxTarNumber GetOctal(int id); + bool SetPath(const wxString& name, wxMBConv& conv); + +private: + char data[TAR_BLOCKSIZE + TAR_NUMFIELDS]; + static const wxTarField fields[]; + static void check(); +}; + +wxDEFINE_SCOPED_PTR_TYPE(wxTarHeaderBlock) + +// A table giving the field names and offsets in a tar header block +const wxTarField wxTarHeaderBlock::fields[] = +{ + { _T("name"), 0 }, // 100 + { _T("mode"), 100 }, // 8 + { _T("uid"), 108 }, // 8 + { _T("gid"), 116 }, // 8 + { _T("size"), 124 }, // 12 + { _T("mtime"), 136 }, // 12 + { _T("chksum"), 148 }, // 8 + { _T("typeflag"), 156 }, // 1 + { _T("linkname"), 157 }, // 100 + { _T("magic"), 257 }, // 6 + { _T("version"), 263 }, // 2 + { _T("uname"), 265 }, // 32 + { _T("gname"), 297 }, // 32 + { _T("devmajor"), 329 }, // 8 + { _T("devminor"), 337 }, // 8 + { _T("prefix"), 345 }, // 155 + { _T("unused"), 500 }, // 12 + { NULL, TAR_BLOCKSIZE } +}; + +void wxTarHeaderBlock::check() +{ +#if 0 + wxCOMPILE_TIME_ASSERT( + WXSIZEOF(fields) == TAR_NUMFIELDS + 1, + Wrong_number_of_elements_in_fields_table + ); +#endif +} + +bool wxTarHeaderBlock::IsAllZeros() const +{ + const char *p = data; + for (size_t i = 0; i < sizeof(data); i++) + if (p[i]) + return false; + return true; +} + +wxUint32 wxTarHeaderBlock::Sum(bool SignedSum /*=false*/) +{ + // the chksum field itself should be blanks during the calculation + memset(Get(TAR_CHKSUM), ' ', Len(TAR_CHKSUM)); + const char *p = data; + wxUint32 n = 0; + + if (SignedSum) + for (size_t i = 0; i < sizeof(data); i++) + n += (signed char)p[i]; + else + for (size_t i = 0; i < sizeof(data); i++) + n += (unsigned char)p[i]; + + return n; +} + +wxUint32 wxTarHeaderBlock::SumField(int id) +{ + unsigned char *p = (unsigned char*)Get(id); + unsigned char *q = p + Len(id); + wxUint32 n = 0; + + while (p < q) + n += *p++; + + return n; +} + +bool wxTarHeaderBlock::Read(wxInputStream& in) +{ + bool ok = true; + + for (int id = 0; id < TAR_NUMFIELDS && ok; id++) + ok = in.Read(Get(id), Len(id)).LastRead() == Len(id); + + return ok; +} + +bool wxTarHeaderBlock::Write(wxOutputStream& out) +{ + bool ok = true; + + for (int id = 0; id < TAR_NUMFIELDS && ok; id++) + ok = WriteField(out, id); + + return ok; +} + +inline bool wxTarHeaderBlock::WriteField(wxOutputStream& out, int id) +{ + return out.Write(Get(id), Len(id)).LastWrite() == Len(id); +} + +wxTarNumber wxTarHeaderBlock::GetOctal(int id) +{ + wxTarNumber n = 0; + const char *p = Get(id); + while (*p == ' ') + p++; + while (*p >= '0' && *p < '8') + n = (n << 3) | (*p++ - '0'); + return n; +} + +bool wxTarHeaderBlock::SetOctal(int id, wxTarNumber n) +{ + // set an octal field, return true if the number fits + char *field = Get(id); + char *p = field + Len(id); + *--p = 0; + while (p > field) { + *--p = char('0' + (n & 7)); + n >>= 3; + } + return n == 0; +} + +bool wxTarHeaderBlock::SetPath(const wxString& name, wxMBConv& conv) +{ + bool badconv = false; + +#if wxUSE_UNICODE + wxCharBuffer nameBuf = name.mb_str(conv); + + // if the conversion fails make an approximation + if (!nameBuf) { + badconv = true; + size_t len = name.length(); + wxCharBuffer approx(len); + for (size_t i = 0; i < len; i++) + approx.data()[i] = name[i] & ~0x7F ? '_' : name[i]; + nameBuf = approx; + } + + const char *mbName = nameBuf; +#else + const char *mbName = name.c_str(); + (void)conv; +#endif + + bool fits; + bool notGoingToFit = false; + size_t len = strlen(mbName); + size_t maxname = Len(TAR_NAME); + size_t maxprefix = Len(TAR_PREFIX); + size_t i = 0; + size_t nexti = 0; + + for (;;) { + fits = i < maxprefix && len - i <= maxname; + + if (!fits) { + const char *p = strchr(mbName + i, '/'); + if (p) + nexti = p - mbName + 1; + if (!p || nexti - 1 > maxprefix) + notGoingToFit = true; + } + + if (fits || notGoingToFit) { + strncpy(Get(TAR_NAME), mbName + i, maxname); + if (i > 0) + strncpy(Get(TAR_PREFIX), mbName, i - 1); + break; + } + + i = nexti; + } + + return fits && !badconv; +} + + +///////////////////////////////////////////////////////////////////////////// +// Some helpers + +static wxFileOffset RoundUpSize(wxFileOffset size, int factor = 1) +{ + wxFileOffset chunk = TAR_BLOCKSIZE * factor; + return ((size + chunk - 1) / chunk) * chunk; +} + +#ifdef __UNIX__ + +static wxString wxTarUserName(int uid) +{ + struct passwd *ppw; + +#ifdef HAVE_GETPWUID_R +#if defined HAVE_SYSCONF && defined _SC_GETPW_R_SIZE_MAX + long pwsize = sysconf(_SC_GETPW_R_SIZE_MAX); + size_t bufsize(wxMin(wxMax(1024l, pwsize), 32768l)); +#else + size_t bufsize = 1024; +#endif + wxCharBuffer buf(bufsize); + struct passwd pw; + + memset(&pw, 0, sizeof(pw)); + if (getpwuid_r(uid, &pw, buf.data(), bufsize, &ppw) == 0 && pw.pw_name) + return wxString(pw.pw_name, wxConvLibc); +#else + if ((ppw = getpwuid(uid)) != NULL) + return wxString(ppw->pw_name, wxConvLibc); +#endif + return _("unknown"); +} + +static wxString wxTarGroupName(int gid) +{ + struct group *pgr; +#ifdef HAVE_GETGRGID_R +#if defined HAVE_SYSCONF && defined _SC_GETGR_R_SIZE_MAX + long grsize = sysconf(_SC_GETGR_R_SIZE_MAX); + size_t bufsize(wxMin(wxMax(1024l, grsize), 32768l)); +#else + size_t bufsize = 1024; +#endif + wxCharBuffer buf(bufsize); + struct group gr; + + memset(&gr, 0, sizeof(gr)); + if (getgrgid_r(gid, &gr, buf.data(), bufsize, &pgr) == 0 && gr.gr_name) + return wxString(gr.gr_name, wxConvLibc); +#else + if ((pgr = getgrgid(gid)) != NULL) + return wxString(pgr->gr_name, wxConvLibc); +#endif + return _("unknown"); +} + +#endif // __UNIX__ + +// Cache the user and group names since getting them can be expensive, +// get both names and ids at the same time. +// +struct wxTarUser +{ + wxTarUser(); + ~wxTarUser() { delete [] uname; delete [] gname; } + + int uid; + int gid; + + wxChar *uname; + wxChar *gname; +}; + +wxTarUser::wxTarUser() +{ +#ifdef __UNIX__ + uid = getuid(); + gid = getgid(); + wxString usr = wxTarUserName(uid); + wxString grp = wxTarGroupName(gid); +#else + uid = 0; + gid = 0; + wxString usr = wxGetUserId(); + wxString grp = _("unknown"); +#endif + + uname = new wxChar[usr.length() + 1]; + wxStrcpy(uname, usr.c_str()); + + gname = new wxChar[grp.length() + 1]; + wxStrcpy(gname, grp.c_str()); +} + +static const wxTarUser& wxGetTarUser() +{ +#if wxUSE_THREADS + static wxCriticalSection cs; + wxCriticalSectionLocker lock(cs); +#endif + static wxTarUser tu; + return tu; +} + +// ignore the size field for entry types 3, 4, 5 and 6 +// +static inline wxFileOffset GetDataSize(const wxTarEntry& entry) +{ + switch (entry.GetTypeFlag()) { + case wxTAR_CHRTYPE: + case wxTAR_BLKTYPE: + case wxTAR_DIRTYPE: + case wxTAR_FIFOTYPE: + return 0; + default: + return entry.GetSize(); + } +} + + +///////////////////////////////////////////////////////////////////////////// +// Tar Entry +// Holds all the meta-data for a file in the tar + +wxTarEntry::wxTarEntry(const wxString& name /*=wxEmptyString*/, + const wxDateTime& dt /*=wxDateTime::Now()*/, + wxFileOffset size /*=0*/) + : m_Mode(0644), + m_IsModeSet(false), + m_UserId(wxGetTarUser().uid), + m_GroupId(wxGetTarUser().gid), + m_Size(size), + m_Offset(wxInvalidOffset), + m_ModifyTime(dt), + m_TypeFlag(wxTAR_REGTYPE), + m_UserName(wxGetTarUser().uname), + m_GroupName(wxGetTarUser().gname), + m_DevMajor(~0), + m_DevMinor(~0) +{ + if (!name.empty()) + SetName(name); +} + +wxTarEntry::~wxTarEntry() +{ +} + +wxTarEntry::wxTarEntry(const wxTarEntry& e) + : wxArchiveEntry(), + m_Name(e.m_Name), + m_Mode(e.m_Mode), + m_IsModeSet(e.m_IsModeSet), + m_UserId(e.m_UserId), + m_GroupId(e.m_GroupId), + m_Size(e.m_Size), + m_Offset(e.m_Offset), + m_ModifyTime(e.m_ModifyTime), + m_AccessTime(e.m_AccessTime), + m_CreateTime(e.m_CreateTime), + m_TypeFlag(e.m_TypeFlag), + m_LinkName(e.m_LinkName), + m_UserName(e.m_UserName), + m_GroupName(e.m_GroupName), + m_DevMajor(e.m_DevMajor), + m_DevMinor(e.m_DevMinor) +{ +} + +wxTarEntry& wxTarEntry::operator=(const wxTarEntry& e) +{ + if (&e != this) { + m_Name = e.m_Name; + m_Mode = e.m_Mode; + m_IsModeSet = e.m_IsModeSet; + m_UserId = e.m_UserId; + m_GroupId = e.m_GroupId; + m_Size = e.m_Size; + m_Offset = e.m_Offset; + m_ModifyTime = e.m_ModifyTime; + m_AccessTime = e.m_AccessTime; + m_CreateTime = e.m_CreateTime; + m_TypeFlag = e.m_TypeFlag; + m_LinkName = e.m_LinkName; + m_UserName = e.m_UserName; + m_GroupName = e.m_GroupName; + m_DevMajor = e.m_DevMajor; + m_DevMinor = e.m_DevMinor; + } + return *this; +} + +wxString wxTarEntry::GetName(wxPathFormat format /*=wxPATH_NATIVE*/) const +{ + bool isDir = IsDir() && !m_Name.empty(); + + // optimisations for common (and easy) cases + switch (wxFileName::GetFormat(format)) { + case wxPATH_DOS: + { + wxString name(isDir ? m_Name + _T("\\") : m_Name); + for (size_t i = 0; i < name.length(); i++) + if (name[i] == _T('/')) + name[i] = _T('\\'); + return name; + } + + case wxPATH_UNIX: + return isDir ? m_Name + _T("/") : m_Name; + + default: + ; + } + + wxFileName fn; + + if (isDir) + fn.AssignDir(m_Name, wxPATH_UNIX); + else + fn.Assign(m_Name, wxPATH_UNIX); + + return fn.GetFullPath(format); +} + +void wxTarEntry::SetName(const wxString& name, wxPathFormat format) +{ + bool isDir; + m_Name = GetInternalName(name, format, &isDir); + SetIsDir(isDir); +} + +// Static - Internally tars and zips use forward slashes for the path +// separator, absolute paths aren't allowed, and directory names have a +// trailing slash. This function converts a path into this internal format, +// but without a trailing slash for a directory. +// +wxString wxTarEntry::GetInternalName(const wxString& name, + wxPathFormat format /*=wxPATH_NATIVE*/, + bool *pIsDir /*=NULL*/) +{ + wxString internal; + + if (wxFileName::GetFormat(format) != wxPATH_UNIX) + internal = wxFileName(name, format).GetFullPath(wxPATH_UNIX); + else + internal = name; + + bool isDir = !internal.empty() && internal.Last() == '/'; + if (pIsDir) + *pIsDir = isDir; + if (isDir) + internal.erase(internal.length() - 1); + + while (!internal.empty() && *internal.begin() == '/') + internal.erase(0, 1); + while (!internal.empty() && internal.compare(0, 2, _T("./")) == 0) + internal.erase(0, 2); + if (internal == _T(".") || internal == _T("..")) + internal = wxEmptyString; + + return internal; +} + +bool wxTarEntry::IsDir() const +{ + return m_TypeFlag == wxTAR_DIRTYPE; +} + +void wxTarEntry::SetIsDir(bool isDir) +{ + if (isDir) + m_TypeFlag = wxTAR_DIRTYPE; + else if (m_TypeFlag == wxTAR_DIRTYPE) + m_TypeFlag = wxTAR_REGTYPE; +} + +void wxTarEntry::SetIsReadOnly(bool isReadOnly) +{ + if (isReadOnly) + m_Mode &= ~0222; + else + m_Mode |= 0200; +} + +int wxTarEntry::GetMode() const +{ + if (m_IsModeSet || !IsDir()) + return m_Mode; + else + return m_Mode | 0111; + +} + +void wxTarEntry::SetMode(int mode) +{ + m_Mode = mode & 07777; + m_IsModeSet = true; +} + + +///////////////////////////////////////////////////////////////////////////// +// Input stream + +wxDECLARE_SCOPED_PTR(wxTarEntry, wxTarEntryPtr_) +wxDEFINE_SCOPED_PTR (wxTarEntry, wxTarEntryPtr_) + +wxTarInputStream::wxTarInputStream(wxInputStream& stream, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveInputStream(stream, conv) +{ + Init(); +} + +wxTarInputStream::wxTarInputStream(wxInputStream *stream, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveInputStream(stream, conv) +{ + Init(); +} + +void wxTarInputStream::Init() +{ + m_pos = wxInvalidOffset; + m_offset = 0; + m_size = wxInvalidOffset; + m_sumType = SUM_UNKNOWN; + m_tarType = TYPE_USTAR; + m_hdr = new wxTarHeaderBlock; + m_HeaderRecs = NULL; + m_GlobalHeaderRecs = NULL; + m_lasterror = m_parent_i_stream->GetLastError(); +} + +wxTarInputStream::~wxTarInputStream() +{ + delete m_hdr; + delete m_HeaderRecs; + delete m_GlobalHeaderRecs; +} + +wxTarEntry *wxTarInputStream::GetNextEntry() +{ + m_lasterror = ReadHeaders(); + + if (!IsOk()) + return NULL; + + wxTarEntryPtr_ entry(new wxTarEntry); + + entry->SetMode(GetHeaderNumber(TAR_MODE)); + entry->SetUserId(GetHeaderNumber(TAR_UID)); + entry->SetGroupId(GetHeaderNumber(TAR_UID)); + entry->SetSize(GetHeaderNumber(TAR_SIZE)); + + entry->SetOffset(m_offset); + + entry->SetDateTime(GetHeaderDate(_T("mtime"))); + entry->SetAccessTime(GetHeaderDate(_T("atime"))); + entry->SetCreateTime(GetHeaderDate(_T("ctime"))); + + entry->SetTypeFlag(*m_hdr->Get(TAR_TYPEFLAG)); + bool isDir = entry->IsDir(); + + entry->SetLinkName(GetHeaderString(TAR_LINKNAME)); + + if (m_tarType != TYPE_OLDTAR) { + entry->SetUserName(GetHeaderString(TAR_UNAME)); + entry->SetGroupName(GetHeaderString(TAR_GNAME)); + + entry->SetDevMajor(GetHeaderNumber(TAR_DEVMAJOR)); + entry->SetDevMinor(GetHeaderNumber(TAR_DEVMINOR)); + } + + entry->SetName(GetHeaderPath(), wxPATH_UNIX); + if (isDir) + entry->SetIsDir(); + + if (m_HeaderRecs) + m_HeaderRecs->clear(); + + m_size = GetDataSize(*entry); + m_pos = 0; + + return entry.release(); +} + +bool wxTarInputStream::OpenEntry(wxTarEntry& entry) +{ + wxFileOffset offset = entry.GetOffset(); + + if (GetLastError() != wxSTREAM_READ_ERROR + && m_parent_i_stream->IsSeekable() + && m_parent_i_stream->SeekI(offset) == offset) + { + m_offset = offset; + m_size = GetDataSize(entry); + m_pos = 0; + m_lasterror = wxSTREAM_NO_ERROR; + return true; + } else { + m_lasterror = wxSTREAM_READ_ERROR; + return false; + } +} + +bool wxTarInputStream::OpenEntry(wxArchiveEntry& entry) +{ + wxTarEntry *tarEntry = wxStaticCast(&entry, wxTarEntry); + return tarEntry ? OpenEntry(*tarEntry) : false; +} + +bool wxTarInputStream::CloseEntry() +{ + if (m_lasterror == wxSTREAM_READ_ERROR) + return false; + if (!IsOpened()) + return true; + + wxFileOffset size = RoundUpSize(m_size); + wxFileOffset remainder = size - m_pos; + + if (remainder && m_parent_i_stream->IsSeekable()) { + wxLogNull nolog; + if (m_parent_i_stream->SeekI(remainder, wxFromCurrent) + != wxInvalidOffset) + remainder = 0; + } + + if (remainder) { + const int BUFSIZE = 8192; + wxCharBuffer buf(BUFSIZE); + + while (remainder > 0 && m_parent_i_stream->IsOk()) + remainder -= m_parent_i_stream->Read( + buf.data(), wxMin(BUFSIZE, remainder)).LastRead(); + } + + m_pos = wxInvalidOffset; + m_offset += size; + m_lasterror = m_parent_i_stream->GetLastError(); + + return IsOk(); +} + +wxStreamError wxTarInputStream::ReadHeaders() +{ + if (!CloseEntry()) + return wxSTREAM_READ_ERROR; + + bool done = false; + + while (!done) { + m_hdr->Read(*m_parent_i_stream); + if (m_parent_i_stream->Eof()) + wxLogError(_("incomplete header block in tar")); + if (!*m_parent_i_stream) + return wxSTREAM_READ_ERROR; + m_offset += TAR_BLOCKSIZE; + + // an all-zero header marks the end of the tar + if (m_hdr->IsAllZeros()) + return wxSTREAM_EOF; + + // the checksum is supposed to be the unsigned sum of the header bytes, + // but there have been versions of tar that used the signed sum, so + // accept that too, but only if used throughout. + wxUint32 chksum = m_hdr->GetOctal(TAR_CHKSUM); + bool ok = false; + + if (m_sumType != SUM_SIGNED) { + ok = chksum == m_hdr->Sum(); + if (m_sumType == SUM_UNKNOWN) + m_sumType = ok ? SUM_UNSIGNED : SUM_SIGNED; + } + if (m_sumType == SUM_SIGNED) + ok = chksum == m_hdr->Sum(true); + if (!ok) { + wxLogError(_("checksum failure reading tar header block")); + return wxSTREAM_READ_ERROR; + } + + if (strcmp(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC) == 0) + m_tarType = TYPE_USTAR; + else if (strcmp(m_hdr->Get(TAR_MAGIC), GNU_MAGIC) == 0 && + strcmp(m_hdr->Get(TAR_VERSION), GNU_VERION) == 0) + m_tarType = TYPE_GNUTAR; + else + m_tarType = TYPE_OLDTAR; + + if (m_tarType != TYPE_USTAR) + break; + + switch (*m_hdr->Get(TAR_TYPEFLAG)) { + case 'g': ReadExtendedHeader(m_GlobalHeaderRecs); break; + case 'x': ReadExtendedHeader(m_HeaderRecs); break; + default: done = true; + } + } + + return wxSTREAM_NO_ERROR; +} + +wxString wxTarInputStream::GetExtendedHeader(const wxString& key) const +{ + wxTarHeaderRecords::iterator it; + + // look at normal extended header records first + if (m_HeaderRecs) { + it = m_HeaderRecs->find(key); + if (it != m_HeaderRecs->end()) + return wxString(it->second.wc_str(wxConvUTF8), GetConv()); + } + + // if not found, look at the global header records + if (m_GlobalHeaderRecs) { + it = m_GlobalHeaderRecs->find(key); + if (it != m_GlobalHeaderRecs->end()) + return wxString(it->second.wc_str(wxConvUTF8), GetConv()); + } + + return wxEmptyString; +} + +wxString wxTarInputStream::GetHeaderPath() const +{ + wxString path; + + if ((path = GetExtendedHeader(_T("path"))) != wxEmptyString) + return path; + + path = wxString(m_hdr->Get(TAR_NAME), GetConv()); + if (m_tarType != TYPE_USTAR) + return path; + + const char *prefix = m_hdr->Get(TAR_PREFIX); + return *prefix ? wxString(prefix, GetConv()) + _T("/") + path : path; +} + +wxDateTime wxTarInputStream::GetHeaderDate(const wxString& key) const +{ + wxString value; + + // try extended header, stored as decimal seconds since the epoch + if ((value = GetExtendedHeader(key)) != wxEmptyString) { + wxLongLong ll; + ll.Assign(wxAtof(value) * 1000.0); + return ll; + } + + if (key == _T("mtime")) + return wxLongLong(m_hdr->GetOctal(TAR_MTIME)) * 1000L; + + return wxDateTime(); +} + +wxTarNumber wxTarInputStream::GetHeaderNumber(int id) const +{ + wxString value; + + if ((value = GetExtendedHeader(m_hdr->Name(id))) != wxEmptyString) { + wxTarNumber n = 0; + const wxChar *p = value; + while (*p == ' ') + p++; + while (isdigit(*p)) + n = n * 10 + (*p++ - '0'); + return n; + } else { + return m_hdr->GetOctal(id); + } +} + +wxString wxTarInputStream::GetHeaderString(int id) const +{ + wxString value; + + if ((value = GetExtendedHeader(m_hdr->Name(id))) != wxEmptyString) + return value; + + return wxString(m_hdr->Get(id), GetConv()); +} + +// An extended header consists of one or more records, each constructed: +// "%d %s=%s\n", , , +// is the byte length, and are UTF-8 + +bool wxTarInputStream::ReadExtendedHeader(wxTarHeaderRecords*& recs) +{ + if (!recs) + recs = new wxTarHeaderRecords; + + // round length up to a whole number of blocks + size_t len = m_hdr->GetOctal(TAR_SIZE); + size_t size = RoundUpSize(len); + + // read in the whole header since it should be small + wxCharBuffer buf(size); + size_t lastread = m_parent_i_stream->Read(buf.data(), size).LastRead(); + if (lastread < len) + len = lastread; + buf.data()[len] = 0; + m_offset += lastread; + + size_t recPos, recSize; + bool ok = true; + + for (recPos = 0; recPos < len; recPos += recSize) { + char *pRec = buf.data() + recPos; + char *p = pRec; + + // read the record size (byte count in ascii decimal) + recSize = 0; + while (isdigit((unsigned char) *p)) + recSize = recSize * 10 + *p++ - '0'; + + // validity checks + if (recPos + recSize > len) + break; + if (recSize < p - pRec + (size_t)3 || *p != ' ' + || pRec[recSize - 1] != '\012') { + ok = false; + continue; + } + + // replace the final '\n' with a nul, to terminate value + pRec[recSize - 1] = 0; + // the key is here, following the space + char *pKey = ++p; + + // look forward for the '=', the value follows + while (*p && *p != '=') + p++; + if (!*p) { + ok = false; + continue; + } + // replace the '=' with a nul, to terminate the key + *p++ = 0; + + wxString key(wxConvUTF8.cMB2WC(pKey), GetConv()); + wxString value(wxConvUTF8.cMB2WC(p), GetConv()); + + // an empty value unsets a previously given value + if (value.empty()) + recs->erase(key); + else + (*recs)[key] = value; + } + + if (!ok || recPos < len || size != lastread) { + wxLogWarning(_("invalid data in extended tar header")); + return false; + } + + return true; +} + +wxFileOffset wxTarInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + if (!IsOpened()) { + wxLogError(_("tar entry not open")); + m_lasterror = wxSTREAM_READ_ERROR; + } + if (!IsOk()) + return wxInvalidOffset; + + switch (mode) { + case wxFromStart: break; + case wxFromCurrent: pos += m_pos; break; + case wxFromEnd: pos += m_size; break; + } + + if (pos < 0 || m_parent_i_stream->SeekI(m_offset + pos) == wxInvalidOffset) + return wxInvalidOffset; + + m_pos = pos; + return m_pos; +} + +size_t wxTarInputStream::OnSysRead(void *buffer, size_t size) +{ + if (!IsOpened()) { + wxLogError(_("tar entry not open")); + m_lasterror = wxSTREAM_READ_ERROR; + } + if (!IsOk() || !size) + return 0; + + if (m_pos >= m_size) + size = 0; + else if (m_pos + size > m_size + (size_t)0) + size = m_size - m_pos; + + size_t lastread = m_parent_i_stream->Read(buffer, size).LastRead(); + m_pos += lastread; + + if (m_pos >= m_size) { + m_lasterror = wxSTREAM_EOF; + } else if (!m_parent_i_stream->IsOk()) { + // any other error will have been reported by the underlying stream + if (m_parent_i_stream->Eof()) + wxLogError(_("unexpected end of file")); + m_lasterror = wxSTREAM_READ_ERROR; + } + + return lastread; +} + + +///////////////////////////////////////////////////////////////////////////// +// Output stream + +wxTarOutputStream::wxTarOutputStream(wxOutputStream& stream, + wxTarFormat format /*=wxTAR_PAX*/, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveOutputStream(stream, conv) +{ + Init(format); +} + +wxTarOutputStream::wxTarOutputStream(wxOutputStream *stream, + wxTarFormat format /*=wxTAR_PAX*/, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveOutputStream(stream, conv) +{ + Init(format); +} + +void wxTarOutputStream::Init(wxTarFormat format) +{ + m_pos = wxInvalidOffset; + m_maxpos = wxInvalidOffset; + m_size = wxInvalidOffset; + m_headpos = wxInvalidOffset; + m_datapos = wxInvalidOffset; + m_tarstart = wxInvalidOffset; + m_tarsize = 0; + m_pax = format == wxTAR_PAX; + m_BlockingFactor = m_pax ? 10 : 20; + m_chksum = 0; + m_large = false; + m_hdr = new wxTarHeaderBlock; + m_hdr2 = NULL; + m_extendedHdr = NULL; + m_extendedSize = 0; + m_lasterror = m_parent_o_stream->GetLastError(); +} + +wxTarOutputStream::~wxTarOutputStream() +{ + if (m_tarsize) + Close(); + delete m_hdr; + delete m_hdr2; + delete [] m_extendedHdr; +} + +bool wxTarOutputStream::PutNextEntry(wxTarEntry *entry) +{ + wxTarEntryPtr_ e(entry); + + if (!CloseEntry()) + return false; + + if (!m_tarsize) { + wxLogNull nolog; + m_tarstart = m_parent_o_stream->TellO(); + } + + if (m_tarstart != wxInvalidOffset) + m_headpos = m_tarstart + m_tarsize; + + if (WriteHeaders(*e)) { + m_pos = 0; + m_maxpos = 0; + m_size = GetDataSize(*e); + if (m_tarstart != wxInvalidOffset) + m_datapos = m_tarstart + m_tarsize; + + // types that are not allowd any data + const char nodata[] = { + wxTAR_LNKTYPE, wxTAR_SYMTYPE, wxTAR_CHRTYPE, wxTAR_BLKTYPE, + wxTAR_DIRTYPE, wxTAR_FIFOTYPE, 0 + }; + int typeflag = e->GetTypeFlag(); + + // pax does now allow data for wxTAR_LNKTYPE + if (!m_pax || typeflag != wxTAR_LNKTYPE) + if (strchr(nodata, typeflag) != NULL) + CloseEntry(); + } + + return IsOk(); +} + +bool wxTarOutputStream::PutNextEntry(const wxString& name, + const wxDateTime& dt, + wxFileOffset size) +{ + return PutNextEntry(new wxTarEntry(name, dt, size)); +} + +bool wxTarOutputStream::PutNextDirEntry(const wxString& name, + const wxDateTime& dt) +{ + wxTarEntry *entry = new wxTarEntry(name, dt); + entry->SetIsDir(); + return PutNextEntry(entry); +} + +bool wxTarOutputStream::PutNextEntry(wxArchiveEntry *entry) +{ + wxTarEntry *tarEntry = wxStaticCast(entry, wxTarEntry); + if (!tarEntry) + delete entry; + return PutNextEntry(tarEntry); +} + +bool wxTarOutputStream::CopyEntry(wxTarEntry *entry, + wxTarInputStream& inputStream) +{ + if (PutNextEntry(entry)) + Write(inputStream); + return IsOk() && inputStream.Eof(); +} + +bool wxTarOutputStream::CopyEntry(wxArchiveEntry *entry, + wxArchiveInputStream& inputStream) +{ + if (PutNextEntry(entry)) + Write(inputStream); + return IsOk() && inputStream.Eof(); +} + +bool wxTarOutputStream::CloseEntry() +{ + if (!IsOpened()) + return true; + + if (m_pos < m_maxpos) { + wxASSERT(m_parent_o_stream->IsSeekable()); + m_parent_o_stream->SeekO(m_datapos + m_maxpos); + m_lasterror = m_parent_o_stream->GetLastError(); + m_pos = m_maxpos; + } + + if (IsOk()) { + wxFileOffset size = RoundUpSize(m_pos); + if (size > m_pos) { + memset(m_hdr, 0, size - m_pos); + m_parent_o_stream->Write(m_hdr, size - m_pos); + m_lasterror = m_parent_o_stream->GetLastError(); + } + m_tarsize += size; + } + + if (IsOk() && m_pos != m_size) + ModifyHeader(); + + m_pos = wxInvalidOffset; + m_maxpos = wxInvalidOffset; + m_size = wxInvalidOffset; + m_headpos = wxInvalidOffset; + m_datapos = wxInvalidOffset; + + return IsOk(); +} + +bool wxTarOutputStream::Close() +{ + if (!CloseEntry()) + return false; + + memset(m_hdr, 0, sizeof(*m_hdr)); + int count = (RoundUpSize(m_tarsize + 2 * TAR_BLOCKSIZE, m_BlockingFactor) + - m_tarsize) / TAR_BLOCKSIZE; + while (count--) + m_parent_o_stream->Write(m_hdr, TAR_BLOCKSIZE); + + m_tarsize = 0; + m_tarstart = wxInvalidOffset; + m_lasterror = m_parent_o_stream->GetLastError(); + return IsOk(); +} + +bool wxTarOutputStream::WriteHeaders(wxTarEntry& entry) +{ + memset(m_hdr, 0, sizeof(*m_hdr)); + + SetHeaderPath(entry.GetName(wxPATH_UNIX)); + + SetHeaderNumber(TAR_MODE, entry.GetMode()); + SetHeaderNumber(TAR_UID, entry.GetUserId()); + SetHeaderNumber(TAR_GID, entry.GetGroupId()); + + if (entry.GetSize() == wxInvalidOffset) + entry.SetSize(0); + m_large = !SetHeaderNumber(TAR_SIZE, entry.GetSize()); + + SetHeaderDate(_T("mtime"), entry.GetDateTime()); + if (entry.GetAccessTime().IsValid()) + SetHeaderDate(_T("atime"), entry.GetAccessTime()); + if (entry.GetCreateTime().IsValid()) + SetHeaderDate(_T("ctime"), entry.GetCreateTime()); + + *m_hdr->Get(TAR_TYPEFLAG) = char(entry.GetTypeFlag()); + + strcpy(m_hdr->Get(TAR_MAGIC), USTAR_MAGIC); + strcpy(m_hdr->Get(TAR_VERSION), USTAR_VERSION); + + SetHeaderString(TAR_LINKNAME, entry.GetLinkName()); + SetHeaderString(TAR_UNAME, entry.GetUserName()); + SetHeaderString(TAR_GNAME, entry.GetGroupName()); + + if (~entry.GetDevMajor()) + SetHeaderNumber(TAR_DEVMAJOR, entry.GetDevMajor()); + if (~entry.GetDevMinor()) + SetHeaderNumber(TAR_DEVMINOR, entry.GetDevMinor()); + + m_chksum = m_hdr->Sum(); + m_hdr->SetOctal(TAR_CHKSUM, m_chksum); + if (!m_large) + m_chksum -= m_hdr->SumField(TAR_SIZE); + + // The main header is now fully prepared so we know what extended headers + // (if any) will be needed. Output any extended headers before writing + // the main header. + if (m_extendedHdr && *m_extendedHdr) { + wxASSERT(m_pax); + // the extended headers are written to the tar as a file entry, + // so prepare a regular header block for the pseudo-file. + if (!m_hdr2) + m_hdr2 = new wxTarHeaderBlock; + memset(m_hdr2, 0, sizeof(*m_hdr2)); + + // an old tar that doesn't understand extended headers will + // extract it as a file, so give these fields reasonable values + // so that the user will have access to read and remove it. + m_hdr2->SetPath(PaxHeaderPath(_T("%d/PaxHeaders.%p/%f"), + entry.GetName(wxPATH_UNIX)), GetConv()); + m_hdr2->SetOctal(TAR_MODE, 0600); + strcpy(m_hdr2->Get(TAR_UID), m_hdr->Get(TAR_UID)); + strcpy(m_hdr2->Get(TAR_GID), m_hdr->Get(TAR_GID)); + size_t length = strlen(m_extendedHdr); + m_hdr2->SetOctal(TAR_SIZE, length); + strcpy(m_hdr2->Get(TAR_MTIME), m_hdr->Get(TAR_MTIME)); + *m_hdr2->Get(TAR_TYPEFLAG) = 'x'; + strcpy(m_hdr2->Get(TAR_MAGIC), USTAR_MAGIC); + strcpy(m_hdr2->Get(TAR_VERSION), USTAR_VERSION); + strcpy(m_hdr2->Get(TAR_UNAME), m_hdr->Get(TAR_UNAME)); + strcpy(m_hdr2->Get(TAR_GNAME), m_hdr->Get(TAR_GNAME)); + + m_hdr2->SetOctal(TAR_CHKSUM, m_hdr2->Sum()); + + m_hdr2->Write(*m_parent_o_stream); + m_tarsize += TAR_BLOCKSIZE; + + size_t rounded = RoundUpSize(length); + memset(m_extendedHdr + length, 0, rounded - length); + m_parent_o_stream->Write(m_extendedHdr, rounded); + m_tarsize += rounded; + + *m_extendedHdr = 0; + + // update m_headpos which is used to seek back to fix up the file + // length if it is not known in advance + if (m_tarstart != wxInvalidOffset) + m_headpos = m_tarstart + m_tarsize; + } + + // if don't have extended headers just report error + if (!m_badfit.empty()) { + wxASSERT(!m_pax); + wxLogWarning(_("%s did not fit the tar header for entry '%s'"), + m_badfit.c_str(), entry.GetName().c_str()); + m_badfit.clear(); + } + + m_hdr->Write(*m_parent_o_stream); + m_tarsize += TAR_BLOCKSIZE; + m_lasterror = m_parent_o_stream->GetLastError(); + + return IsOk(); +} + +wxString wxTarOutputStream::PaxHeaderPath(const wxString& format, + const wxString& path) +{ + wxString d = path.BeforeLast(_T('/')); + wxString f = path.AfterLast(_T('/')); + wxString ret; + + if (d.empty()) + d = _T("."); + + ret.reserve(format.length() + path.length() + 16); + + size_t begin = 0; + size_t end; + + for (;;) { + end = format.find('%', begin); + if (end == wxString::npos || end + 1 >= format.length()) + break; + ret << format.substr(begin, end - begin); + switch (format[end + 1]) { + case 'd': ret << d; break; + case 'f': ret << f; break; + case 'p': ret << wxGetProcessId(); break; + case '%': ret << _T("%"); break; + } + begin = end + 2; + } + + ret << format.substr(begin); + + return ret; +} + +bool wxTarOutputStream::ModifyHeader() +{ + wxFileOffset originalPos = wxInvalidOffset; + wxFileOffset sizePos = wxInvalidOffset; + + if (!m_large && m_headpos != wxInvalidOffset + && m_parent_o_stream->IsSeekable()) + { + wxLogNull nolog; + originalPos = m_parent_o_stream->TellO(); + if (originalPos != wxInvalidOffset) + sizePos = + m_parent_o_stream->SeekO(m_headpos + m_hdr->Offset(TAR_SIZE)); + } + + if (sizePos == wxInvalidOffset || !m_hdr->SetOctal(TAR_SIZE, m_pos)) { + wxLogError(_("incorrect size given for tar entry")); + m_lasterror = wxSTREAM_WRITE_ERROR; + return false; + } + + m_chksum += m_hdr->SumField(TAR_SIZE); + m_hdr->SetOctal(TAR_CHKSUM, m_chksum); + wxFileOffset sumPos = m_headpos + m_hdr->Offset(TAR_CHKSUM); + + return + m_hdr->WriteField(*m_parent_o_stream, TAR_SIZE) && + m_parent_o_stream->SeekO(sumPos) == sumPos && + m_hdr->WriteField(*m_parent_o_stream, TAR_CHKSUM) && + m_parent_o_stream->SeekO(originalPos) == originalPos; +} + +void wxTarOutputStream::SetHeaderPath(const wxString& name) +{ + if (!m_hdr->SetPath(name, GetConv()) || (m_pax && !name.IsAscii())) + SetExtendedHeader(_T("path"), name); +} + +bool wxTarOutputStream::SetHeaderNumber(int id, wxTarNumber n) +{ + if (m_hdr->SetOctal(id, n)) { + return true; + } else { + SetExtendedHeader(m_hdr->Name(id), wxLongLong(n).ToString()); + return false; + } +} + +void wxTarOutputStream::SetHeaderString(int id, const wxString& str) +{ + strncpy(m_hdr->Get(id), str.mb_str(GetConv()), m_hdr->Len(id)); + if (str.length() > m_hdr->Len(id)) + SetExtendedHeader(m_hdr->Name(id), str); +} + +void wxTarOutputStream::SetHeaderDate(const wxString& key, + const wxDateTime& datetime) +{ + wxLongLong ll = datetime.IsValid() ? datetime.GetValue() : wxLongLong(0); + wxLongLong secs = ll / 1000L; + + if (key != _T("mtime") + || !m_hdr->SetOctal(TAR_MTIME, wxTarNumber(secs.GetValue())) + || secs <= 0 || secs >= 0x7fffffff) + { + wxString str; + if (ll >= LONG_MIN && ll <= LONG_MAX) { + str.Printf(_T("%g"), ll.ToLong() / 1000.0); + } else { + str = ll.ToString(); + str.insert(str.end() - 3, '.'); + } + SetExtendedHeader(key, str); + } +} + +void wxTarOutputStream::SetExtendedHeader(const wxString& key, + const wxString& value) +{ + if (m_pax) { + const wxWX2WCbuf wide_key = key.wc_str(GetConv()); + const wxCharBuffer utf_key = wxConvUTF8.cWC2MB(wide_key); + + const wxWX2WCbuf wide_value = value.wc_str(GetConv()); + const wxCharBuffer utf_value = wxConvUTF8.cWC2MB(wide_value); + + // a small buffer to format the length field in + char buf[32]; + // length of "99=\n" + unsigned long length = strlen(utf_value) + strlen(utf_key) + 5; + sprintf(buf, "%lu", length); + // the length includes itself + size_t lenlen = strlen(buf); + if (lenlen != 2) { + length += lenlen - 2; + sprintf(buf, "%lu", length); + if (strlen(buf) > lenlen) + sprintf(buf, "%lu", ++length); + } + + // reallocate m_extendedHdr if it's not big enough + if (m_extendedSize < length) { + size_t rounded = RoundUpSize(length); + m_extendedSize <<= 1; + if (rounded > m_extendedSize) + m_extendedSize = rounded; + char *oldHdr = m_extendedHdr; + m_extendedHdr = new char[m_extendedSize]; + if (oldHdr) { + strcpy(m_extendedHdr, oldHdr); + delete oldHdr; + } else { + *m_extendedHdr = 0; + } + } + + // append the new record + char *append = strchr(m_extendedHdr, 0); + sprintf(append, "%s %s=%s\012", buf, + (const char*)utf_key, (const char*)utf_value); + } + else { + // if not pax then make a list of fields to report as errors + if (!m_badfit.empty()) + m_badfit += _T(", "); + m_badfit += key; + } +} + +void wxTarOutputStream::Sync() +{ + m_parent_o_stream->Sync(); +} + +wxFileOffset wxTarOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + if (!IsOpened()) { + wxLogError(_("tar entry not open")); + m_lasterror = wxSTREAM_WRITE_ERROR; + } + if (!IsOk() || m_datapos == wxInvalidOffset) + return wxInvalidOffset; + + switch (mode) { + case wxFromStart: break; + case wxFromCurrent: pos += m_pos; break; + case wxFromEnd: pos += m_maxpos; break; + } + + if (pos < 0 || m_parent_o_stream->SeekO(m_datapos + pos) == wxInvalidOffset) + return wxInvalidOffset; + + m_pos = pos; + return m_pos; +} + +size_t wxTarOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + if (!IsOpened()) { + wxLogError(_("tar entry not open")); + m_lasterror = wxSTREAM_WRITE_ERROR; + } + if (!IsOk() || !size) + return 0; + + size_t lastwrite = m_parent_o_stream->Write(buffer, size).LastWrite(); + m_pos += lastwrite; + if (m_pos > m_maxpos) + m_maxpos = m_pos; + + if (lastwrite != size) + m_lasterror = wxSTREAM_WRITE_ERROR; + + return lastwrite; +} + +#endif // wxUSE_TARSTREAM diff --git a/Source/3rd Party/wx/src/common/tbarbase.cpp b/Source/3rd Party/wx/src/common/tbarbase.cpp index 2b1459c6b..084d17c06 100644 --- a/Source/3rd Party/wx/src/common/tbarbase.cpp +++ b/Source/3rd Party/wx/src/common/tbarbase.cpp @@ -1,746 +1,746 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/tbarbase.cpp -// Purpose: wxToolBarBase implementation -// Author: Julian Smart -// Modified by: VZ at 11.12.99 (wxScrollableToolBar split off) -// Created: 04/01/98 -// RCS-ID: $Id: tbarbase.cpp 42840 2006-10-31 13:09:08Z VZ $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_TOOLBAR - -#include "wx/toolbar.h" - -#ifndef WX_PRECOMP - #include "wx/control.h" - #include "wx/frame.h" - #include "wx/settings.h" - #include "wx/image.h" -#endif - -// ---------------------------------------------------------------------------- -// wxWidgets macros -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxToolBarBase, wxControl) -END_EVENT_TABLE() - -#include "wx/listimpl.cpp" - -WX_DEFINE_LIST(wxToolBarToolsList) - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxToolBarToolBase -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxToolBarToolBase, wxObject) - -bool wxToolBarToolBase::Enable(bool enable) -{ - if ( m_enabled == enable ) - return false; - - m_enabled = enable; - - return true; -} - -bool wxToolBarToolBase::Toggle(bool toggle) -{ - wxASSERT_MSG( CanBeToggled(), _T("can't toggle this tool") ); - - if ( m_toggled == toggle ) - return false; - - m_toggled = toggle; - - return true; -} - -bool wxToolBarToolBase::SetToggle(bool toggle) -{ - wxItemKind kind = toggle ? wxITEM_CHECK : wxITEM_NORMAL; - if ( m_kind == kind ) - return false; - - m_kind = kind; - - return true; -} - -bool wxToolBarToolBase::SetShortHelp(const wxString& help) -{ - if ( m_shortHelpString == help ) - return false; - - m_shortHelpString = help; - - return true; -} - -bool wxToolBarToolBase::SetLongHelp(const wxString& help) -{ - if ( m_longHelpString == help ) - return false; - - m_longHelpString = help; - - return true; -} - -// ---------------------------------------------------------------------------- -// wxToolBarBase adding/deleting items -// ---------------------------------------------------------------------------- - -wxToolBarBase::wxToolBarBase() -{ - // the list owns the pointers - m_xMargin = m_yMargin = 0; - m_maxRows = m_maxCols = 0; - m_toolPacking = m_toolSeparation = 0; - m_defaultWidth = 16; - m_defaultHeight = 15; -} - -void wxToolBarBase::FixupStyle() -{ - if ( !HasFlag(wxTB_TOP | wxTB_LEFT | wxTB_RIGHT | wxTB_BOTTOM) ) - { - // this is the default - m_windowStyle |= wxTB_TOP; - } -} - -wxToolBarToolBase *wxToolBarBase::DoAddTool(int id, - const wxString& label, - const wxBitmap& bitmap, - const wxBitmap& bmpDisabled, - wxItemKind kind, - const wxString& shortHelp, - const wxString& longHelp, - wxObject *clientData, - wxCoord WXUNUSED(xPos), - wxCoord WXUNUSED(yPos)) -{ - InvalidateBestSize(); - return InsertTool(GetToolsCount(), id, label, bitmap, bmpDisabled, - kind, shortHelp, longHelp, clientData); -} - -wxToolBarToolBase *wxToolBarBase::InsertTool(size_t pos, - int id, - const wxString& label, - const wxBitmap& bitmap, - const wxBitmap& bmpDisabled, - wxItemKind kind, - const wxString& shortHelp, - const wxString& longHelp, - wxObject *clientData) -{ - wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, - _T("invalid position in wxToolBar::InsertTool()") ); - - wxToolBarToolBase *tool = CreateTool(id, label, bitmap, bmpDisabled, kind, - clientData, shortHelp, longHelp); - - if ( !InsertTool(pos, tool) ) - { - delete tool; - - return NULL; - } - - return tool; -} - -wxToolBarToolBase *wxToolBarBase::AddTool(wxToolBarToolBase *tool) -{ - return InsertTool(GetToolsCount(), tool); -} - -wxToolBarToolBase * -wxToolBarBase::InsertTool(size_t pos, wxToolBarToolBase *tool) -{ - wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, - _T("invalid position in wxToolBar::InsertTool()") ); - - if ( !tool || !DoInsertTool(pos, tool) ) - { - return NULL; - } - - m_tools.Insert(pos, tool); - - return tool; -} - -wxToolBarToolBase *wxToolBarBase::AddControl(wxControl *control) -{ - return InsertControl(GetToolsCount(), control); -} - -wxToolBarToolBase *wxToolBarBase::InsertControl(size_t pos, wxControl *control) -{ - wxCHECK_MSG( control, (wxToolBarToolBase *)NULL, - _T("toolbar: can't insert NULL control") ); - - wxCHECK_MSG( control->GetParent() == this, (wxToolBarToolBase *)NULL, - _T("control must have toolbar as parent") ); - - wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, - _T("invalid position in wxToolBar::InsertControl()") ); - - wxToolBarToolBase *tool = CreateTool(control); - - if ( !InsertTool(pos, tool) ) - { - delete tool; - - return NULL; - } - - return tool; -} - -wxControl *wxToolBarBase::FindControl( int id ) -{ - for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); - node; - node = node->GetNext() ) - { - const wxToolBarToolBase * const tool = node->GetData(); - if ( tool->IsControl() ) - { - wxControl * const control = tool->GetControl(); - - if ( !control ) - { - wxFAIL_MSG( _T("NULL control in toolbar?") ); - } - else if ( control->GetId() == id ) - { - // found - return control; - } - } - } - - return NULL; -} - -wxToolBarToolBase *wxToolBarBase::AddSeparator() -{ - return InsertSeparator(GetToolsCount()); -} - -wxToolBarToolBase *wxToolBarBase::InsertSeparator(size_t pos) -{ - wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, - _T("invalid position in wxToolBar::InsertSeparator()") ); - - wxToolBarToolBase *tool = CreateTool(wxID_SEPARATOR, - wxEmptyString, - wxNullBitmap, wxNullBitmap, - wxITEM_SEPARATOR, (wxObject *)NULL, - wxEmptyString, wxEmptyString); - - if ( !tool || !DoInsertTool(pos, tool) ) - { - delete tool; - - return NULL; - } - - m_tools.Insert(pos, tool); - - return tool; -} - -wxToolBarToolBase *wxToolBarBase::RemoveTool(int id) -{ - size_t pos = 0; - wxToolBarToolsList::compatibility_iterator node; - for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) - { - if ( node->GetData()->GetId() == id ) - break; - - pos++; - } - - if ( !node ) - { - // don't give any error messages - sometimes we might call RemoveTool() - // without knowing whether the tool is or not in the toolbar - return (wxToolBarToolBase *)NULL; - } - - wxToolBarToolBase *tool = node->GetData(); - if ( !DoDeleteTool(pos, tool) ) - { - return (wxToolBarToolBase *)NULL; - } - - m_tools.Erase(node); - - return tool; -} - -bool wxToolBarBase::DeleteToolByPos(size_t pos) -{ - wxCHECK_MSG( pos < GetToolsCount(), false, - _T("invalid position in wxToolBar::DeleteToolByPos()") ); - - wxToolBarToolsList::compatibility_iterator node = m_tools.Item(pos); - - if ( !DoDeleteTool(pos, node->GetData()) ) - { - return false; - } - - delete node->GetData(); - m_tools.Erase(node); - - return true; -} - -bool wxToolBarBase::DeleteTool(int id) -{ - size_t pos = 0; - wxToolBarToolsList::compatibility_iterator node; - for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) - { - if ( node->GetData()->GetId() == id ) - break; - - pos++; - } - - if ( !node || !DoDeleteTool(pos, node->GetData()) ) - { - return false; - } - - delete node->GetData(); - m_tools.Erase(node); - - return true; -} - -wxToolBarToolBase *wxToolBarBase::FindById(int id) const -{ - wxToolBarToolBase *tool = (wxToolBarToolBase *)NULL; - - for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); - node; - node = node->GetNext() ) - { - tool = node->GetData(); - if ( tool->GetId() == id ) - { - // found - break; - } - - tool = NULL; - } - - return tool; -} - -void wxToolBarBase::UnToggleRadioGroup(wxToolBarToolBase *tool) -{ - wxCHECK_RET( tool, _T("NULL tool in wxToolBarTool::UnToggleRadioGroup") ); - - if ( !tool->IsButton() || tool->GetKind() != wxITEM_RADIO ) - return; - - wxToolBarToolsList::compatibility_iterator node = m_tools.Find(tool); - wxCHECK_RET( node, _T("invalid tool in wxToolBarTool::UnToggleRadioGroup") ); - - wxToolBarToolsList::compatibility_iterator nodeNext = node->GetNext(); - while ( nodeNext ) - { - wxToolBarToolBase *toolNext = nodeNext->GetData(); - - if ( !toolNext->IsButton() || toolNext->GetKind() != wxITEM_RADIO ) - break; - - if ( toolNext->Toggle(false) ) - { - DoToggleTool(toolNext, false); - } - - nodeNext = nodeNext->GetNext(); - } - - wxToolBarToolsList::compatibility_iterator nodePrev = node->GetPrevious(); - while ( nodePrev ) - { - wxToolBarToolBase *toolNext = nodePrev->GetData(); - - if ( !toolNext->IsButton() || toolNext->GetKind() != wxITEM_RADIO ) - break; - - if ( toolNext->Toggle(false) ) - { - DoToggleTool(toolNext, false); - } - - nodePrev = nodePrev->GetPrevious(); - } -} - -void wxToolBarBase::ClearTools() -{ - while ( GetToolsCount() ) - { - DeleteToolByPos(0); - } -} - -bool wxToolBarBase::Realize() -{ - return true; -} - -wxToolBarBase::~wxToolBarBase() -{ - WX_CLEAR_LIST(wxToolBarToolsList, m_tools); - - // notify the frame that it doesn't have a tool bar any longer to avoid - // dangling pointers - wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); - if ( frame && frame->GetToolBar() == this ) - { - frame->SetToolBar(NULL); - } -} - -// ---------------------------------------------------------------------------- -// wxToolBarBase tools state -// ---------------------------------------------------------------------------- - -void wxToolBarBase::EnableTool(int id, bool enable) -{ - wxToolBarToolBase *tool = FindById(id); - if ( tool ) - { - if ( tool->Enable(enable) ) - { - DoEnableTool(tool, enable); - } - } -} - -void wxToolBarBase::ToggleTool(int id, bool toggle) -{ - wxToolBarToolBase *tool = FindById(id); - if ( tool && tool->CanBeToggled() ) - { - if ( tool->Toggle(toggle) ) - { - UnToggleRadioGroup(tool); - DoToggleTool(tool, toggle); - } - } -} - -void wxToolBarBase::SetToggle(int id, bool toggle) -{ - wxToolBarToolBase *tool = FindById(id); - if ( tool ) - { - if ( tool->SetToggle(toggle) ) - { - DoSetToggle(tool, toggle); - } - } -} - -void wxToolBarBase::SetToolShortHelp(int id, const wxString& help) -{ - wxToolBarToolBase *tool = FindById(id); - if ( tool ) - { - (void)tool->SetShortHelp(help); - } -} - -void wxToolBarBase::SetToolLongHelp(int id, const wxString& help) -{ - wxToolBarToolBase *tool = FindById(id); - if ( tool ) - { - (void)tool->SetLongHelp(help); - } -} - -wxObject *wxToolBarBase::GetToolClientData(int id) const -{ - wxToolBarToolBase *tool = FindById(id); - - return tool ? tool->GetClientData() : (wxObject *)NULL; -} - -void wxToolBarBase::SetToolClientData(int id, wxObject *clientData) -{ - wxToolBarToolBase *tool = FindById(id); - - wxCHECK_RET( tool, _T("no such tool in wxToolBar::SetToolClientData") ); - - tool->SetClientData(clientData); -} - -int wxToolBarBase::GetToolPos(int id) const -{ - size_t pos = 0; - wxToolBarToolsList::compatibility_iterator node; - - for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) - { - if ( node->GetData()->GetId() == id ) - return pos; - - pos++; - } - - return wxNOT_FOUND; -} - -bool wxToolBarBase::GetToolState(int id) const -{ - wxToolBarToolBase *tool = FindById(id); - wxCHECK_MSG( tool, false, _T("no such tool") ); - - return tool->IsToggled(); -} - -bool wxToolBarBase::GetToolEnabled(int id) const -{ - wxToolBarToolBase *tool = FindById(id); - wxCHECK_MSG( tool, false, _T("no such tool") ); - - return tool->IsEnabled(); -} - -wxString wxToolBarBase::GetToolShortHelp(int id) const -{ - wxToolBarToolBase *tool = FindById(id); - wxCHECK_MSG( tool, wxEmptyString, _T("no such tool") ); - - return tool->GetShortHelp(); -} - -wxString wxToolBarBase::GetToolLongHelp(int id) const -{ - wxToolBarToolBase *tool = FindById(id); - wxCHECK_MSG( tool, wxEmptyString, _T("no such tool") ); - - return tool->GetLongHelp(); -} - -// ---------------------------------------------------------------------------- -// wxToolBarBase geometry -// ---------------------------------------------------------------------------- - -void wxToolBarBase::SetMargins(int x, int y) -{ - m_xMargin = x; - m_yMargin = y; -} - -void wxToolBarBase::SetRows(int WXUNUSED(nRows)) -{ - // nothing -} - -// ---------------------------------------------------------------------------- -// event processing -// ---------------------------------------------------------------------------- - -// Only allow toggle if returns true -bool wxToolBarBase::OnLeftClick(int id, bool toggleDown) -{ - wxCommandEvent event(wxEVT_COMMAND_TOOL_CLICKED, id); - event.SetEventObject(this); - - // we use SetInt() to make wxCommandEvent::IsChecked() return toggleDown - event.SetInt((int)toggleDown); - - // and SetExtraLong() for backwards compatibility - event.SetExtraLong((long)toggleDown); - - // Send events to this toolbar instead (and thence up the window hierarchy) - GetEventHandler()->ProcessEvent(event); - - return true; -} - -// Call when right button down. -void wxToolBarBase::OnRightClick(int id, - long WXUNUSED(x), - long WXUNUSED(y)) -{ - wxCommandEvent event(wxEVT_COMMAND_TOOL_RCLICKED, id); - event.SetEventObject(this); - event.SetInt(id); - - GetEventHandler()->ProcessEvent(event); -} - -// Called when the mouse cursor enters a tool bitmap (no button pressed). -// Argument is wxID_ANY if mouse is exiting the toolbar. -// Note that for this event, the id of the window is used, -// and the integer parameter of wxCommandEvent is used to retrieve -// the tool id. -void wxToolBarBase::OnMouseEnter(int id) -{ - wxCommandEvent event(wxEVT_COMMAND_TOOL_ENTER, GetId()); - event.SetEventObject(this); - event.SetInt(id); - - wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); - if( frame ) - { - wxString help; - wxToolBarToolBase* tool = id == wxID_ANY ? (wxToolBarToolBase*)NULL : FindById(id); - if(tool) - help = tool->GetLongHelp(); - frame->DoGiveHelp( help, id != wxID_ANY ); - } - - (void)GetEventHandler()->ProcessEvent(event); -} - -// ---------------------------------------------------------------------------- -// UI updates -// ---------------------------------------------------------------------------- - -// Do the toolbar button updates (check for EVT_UPDATE_UI handlers) -void wxToolBarBase::UpdateWindowUI(long flags) -{ - wxWindowBase::UpdateWindowUI(flags); - - // There is no sense in updating the toolbar UI - // if the parent window is about to get destroyed - wxWindow *tlw = wxGetTopLevelParent( this ); - if (tlw && wxPendingDelete.Member( tlw )) - return; - - wxEvtHandler* evtHandler = GetEventHandler() ; - - for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); - node; - node = node->GetNext() ) - { - int id = node->GetData()->GetId(); - - wxUpdateUIEvent event(id); - event.SetEventObject(this); - - if ( evtHandler->ProcessEvent(event) ) - { - if ( event.GetSetEnabled() ) - EnableTool(id, event.GetEnabled()); - if ( event.GetSetChecked() ) - ToggleTool(id, event.GetChecked()); -#if 0 - if ( event.GetSetText() ) - // Set tooltip? -#endif // 0 - } - } -} - -#if wxUSE_IMAGE - -/* - * Make a greyed-out image suitable for disabled buttons. - * This code is adapted from wxNewBitmapButton in FL. - */ - -bool wxCreateGreyedImage(const wxImage& src, wxImage& dst) -{ - dst = src.Copy(); - - unsigned char rBg, gBg, bBg; - if ( src.HasMask() ) - { - src.GetOrFindMaskColour(&rBg, &gBg, &bBg); - dst.SetMaskColour(rBg, gBg, bBg); - } - else // assuming the pixels along the edges are of the background color - { - rBg = src.GetRed(0, 0); - gBg = src.GetGreen(0, 0); - bBg = src.GetBlue(0, 0); - } - - const wxColour colBg(rBg, gBg, bBg); - - const wxColour colDark = wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW); - const wxColour colLight = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT); - - // Second attempt, just making things monochrome - const int width = src.GetWidth(); - const int height = src.GetHeight(); - - for ( int x = 0; x < width; x++ ) - { - for ( int y = 0; y < height; y++ ) - { - const int r = src.GetRed(x, y); - const int g = src.GetGreen(x, y); - const int b = src.GetBlue(x, y); - - if ( r == rBg && g == gBg && b == bBg ) - { - // Leave the background colour as-is - continue; - } - - // Change light things to the background colour - wxColour col; - if ( r >= (colLight.Red() - 50) && - g >= (colLight.Green() - 50) && - b >= (colLight.Blue() - 50) ) - { - col = colBg; - } - else // Change dark things to really dark - { - col = colDark; - } - - dst.SetRGB(x, y, col.Red(), col.Green(), col.Blue()); - } - } - - return true; -} - -#endif // wxUSE_IMAGE - -#endif // wxUSE_TOOLBAR +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/tbarbase.cpp +// Purpose: wxToolBarBase implementation +// Author: Julian Smart +// Modified by: VZ at 11.12.99 (wxScrollableToolBar split off) +// Created: 04/01/98 +// RCS-ID: $Id: tbarbase.cpp 42840 2006-10-31 13:09:08Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TOOLBAR + +#include "wx/toolbar.h" + +#ifndef WX_PRECOMP + #include "wx/control.h" + #include "wx/frame.h" + #include "wx/settings.h" + #include "wx/image.h" +#endif + +// ---------------------------------------------------------------------------- +// wxWidgets macros +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxToolBarBase, wxControl) +END_EVENT_TABLE() + +#include "wx/listimpl.cpp" + +WX_DEFINE_LIST(wxToolBarToolsList) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxToolBarToolBase +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxToolBarToolBase, wxObject) + +bool wxToolBarToolBase::Enable(bool enable) +{ + if ( m_enabled == enable ) + return false; + + m_enabled = enable; + + return true; +} + +bool wxToolBarToolBase::Toggle(bool toggle) +{ + wxASSERT_MSG( CanBeToggled(), _T("can't toggle this tool") ); + + if ( m_toggled == toggle ) + return false; + + m_toggled = toggle; + + return true; +} + +bool wxToolBarToolBase::SetToggle(bool toggle) +{ + wxItemKind kind = toggle ? wxITEM_CHECK : wxITEM_NORMAL; + if ( m_kind == kind ) + return false; + + m_kind = kind; + + return true; +} + +bool wxToolBarToolBase::SetShortHelp(const wxString& help) +{ + if ( m_shortHelpString == help ) + return false; + + m_shortHelpString = help; + + return true; +} + +bool wxToolBarToolBase::SetLongHelp(const wxString& help) +{ + if ( m_longHelpString == help ) + return false; + + m_longHelpString = help; + + return true; +} + +// ---------------------------------------------------------------------------- +// wxToolBarBase adding/deleting items +// ---------------------------------------------------------------------------- + +wxToolBarBase::wxToolBarBase() +{ + // the list owns the pointers + m_xMargin = m_yMargin = 0; + m_maxRows = m_maxCols = 0; + m_toolPacking = m_toolSeparation = 0; + m_defaultWidth = 16; + m_defaultHeight = 15; +} + +void wxToolBarBase::FixupStyle() +{ + if ( !HasFlag(wxTB_TOP | wxTB_LEFT | wxTB_RIGHT | wxTB_BOTTOM) ) + { + // this is the default + m_windowStyle |= wxTB_TOP; + } +} + +wxToolBarToolBase *wxToolBarBase::DoAddTool(int id, + const wxString& label, + const wxBitmap& bitmap, + const wxBitmap& bmpDisabled, + wxItemKind kind, + const wxString& shortHelp, + const wxString& longHelp, + wxObject *clientData, + wxCoord WXUNUSED(xPos), + wxCoord WXUNUSED(yPos)) +{ + InvalidateBestSize(); + return InsertTool(GetToolsCount(), id, label, bitmap, bmpDisabled, + kind, shortHelp, longHelp, clientData); +} + +wxToolBarToolBase *wxToolBarBase::InsertTool(size_t pos, + int id, + const wxString& label, + const wxBitmap& bitmap, + const wxBitmap& bmpDisabled, + wxItemKind kind, + const wxString& shortHelp, + const wxString& longHelp, + wxObject *clientData) +{ + wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, + _T("invalid position in wxToolBar::InsertTool()") ); + + wxToolBarToolBase *tool = CreateTool(id, label, bitmap, bmpDisabled, kind, + clientData, shortHelp, longHelp); + + if ( !InsertTool(pos, tool) ) + { + delete tool; + + return NULL; + } + + return tool; +} + +wxToolBarToolBase *wxToolBarBase::AddTool(wxToolBarToolBase *tool) +{ + return InsertTool(GetToolsCount(), tool); +} + +wxToolBarToolBase * +wxToolBarBase::InsertTool(size_t pos, wxToolBarToolBase *tool) +{ + wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, + _T("invalid position in wxToolBar::InsertTool()") ); + + if ( !tool || !DoInsertTool(pos, tool) ) + { + return NULL; + } + + m_tools.Insert(pos, tool); + + return tool; +} + +wxToolBarToolBase *wxToolBarBase::AddControl(wxControl *control) +{ + return InsertControl(GetToolsCount(), control); +} + +wxToolBarToolBase *wxToolBarBase::InsertControl(size_t pos, wxControl *control) +{ + wxCHECK_MSG( control, (wxToolBarToolBase *)NULL, + _T("toolbar: can't insert NULL control") ); + + wxCHECK_MSG( control->GetParent() == this, (wxToolBarToolBase *)NULL, + _T("control must have toolbar as parent") ); + + wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, + _T("invalid position in wxToolBar::InsertControl()") ); + + wxToolBarToolBase *tool = CreateTool(control); + + if ( !InsertTool(pos, tool) ) + { + delete tool; + + return NULL; + } + + return tool; +} + +wxControl *wxToolBarBase::FindControl( int id ) +{ + for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); + node; + node = node->GetNext() ) + { + const wxToolBarToolBase * const tool = node->GetData(); + if ( tool->IsControl() ) + { + wxControl * const control = tool->GetControl(); + + if ( !control ) + { + wxFAIL_MSG( _T("NULL control in toolbar?") ); + } + else if ( control->GetId() == id ) + { + // found + return control; + } + } + } + + return NULL; +} + +wxToolBarToolBase *wxToolBarBase::AddSeparator() +{ + return InsertSeparator(GetToolsCount()); +} + +wxToolBarToolBase *wxToolBarBase::InsertSeparator(size_t pos) +{ + wxCHECK_MSG( pos <= GetToolsCount(), (wxToolBarToolBase *)NULL, + _T("invalid position in wxToolBar::InsertSeparator()") ); + + wxToolBarToolBase *tool = CreateTool(wxID_SEPARATOR, + wxEmptyString, + wxNullBitmap, wxNullBitmap, + wxITEM_SEPARATOR, (wxObject *)NULL, + wxEmptyString, wxEmptyString); + + if ( !tool || !DoInsertTool(pos, tool) ) + { + delete tool; + + return NULL; + } + + m_tools.Insert(pos, tool); + + return tool; +} + +wxToolBarToolBase *wxToolBarBase::RemoveTool(int id) +{ + size_t pos = 0; + wxToolBarToolsList::compatibility_iterator node; + for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) + { + if ( node->GetData()->GetId() == id ) + break; + + pos++; + } + + if ( !node ) + { + // don't give any error messages - sometimes we might call RemoveTool() + // without knowing whether the tool is or not in the toolbar + return (wxToolBarToolBase *)NULL; + } + + wxToolBarToolBase *tool = node->GetData(); + if ( !DoDeleteTool(pos, tool) ) + { + return (wxToolBarToolBase *)NULL; + } + + m_tools.Erase(node); + + return tool; +} + +bool wxToolBarBase::DeleteToolByPos(size_t pos) +{ + wxCHECK_MSG( pos < GetToolsCount(), false, + _T("invalid position in wxToolBar::DeleteToolByPos()") ); + + wxToolBarToolsList::compatibility_iterator node = m_tools.Item(pos); + + if ( !DoDeleteTool(pos, node->GetData()) ) + { + return false; + } + + delete node->GetData(); + m_tools.Erase(node); + + return true; +} + +bool wxToolBarBase::DeleteTool(int id) +{ + size_t pos = 0; + wxToolBarToolsList::compatibility_iterator node; + for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) + { + if ( node->GetData()->GetId() == id ) + break; + + pos++; + } + + if ( !node || !DoDeleteTool(pos, node->GetData()) ) + { + return false; + } + + delete node->GetData(); + m_tools.Erase(node); + + return true; +} + +wxToolBarToolBase *wxToolBarBase::FindById(int id) const +{ + wxToolBarToolBase *tool = (wxToolBarToolBase *)NULL; + + for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); + node; + node = node->GetNext() ) + { + tool = node->GetData(); + if ( tool->GetId() == id ) + { + // found + break; + } + + tool = NULL; + } + + return tool; +} + +void wxToolBarBase::UnToggleRadioGroup(wxToolBarToolBase *tool) +{ + wxCHECK_RET( tool, _T("NULL tool in wxToolBarTool::UnToggleRadioGroup") ); + + if ( !tool->IsButton() || tool->GetKind() != wxITEM_RADIO ) + return; + + wxToolBarToolsList::compatibility_iterator node = m_tools.Find(tool); + wxCHECK_RET( node, _T("invalid tool in wxToolBarTool::UnToggleRadioGroup") ); + + wxToolBarToolsList::compatibility_iterator nodeNext = node->GetNext(); + while ( nodeNext ) + { + wxToolBarToolBase *toolNext = nodeNext->GetData(); + + if ( !toolNext->IsButton() || toolNext->GetKind() != wxITEM_RADIO ) + break; + + if ( toolNext->Toggle(false) ) + { + DoToggleTool(toolNext, false); + } + + nodeNext = nodeNext->GetNext(); + } + + wxToolBarToolsList::compatibility_iterator nodePrev = node->GetPrevious(); + while ( nodePrev ) + { + wxToolBarToolBase *toolNext = nodePrev->GetData(); + + if ( !toolNext->IsButton() || toolNext->GetKind() != wxITEM_RADIO ) + break; + + if ( toolNext->Toggle(false) ) + { + DoToggleTool(toolNext, false); + } + + nodePrev = nodePrev->GetPrevious(); + } +} + +void wxToolBarBase::ClearTools() +{ + while ( GetToolsCount() ) + { + DeleteToolByPos(0); + } +} + +bool wxToolBarBase::Realize() +{ + return true; +} + +wxToolBarBase::~wxToolBarBase() +{ + WX_CLEAR_LIST(wxToolBarToolsList, m_tools); + + // notify the frame that it doesn't have a tool bar any longer to avoid + // dangling pointers + wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); + if ( frame && frame->GetToolBar() == this ) + { + frame->SetToolBar(NULL); + } +} + +// ---------------------------------------------------------------------------- +// wxToolBarBase tools state +// ---------------------------------------------------------------------------- + +void wxToolBarBase::EnableTool(int id, bool enable) +{ + wxToolBarToolBase *tool = FindById(id); + if ( tool ) + { + if ( tool->Enable(enable) ) + { + DoEnableTool(tool, enable); + } + } +} + +void wxToolBarBase::ToggleTool(int id, bool toggle) +{ + wxToolBarToolBase *tool = FindById(id); + if ( tool && tool->CanBeToggled() ) + { + if ( tool->Toggle(toggle) ) + { + UnToggleRadioGroup(tool); + DoToggleTool(tool, toggle); + } + } +} + +void wxToolBarBase::SetToggle(int id, bool toggle) +{ + wxToolBarToolBase *tool = FindById(id); + if ( tool ) + { + if ( tool->SetToggle(toggle) ) + { + DoSetToggle(tool, toggle); + } + } +} + +void wxToolBarBase::SetToolShortHelp(int id, const wxString& help) +{ + wxToolBarToolBase *tool = FindById(id); + if ( tool ) + { + (void)tool->SetShortHelp(help); + } +} + +void wxToolBarBase::SetToolLongHelp(int id, const wxString& help) +{ + wxToolBarToolBase *tool = FindById(id); + if ( tool ) + { + (void)tool->SetLongHelp(help); + } +} + +wxObject *wxToolBarBase::GetToolClientData(int id) const +{ + wxToolBarToolBase *tool = FindById(id); + + return tool ? tool->GetClientData() : (wxObject *)NULL; +} + +void wxToolBarBase::SetToolClientData(int id, wxObject *clientData) +{ + wxToolBarToolBase *tool = FindById(id); + + wxCHECK_RET( tool, _T("no such tool in wxToolBar::SetToolClientData") ); + + tool->SetClientData(clientData); +} + +int wxToolBarBase::GetToolPos(int id) const +{ + size_t pos = 0; + wxToolBarToolsList::compatibility_iterator node; + + for ( node = m_tools.GetFirst(); node; node = node->GetNext() ) + { + if ( node->GetData()->GetId() == id ) + return pos; + + pos++; + } + + return wxNOT_FOUND; +} + +bool wxToolBarBase::GetToolState(int id) const +{ + wxToolBarToolBase *tool = FindById(id); + wxCHECK_MSG( tool, false, _T("no such tool") ); + + return tool->IsToggled(); +} + +bool wxToolBarBase::GetToolEnabled(int id) const +{ + wxToolBarToolBase *tool = FindById(id); + wxCHECK_MSG( tool, false, _T("no such tool") ); + + return tool->IsEnabled(); +} + +wxString wxToolBarBase::GetToolShortHelp(int id) const +{ + wxToolBarToolBase *tool = FindById(id); + wxCHECK_MSG( tool, wxEmptyString, _T("no such tool") ); + + return tool->GetShortHelp(); +} + +wxString wxToolBarBase::GetToolLongHelp(int id) const +{ + wxToolBarToolBase *tool = FindById(id); + wxCHECK_MSG( tool, wxEmptyString, _T("no such tool") ); + + return tool->GetLongHelp(); +} + +// ---------------------------------------------------------------------------- +// wxToolBarBase geometry +// ---------------------------------------------------------------------------- + +void wxToolBarBase::SetMargins(int x, int y) +{ + m_xMargin = x; + m_yMargin = y; +} + +void wxToolBarBase::SetRows(int WXUNUSED(nRows)) +{ + // nothing +} + +// ---------------------------------------------------------------------------- +// event processing +// ---------------------------------------------------------------------------- + +// Only allow toggle if returns true +bool wxToolBarBase::OnLeftClick(int id, bool toggleDown) +{ + wxCommandEvent event(wxEVT_COMMAND_TOOL_CLICKED, id); + event.SetEventObject(this); + + // we use SetInt() to make wxCommandEvent::IsChecked() return toggleDown + event.SetInt((int)toggleDown); + + // and SetExtraLong() for backwards compatibility + event.SetExtraLong((long)toggleDown); + + // Send events to this toolbar instead (and thence up the window hierarchy) + GetEventHandler()->ProcessEvent(event); + + return true; +} + +// Call when right button down. +void wxToolBarBase::OnRightClick(int id, + long WXUNUSED(x), + long WXUNUSED(y)) +{ + wxCommandEvent event(wxEVT_COMMAND_TOOL_RCLICKED, id); + event.SetEventObject(this); + event.SetInt(id); + + GetEventHandler()->ProcessEvent(event); +} + +// Called when the mouse cursor enters a tool bitmap (no button pressed). +// Argument is wxID_ANY if mouse is exiting the toolbar. +// Note that for this event, the id of the window is used, +// and the integer parameter of wxCommandEvent is used to retrieve +// the tool id. +void wxToolBarBase::OnMouseEnter(int id) +{ + wxCommandEvent event(wxEVT_COMMAND_TOOL_ENTER, GetId()); + event.SetEventObject(this); + event.SetInt(id); + + wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); + if( frame ) + { + wxString help; + wxToolBarToolBase* tool = id == wxID_ANY ? (wxToolBarToolBase*)NULL : FindById(id); + if(tool) + help = tool->GetLongHelp(); + frame->DoGiveHelp( help, id != wxID_ANY ); + } + + (void)GetEventHandler()->ProcessEvent(event); +} + +// ---------------------------------------------------------------------------- +// UI updates +// ---------------------------------------------------------------------------- + +// Do the toolbar button updates (check for EVT_UPDATE_UI handlers) +void wxToolBarBase::UpdateWindowUI(long flags) +{ + wxWindowBase::UpdateWindowUI(flags); + + // There is no sense in updating the toolbar UI + // if the parent window is about to get destroyed + wxWindow *tlw = wxGetTopLevelParent( this ); + if (tlw && wxPendingDelete.Member( tlw )) + return; + + wxEvtHandler* evtHandler = GetEventHandler() ; + + for ( wxToolBarToolsList::compatibility_iterator node = m_tools.GetFirst(); + node; + node = node->GetNext() ) + { + int id = node->GetData()->GetId(); + + wxUpdateUIEvent event(id); + event.SetEventObject(this); + + if ( evtHandler->ProcessEvent(event) ) + { + if ( event.GetSetEnabled() ) + EnableTool(id, event.GetEnabled()); + if ( event.GetSetChecked() ) + ToggleTool(id, event.GetChecked()); +#if 0 + if ( event.GetSetText() ) + // Set tooltip? +#endif // 0 + } + } +} + +#if wxUSE_IMAGE + +/* + * Make a greyed-out image suitable for disabled buttons. + * This code is adapted from wxNewBitmapButton in FL. + */ + +bool wxCreateGreyedImage(const wxImage& src, wxImage& dst) +{ + dst = src.Copy(); + + unsigned char rBg, gBg, bBg; + if ( src.HasMask() ) + { + src.GetOrFindMaskColour(&rBg, &gBg, &bBg); + dst.SetMaskColour(rBg, gBg, bBg); + } + else // assuming the pixels along the edges are of the background color + { + rBg = src.GetRed(0, 0); + gBg = src.GetGreen(0, 0); + bBg = src.GetBlue(0, 0); + } + + const wxColour colBg(rBg, gBg, bBg); + + const wxColour colDark = wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW); + const wxColour colLight = wxSystemSettings::GetColour(wxSYS_COLOUR_3DHIGHLIGHT); + + // Second attempt, just making things monochrome + const int width = src.GetWidth(); + const int height = src.GetHeight(); + + for ( int x = 0; x < width; x++ ) + { + for ( int y = 0; y < height; y++ ) + { + const int r = src.GetRed(x, y); + const int g = src.GetGreen(x, y); + const int b = src.GetBlue(x, y); + + if ( r == rBg && g == gBg && b == bBg ) + { + // Leave the background colour as-is + continue; + } + + // Change light things to the background colour + wxColour col; + if ( r >= (colLight.Red() - 50) && + g >= (colLight.Green() - 50) && + b >= (colLight.Blue() - 50) ) + { + col = colBg; + } + else // Change dark things to really dark + { + col = colDark; + } + + dst.SetRGB(x, y, col.Red(), col.Green(), col.Blue()); + } + } + + return true; +} + +#endif // wxUSE_IMAGE + +#endif // wxUSE_TOOLBAR diff --git a/Source/3rd Party/wx/src/common/textbuf.cpp b/Source/3rd Party/wx/src/common/textbuf.cpp index 7aab70743..6f97b98ca 100644 --- a/Source/3rd Party/wx/src/common/textbuf.cpp +++ b/Source/3rd Party/wx/src/common/textbuf.cpp @@ -1,284 +1,284 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/textbuf.cpp -// Purpose: implementation of wxTextBuffer class -// Created: 14.11.01 -// Author: Morten Hanssen, Vadim Zeitlin -// RCS-ID: $Id: textbuf.cpp 38570 2006-04-05 14:37:47Z VZ $ -// Copyright: (c) 1998-2001 wxWidgets team -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// headers -// ============================================================================ - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif //__BORLANDC__ - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/log.h" -#endif - -#include "wx/textbuf.h" - -// ============================================================================ -// wxTextBuffer class implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// static methods (always compiled in) -// ---------------------------------------------------------------------------- - -// default type is the native one -// the native type under Mac OS X is: -// - Unix when compiling with the Apple Developer Tools (__UNIX__) -// - Mac when compiling with CodeWarrior (__WXMAC__) - -const wxTextFileType wxTextBuffer::typeDefault = -#if defined(__WINDOWS__) || defined(__DOS__) || defined(__PALMOS__) - wxTextFileType_Dos; -#elif defined(__UNIX__) - wxTextFileType_Unix; -#elif defined(__WXMAC__) - wxTextFileType_Mac; -#elif defined(__OS2__) - wxTextFileType_Os2; -#else - wxTextFileType_None; - #error "wxTextBuffer: unsupported platform." -#endif - -const wxChar *wxTextBuffer::GetEOL(wxTextFileType type) -{ - switch ( type ) { - default: - wxFAIL_MSG(wxT("bad buffer type in wxTextBuffer::GetEOL.")); - // fall through nevertheless - we must return something... - - case wxTextFileType_None: return wxEmptyString; - case wxTextFileType_Unix: return wxT("\n"); - case wxTextFileType_Dos: return wxT("\r\n"); - case wxTextFileType_Mac: return wxT("\r"); - } -} - -wxString wxTextBuffer::Translate(const wxString& text, wxTextFileType type) -{ - // don't do anything if there is nothing to do - if ( type == wxTextFileType_None ) - return text; - - // nor if it is empty - if ( text.empty() ) - return text; - - wxString eol = GetEOL(type), result; - - // optimization: we know that the length of the new string will be about - // the same as the length of the old one, so prealloc memory to aviod - // unnecessary relocations - result.Alloc(text.Len()); - - wxChar chLast = 0; - for ( const wxChar *pc = text.c_str(); *pc; pc++ ) - { - wxChar ch = *pc; - switch ( ch ) { - case _T('\n'): - // Dos/Unix line termination - result += eol; - chLast = 0; - break; - - case _T('\r'): - if ( chLast == _T('\r') ) { - // Mac empty line - result += eol; - } - else { - // just remember it: we don't know whether it is just "\r" - // or "\r\n" yet - chLast = _T('\r'); - } - break; - - default: - if ( chLast == _T('\r') ) { - // Mac line termination - result += eol; - - // reset chLast to avoid inserting another eol before the - // next character - chLast = 0; - } - - // add to the current line - result += ch; - } - } - - if ( chLast ) { - // trailing '\r' - result += eol; - } - - return result; -} - -#if wxUSE_TEXTBUFFER - -wxString wxTextBuffer::ms_eof; - -// ---------------------------------------------------------------------------- -// ctors & dtor -// ---------------------------------------------------------------------------- - -wxTextBuffer::wxTextBuffer(const wxString& strBufferName) - : m_strBufferName(strBufferName) -{ - m_nCurLine = 0; - m_isOpened = false; -} - -wxTextBuffer::~wxTextBuffer() -{ - // required here for Darwin -} - -// ---------------------------------------------------------------------------- -// buffer operations -// ---------------------------------------------------------------------------- - -bool wxTextBuffer::Exists() const -{ - return OnExists(); -} - -bool wxTextBuffer::Create(const wxString& strBufferName) -{ - m_strBufferName = strBufferName; - - return Create(); -} - -bool wxTextBuffer::Create() -{ - // buffer name must be either given in ctor or in Create(const wxString&) - wxASSERT( !m_strBufferName.empty() ); - - // if the buffer already exists do nothing - if ( Exists() ) return false; - - if ( !OnOpen(m_strBufferName, WriteAccess) ) - return false; - - OnClose(); - return true; -} - -bool wxTextBuffer::Open(const wxString& strBufferName, const wxMBConv& conv) -{ - m_strBufferName = strBufferName; - - return Open(conv); -} - -bool wxTextBuffer::Open(const wxMBConv& conv) -{ - // buffer name must be either given in ctor or in Open(const wxString&) - wxASSERT( !m_strBufferName.empty() ); - - // open buffer in read-only mode - if ( !OnOpen(m_strBufferName, ReadAccess) ) - return false; - - // read buffer into memory - m_isOpened = OnRead(conv); - - OnClose(); - - return m_isOpened; -} - -// analyse some lines of the buffer trying to guess it's type. -// if it fails, it assumes the native type for our platform. -wxTextFileType wxTextBuffer::GuessType() const -{ - wxASSERT( IsOpened() ); - - // scan the buffer lines - size_t nUnix = 0, // number of '\n's alone - nDos = 0, // number of '\r\n' - nMac = 0; // number of '\r's - - // we take MAX_LINES_SCAN in the beginning, middle and the end of buffer - #define MAX_LINES_SCAN (10) - size_t nCount = m_aLines.Count() / 3, - nScan = nCount > 3*MAX_LINES_SCAN ? MAX_LINES_SCAN : nCount / 3; - - #define AnalyseLine(n) \ - switch ( m_aTypes[n] ) { \ - case wxTextFileType_Unix: nUnix++; break; \ - case wxTextFileType_Dos: nDos++; break; \ - case wxTextFileType_Mac: nMac++; break; \ - default: wxFAIL_MSG(_("unknown line terminator")); \ - } - - size_t n; - for ( n = 0; n < nScan; n++ ) // the beginning - AnalyseLine(n); - for ( n = (nCount - nScan)/2; n < (nCount + nScan)/2; n++ ) - AnalyseLine(n); - for ( n = nCount - nScan; n < nCount; n++ ) - AnalyseLine(n); - - #undef AnalyseLine - - // interpret the results (FIXME far from being even 50% fool proof) - if ( nScan > 0 && nDos + nUnix + nMac == 0 ) { - // no newlines at all - wxLogWarning(_("'%s' is probably a binary buffer."), m_strBufferName.c_str()); - } - else { - #define GREATER_OF(t1, t2) n##t1 == n##t2 ? typeDefault \ - : n##t1 > n##t2 \ - ? wxTextFileType_##t1 \ - : wxTextFileType_##t2 - -#if !defined(__WATCOMC__) || wxCHECK_WATCOM_VERSION(1,4) - if ( nDos > nUnix ) - return GREATER_OF(Dos, Mac); - else if ( nDos < nUnix ) - return GREATER_OF(Unix, Mac); - else { - // nDos == nUnix - return nMac > nDos ? wxTextFileType_Mac : typeDefault; - } -#endif // __WATCOMC__ - - #undef GREATER_OF - } - - return typeDefault; -} - - -bool wxTextBuffer::Close() -{ - Clear(); - m_isOpened = false; - - return true; -} - -bool wxTextBuffer::Write(wxTextFileType typeNew, const wxMBConv& conv) -{ - return OnWrite(typeNew, conv); -} - -#endif // wxUSE_TEXTBUFFER +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/textbuf.cpp +// Purpose: implementation of wxTextBuffer class +// Created: 14.11.01 +// Author: Morten Hanssen, Vadim Zeitlin +// RCS-ID: $Id: textbuf.cpp 38570 2006-04-05 14:37:47Z VZ $ +// Copyright: (c) 1998-2001 wxWidgets team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// headers +// ============================================================================ + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif //__BORLANDC__ + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/log.h" +#endif + +#include "wx/textbuf.h" + +// ============================================================================ +// wxTextBuffer class implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// static methods (always compiled in) +// ---------------------------------------------------------------------------- + +// default type is the native one +// the native type under Mac OS X is: +// - Unix when compiling with the Apple Developer Tools (__UNIX__) +// - Mac when compiling with CodeWarrior (__WXMAC__) + +const wxTextFileType wxTextBuffer::typeDefault = +#if defined(__WINDOWS__) || defined(__DOS__) || defined(__PALMOS__) + wxTextFileType_Dos; +#elif defined(__UNIX__) + wxTextFileType_Unix; +#elif defined(__WXMAC__) + wxTextFileType_Mac; +#elif defined(__OS2__) + wxTextFileType_Os2; +#else + wxTextFileType_None; + #error "wxTextBuffer: unsupported platform." +#endif + +const wxChar *wxTextBuffer::GetEOL(wxTextFileType type) +{ + switch ( type ) { + default: + wxFAIL_MSG(wxT("bad buffer type in wxTextBuffer::GetEOL.")); + // fall through nevertheless - we must return something... + + case wxTextFileType_None: return wxEmptyString; + case wxTextFileType_Unix: return wxT("\n"); + case wxTextFileType_Dos: return wxT("\r\n"); + case wxTextFileType_Mac: return wxT("\r"); + } +} + +wxString wxTextBuffer::Translate(const wxString& text, wxTextFileType type) +{ + // don't do anything if there is nothing to do + if ( type == wxTextFileType_None ) + return text; + + // nor if it is empty + if ( text.empty() ) + return text; + + wxString eol = GetEOL(type), result; + + // optimization: we know that the length of the new string will be about + // the same as the length of the old one, so prealloc memory to aviod + // unnecessary relocations + result.Alloc(text.Len()); + + wxChar chLast = 0; + for ( const wxChar *pc = text.c_str(); *pc; pc++ ) + { + wxChar ch = *pc; + switch ( ch ) { + case _T('\n'): + // Dos/Unix line termination + result += eol; + chLast = 0; + break; + + case _T('\r'): + if ( chLast == _T('\r') ) { + // Mac empty line + result += eol; + } + else { + // just remember it: we don't know whether it is just "\r" + // or "\r\n" yet + chLast = _T('\r'); + } + break; + + default: + if ( chLast == _T('\r') ) { + // Mac line termination + result += eol; + + // reset chLast to avoid inserting another eol before the + // next character + chLast = 0; + } + + // add to the current line + result += ch; + } + } + + if ( chLast ) { + // trailing '\r' + result += eol; + } + + return result; +} + +#if wxUSE_TEXTBUFFER + +wxString wxTextBuffer::ms_eof; + +// ---------------------------------------------------------------------------- +// ctors & dtor +// ---------------------------------------------------------------------------- + +wxTextBuffer::wxTextBuffer(const wxString& strBufferName) + : m_strBufferName(strBufferName) +{ + m_nCurLine = 0; + m_isOpened = false; +} + +wxTextBuffer::~wxTextBuffer() +{ + // required here for Darwin +} + +// ---------------------------------------------------------------------------- +// buffer operations +// ---------------------------------------------------------------------------- + +bool wxTextBuffer::Exists() const +{ + return OnExists(); +} + +bool wxTextBuffer::Create(const wxString& strBufferName) +{ + m_strBufferName = strBufferName; + + return Create(); +} + +bool wxTextBuffer::Create() +{ + // buffer name must be either given in ctor or in Create(const wxString&) + wxASSERT( !m_strBufferName.empty() ); + + // if the buffer already exists do nothing + if ( Exists() ) return false; + + if ( !OnOpen(m_strBufferName, WriteAccess) ) + return false; + + OnClose(); + return true; +} + +bool wxTextBuffer::Open(const wxString& strBufferName, const wxMBConv& conv) +{ + m_strBufferName = strBufferName; + + return Open(conv); +} + +bool wxTextBuffer::Open(const wxMBConv& conv) +{ + // buffer name must be either given in ctor or in Open(const wxString&) + wxASSERT( !m_strBufferName.empty() ); + + // open buffer in read-only mode + if ( !OnOpen(m_strBufferName, ReadAccess) ) + return false; + + // read buffer into memory + m_isOpened = OnRead(conv); + + OnClose(); + + return m_isOpened; +} + +// analyse some lines of the buffer trying to guess it's type. +// if it fails, it assumes the native type for our platform. +wxTextFileType wxTextBuffer::GuessType() const +{ + wxASSERT( IsOpened() ); + + // scan the buffer lines + size_t nUnix = 0, // number of '\n's alone + nDos = 0, // number of '\r\n' + nMac = 0; // number of '\r's + + // we take MAX_LINES_SCAN in the beginning, middle and the end of buffer + #define MAX_LINES_SCAN (10) + size_t nCount = m_aLines.Count() / 3, + nScan = nCount > 3*MAX_LINES_SCAN ? MAX_LINES_SCAN : nCount / 3; + + #define AnalyseLine(n) \ + switch ( m_aTypes[n] ) { \ + case wxTextFileType_Unix: nUnix++; break; \ + case wxTextFileType_Dos: nDos++; break; \ + case wxTextFileType_Mac: nMac++; break; \ + default: wxFAIL_MSG(_("unknown line terminator")); \ + } + + size_t n; + for ( n = 0; n < nScan; n++ ) // the beginning + AnalyseLine(n); + for ( n = (nCount - nScan)/2; n < (nCount + nScan)/2; n++ ) + AnalyseLine(n); + for ( n = nCount - nScan; n < nCount; n++ ) + AnalyseLine(n); + + #undef AnalyseLine + + // interpret the results (FIXME far from being even 50% fool proof) + if ( nScan > 0 && nDos + nUnix + nMac == 0 ) { + // no newlines at all + wxLogWarning(_("'%s' is probably a binary buffer."), m_strBufferName.c_str()); + } + else { + #define GREATER_OF(t1, t2) n##t1 == n##t2 ? typeDefault \ + : n##t1 > n##t2 \ + ? wxTextFileType_##t1 \ + : wxTextFileType_##t2 + +#if !defined(__WATCOMC__) || wxCHECK_WATCOM_VERSION(1,4) + if ( nDos > nUnix ) + return GREATER_OF(Dos, Mac); + else if ( nDos < nUnix ) + return GREATER_OF(Unix, Mac); + else { + // nDos == nUnix + return nMac > nDos ? wxTextFileType_Mac : typeDefault; + } +#endif // __WATCOMC__ + + #undef GREATER_OF + } + + return typeDefault; +} + + +bool wxTextBuffer::Close() +{ + Clear(); + m_isOpened = false; + + return true; +} + +bool wxTextBuffer::Write(wxTextFileType typeNew, const wxMBConv& conv) +{ + return OnWrite(typeNew, conv); +} + +#endif // wxUSE_TEXTBUFFER diff --git a/Source/3rd Party/wx/src/common/textcmn.cpp b/Source/3rd Party/wx/src/common/textcmn.cpp index f25ba5b5c..952fcf974 100644 --- a/Source/3rd Party/wx/src/common/textcmn.cpp +++ b/Source/3rd Party/wx/src/common/textcmn.cpp @@ -1,553 +1,553 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/textcmn.cpp -// Purpose: implementation of platform-independent functions of wxTextCtrl -// Author: Julian Smart -// Modified by: -// Created: 13.07.99 -// RCS-ID: $Id: textcmn.cpp 62095 2009-09-24 18:20:21Z JS $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// for compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/event.h" -#endif // WX_PRECOMP - -#if wxUSE_TEXTCTRL - -#include "wx/textctrl.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" -#endif // WX_PRECOMP - -#include "wx/ffile.h" - -// ---------------------------------------------------------------------------- -// macros -// ---------------------------------------------------------------------------- - -// we don't have any objects of type wxTextCtrlBase in the program, only -// wxTextCtrl, so this cast is safe -#define TEXTCTRL(ptr) ((wxTextCtrl *)(ptr)) - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_DYNAMIC_CLASS(wxTextUrlEvent, wxCommandEvent) - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_UPDATED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_ENTER) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_URL) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_MAXLEN) - -IMPLEMENT_ABSTRACT_CLASS(wxTextCtrlBase, wxControl) - -// ---------------------------------------------------------------------------- -// style functions - not implemented here -// ---------------------------------------------------------------------------- - -wxTextAttr::wxTextAttr(const wxColour& colText, - const wxColour& colBack, - const wxFont& font, - wxTextAttrAlignment alignment) - : m_colText(colText), m_colBack(colBack), m_font(font), m_textAlignment(alignment) -{ - m_flags = 0; - m_leftIndent = 0; - m_leftSubIndent = 0; - m_rightIndent = 0; - if (m_colText.Ok()) m_flags |= wxTEXT_ATTR_TEXT_COLOUR; - if (m_colBack.Ok()) m_flags |= wxTEXT_ATTR_BACKGROUND_COLOUR; - if (m_font.Ok()) m_flags |= wxTEXT_ATTR_FONT; - if (alignment != wxTEXT_ALIGNMENT_DEFAULT) - m_flags |= wxTEXT_ATTR_ALIGNMENT; -} - -void wxTextAttr::Init() -{ - m_textAlignment = wxTEXT_ALIGNMENT_DEFAULT; - m_flags = 0; - m_leftIndent = 0; - m_leftSubIndent = 0; - m_rightIndent = 0; -} - -/* static */ -wxTextAttr wxTextAttr::Combine(const wxTextAttr& attr, - const wxTextAttr& attrDef, - const wxTextCtrlBase *text) -{ - wxFont font = attr.GetFont(); - if ( !font.Ok() ) - { - font = attrDef.GetFont(); - - if ( text && !font.Ok() ) - font = text->GetFont(); - } - - wxColour colFg = attr.GetTextColour(); - if ( !colFg.Ok() ) - { - colFg = attrDef.GetTextColour(); - - if ( text && !colFg.Ok() ) - colFg = text->GetForegroundColour(); - } - - wxColour colBg = attr.GetBackgroundColour(); - if ( !colBg.Ok() ) - { - colBg = attrDef.GetBackgroundColour(); - - if ( text && !colBg.Ok() ) - colBg = text->GetBackgroundColour(); - } - - wxTextAttr newAttr(colFg, colBg, font); - - if (attr.HasAlignment()) - newAttr.SetAlignment(attr.GetAlignment()); - else if (attrDef.HasAlignment()) - newAttr.SetAlignment(attrDef.GetAlignment()); - - if (attr.HasTabs()) - newAttr.SetTabs(attr.GetTabs()); - else if (attrDef.HasTabs()) - newAttr.SetTabs(attrDef.GetTabs()); - - if (attr.HasLeftIndent()) - newAttr.SetLeftIndent(attr.GetLeftIndent(), attr.GetLeftSubIndent()); - else if (attrDef.HasLeftIndent()) - newAttr.SetLeftIndent(attrDef.GetLeftIndent(), attr.GetLeftSubIndent()); - - if (attr.HasRightIndent()) - newAttr.SetRightIndent(attr.GetRightIndent()); - else if (attrDef.HasRightIndent()) - newAttr.SetRightIndent(attrDef.GetRightIndent()); - - return newAttr; -} - -void wxTextAttr::operator= (const wxTextAttr& attr) -{ - m_font = attr.m_font; - m_colText = attr.m_colText; - m_colBack = attr.m_colBack; - m_textAlignment = attr.m_textAlignment; - m_leftIndent = attr.m_leftIndent; - m_leftSubIndent = attr.m_leftSubIndent; - m_rightIndent = attr.m_rightIndent; - m_tabs = attr.m_tabs; - m_flags = attr.m_flags; -} - - -// apply styling to text range -bool wxTextCtrlBase::SetStyle(long WXUNUSED(start), long WXUNUSED(end), - const wxTextAttr& WXUNUSED(style)) -{ - // to be implemented in derived TextCtrl classes - return false; -} - -// get the styling at the given position -bool wxTextCtrlBase::GetStyle(long WXUNUSED(position), wxTextAttr& WXUNUSED(style)) -{ - // to be implemented in derived TextCtrl classes - return false; -} - -// change default text attributes -bool wxTextCtrlBase::SetDefaultStyle(const wxTextAttr& style) -{ - // keep the old attributes if the new style doesn't specify them unless the - // new style is empty - then reset m_defaultStyle (as there is no other way - // to do it) - if ( style.IsDefault() ) - m_defaultStyle = style; - else - m_defaultStyle = wxTextAttr::Combine(style, m_defaultStyle, this); - - return true; -} - -// get default text attributes -const wxTextAttr& wxTextCtrlBase::GetDefaultStyle() const -{ - return m_defaultStyle; -} - -// ---------------------------------------------------------------------------- -// file IO functions -// ---------------------------------------------------------------------------- - -bool wxTextCtrlBase::DoLoadFile(const wxString& filename, int WXUNUSED(fileType)) -{ -#if wxUSE_FFILE - wxFFile file(filename); - if ( file.IsOpened() ) - { - wxString text; - if ( file.ReadAll(&text) ) - { - SetValue(text); - - DiscardEdits(); - - m_filename = filename; - - return true; - } - } - - wxLogError(_("File couldn't be loaded.")); -#endif // wxUSE_FFILE - - return false; -} - -bool wxTextCtrlBase::SaveFile(const wxString& filename, int fileType) -{ - wxString filenameToUse = filename.empty() ? m_filename : filename; - if ( filenameToUse.empty() ) - { - // what kind of message to give? is it an error or a program bug? - wxLogDebug(wxT("Can't save textctrl to file without filename.")); - - return false; - } - - return DoSaveFile(filenameToUse, fileType); -} - -bool wxTextCtrlBase::DoSaveFile(const wxString& filename, int WXUNUSED(fileType)) -{ -#if wxUSE_FFILE - wxFFile file(filename, _T("w")); - if ( file.IsOpened() && file.Write(GetValue()) ) - { - // if it worked, save for future calls - m_filename = filename; - - // it's not modified any longer - DiscardEdits(); - - return true; - } -#endif // wxUSE_FFILE - - wxLogError(_("The text couldn't be saved.")); - - return false; -} - -// ---------------------------------------------------------------------------- -// stream-like insertion operator -// ---------------------------------------------------------------------------- - -wxTextCtrl& wxTextCtrlBase::operator<<(const wxString& s) -{ - AppendText(s); - return *TEXTCTRL(this); -} - -wxTextCtrl& wxTextCtrlBase::operator<<(float f) -{ - wxString str; - str.Printf(wxT("%.2f"), f); - AppendText(str); - return *TEXTCTRL(this); -} - -wxTextCtrl& wxTextCtrlBase::operator<<(double d) -{ - wxString str; - str.Printf(wxT("%.2f"), d); - AppendText(str); - return *TEXTCTRL(this); -} - -wxTextCtrl& wxTextCtrlBase::operator<<(int i) -{ - wxString str; - str.Printf(wxT("%d"), i); - AppendText(str); - return *TEXTCTRL(this); -} - -wxTextCtrl& wxTextCtrlBase::operator<<(long i) -{ - wxString str; - str.Printf(wxT("%ld"), i); - AppendText(str); - return *TEXTCTRL(this); -} - -wxTextCtrl& wxTextCtrlBase::operator<<(const wxChar c) -{ - return operator<<(wxString(c)); -} - -// ---------------------------------------------------------------------------- -// streambuf methods implementation -// ---------------------------------------------------------------------------- - -#if wxHAS_TEXT_WINDOW_STREAM - -int wxTextCtrlBase::overflow(int c) -{ - AppendText((wxChar)c); - - // return something different from EOF - return 0; -} - -#endif // wxHAS_TEXT_WINDOW_STREAM - -// ---------------------------------------------------------------------------- -// clipboard stuff -// ---------------------------------------------------------------------------- - -bool wxTextCtrlBase::CanCopy() const -{ - // can copy if there's a selection - long from, to; - GetSelection(&from, &to); - return from != to; -} - -bool wxTextCtrlBase::CanCut() const -{ - // can cut if there's a selection and if we're not read only - return CanCopy() && IsEditable(); -} - -bool wxTextCtrlBase::CanPaste() const -{ - // can paste if we are not read only - return IsEditable(); -} - -// ---------------------------------------------------------------------------- -// emulating key presses -// ---------------------------------------------------------------------------- - -#ifdef __WIN32__ -// the generic version is unused in wxMSW -bool wxTextCtrlBase::EmulateKeyPress(const wxKeyEvent& WXUNUSED(event)) -{ - return false; -} -#else // !__WIN32__ -bool wxTextCtrlBase::EmulateKeyPress(const wxKeyEvent& event) -{ - wxChar ch = 0; - int keycode = event.GetKeyCode(); - switch ( keycode ) - { - case WXK_NUMPAD0: - case WXK_NUMPAD1: - case WXK_NUMPAD2: - case WXK_NUMPAD3: - case WXK_NUMPAD4: - case WXK_NUMPAD5: - case WXK_NUMPAD6: - case WXK_NUMPAD7: - case WXK_NUMPAD8: - case WXK_NUMPAD9: - ch = (wxChar)(_T('0') + keycode - WXK_NUMPAD0); - break; - - case WXK_MULTIPLY: - case WXK_NUMPAD_MULTIPLY: - ch = _T('*'); - break; - - case WXK_ADD: - case WXK_NUMPAD_ADD: - ch = _T('+'); - break; - - case WXK_SUBTRACT: - case WXK_NUMPAD_SUBTRACT: - ch = _T('-'); - break; - - case WXK_DECIMAL: - case WXK_NUMPAD_DECIMAL: - ch = _T('.'); - break; - - case WXK_DIVIDE: - case WXK_NUMPAD_DIVIDE: - ch = _T('/'); - break; - - case WXK_DELETE: - case WXK_NUMPAD_DELETE: - // delete the character at cursor - { - const long pos = GetInsertionPoint(); - if ( pos < GetLastPosition() ) - Remove(pos, pos + 1); - } - break; - - case WXK_BACK: - // delete the character before the cursor - { - const long pos = GetInsertionPoint(); - if ( pos > 0 ) - Remove(pos - 1, pos); - } - break; - - default: -#if wxUSE_UNICODE - if ( event.GetUnicodeKey() ) - { - ch = event.GetUnicodeKey(); - } - else -#endif - if ( keycode < 256 && keycode >= 0 && wxIsprint(keycode) ) - { - // FIXME this is not going to work for non letters... - if ( !event.ShiftDown() ) - { - keycode = wxTolower(keycode); - } - - ch = (wxChar)keycode; - } - else - { - ch = _T('\0'); - } - } - - if ( ch ) - { - WriteText(ch); - - return true; - } - - return false; -} -#endif // !__WIN32__ - -// ---------------------------------------------------------------------------- -// selection and ranges -// ---------------------------------------------------------------------------- - -void wxTextCtrlBase::SelectAll() -{ - SetSelection(0, GetLastPosition()); -} - -wxString wxTextCtrlBase::GetStringSelection() const -{ - long from, to; - GetSelection(&from, &to); - - return GetRange(from, to); -} - -wxString wxTextCtrlBase::GetRange(long from, long to) const -{ - wxString sel; - if ( from < to ) - { - sel = GetValue().Mid(from, to - from); - } - - return sel; -} - -// do the window-specific processing after processing the update event -void wxTextCtrlBase::DoUpdateWindowUI(wxUpdateUIEvent& event) -{ - // call inherited, but skip the wxControl's version, and call directly the - // wxWindow's one instead, because the only reason why we are overriding this - // function is that we want to use SetValue() instead of wxControl::SetLabel() - wxWindowBase::DoUpdateWindowUI(event); - - // update text - if ( event.GetSetText() ) - { - if ( event.GetText() != GetValue() ) - SetValue(event.GetText()); - } -} - -// ---------------------------------------------------------------------------- -// hit testing -// ---------------------------------------------------------------------------- - -wxTextCtrlHitTestResult -wxTextCtrlBase::HitTest(const wxPoint& pt, wxTextCoord *x, wxTextCoord *y) const -{ - // implement in terms of the other overload as the native ports typically - // can get the position and not (x, y) pair directly (although wxUniv - // directly gets x and y -- and so overrides this method as well) - long pos; - wxTextCtrlHitTestResult rc = HitTest(pt, &pos); - - if ( rc != wxTE_HT_UNKNOWN ) - { - PositionToXY(pos, x, y); - } - - return rc; -} - -wxTextCtrlHitTestResult -wxTextCtrlBase::HitTest(const wxPoint& WXUNUSED(pt), - long * WXUNUSED(pos)) const -{ - // not implemented - return wxTE_HT_UNKNOWN; -} - -// ---------------------------------------------------------------------------- -// events -// ---------------------------------------------------------------------------- - -void wxTextCtrlBase::SendTextUpdatedEvent() -{ - wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId()); - - // do not do this as it could be very inefficient if the text control - // contains a lot of text and we're not using ref-counted wxString - // implementation -- instead, event.GetString() will query the control for - // its current text if needed - //event.SetString(GetValue()); - - event.SetEventObject(this); - GetEventHandler()->ProcessEvent(event); -} - -#else // !wxUSE_TEXTCTRL - -// define this one even if !wxUSE_TEXTCTRL because it is also used by other -// controls (wxComboBox and wxSpinCtrl) - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_UPDATED) - -#endif // wxUSE_TEXTCTRL/!wxUSE_TEXTCTRL +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/textcmn.cpp +// Purpose: implementation of platform-independent functions of wxTextCtrl +// Author: Julian Smart +// Modified by: +// Created: 13.07.99 +// RCS-ID: $Id: textcmn.cpp 62095 2009-09-24 18:20:21Z JS $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/event.h" +#endif // WX_PRECOMP + +#if wxUSE_TEXTCTRL + +#include "wx/textctrl.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" +#endif // WX_PRECOMP + +#include "wx/ffile.h" + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +// we don't have any objects of type wxTextCtrlBase in the program, only +// wxTextCtrl, so this cast is safe +#define TEXTCTRL(ptr) ((wxTextCtrl *)(ptr)) + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_DYNAMIC_CLASS(wxTextUrlEvent, wxCommandEvent) + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_UPDATED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_ENTER) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_URL) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_MAXLEN) + +IMPLEMENT_ABSTRACT_CLASS(wxTextCtrlBase, wxControl) + +// ---------------------------------------------------------------------------- +// style functions - not implemented here +// ---------------------------------------------------------------------------- + +wxTextAttr::wxTextAttr(const wxColour& colText, + const wxColour& colBack, + const wxFont& font, + wxTextAttrAlignment alignment) + : m_colText(colText), m_colBack(colBack), m_font(font), m_textAlignment(alignment) +{ + m_flags = 0; + m_leftIndent = 0; + m_leftSubIndent = 0; + m_rightIndent = 0; + if (m_colText.Ok()) m_flags |= wxTEXT_ATTR_TEXT_COLOUR; + if (m_colBack.Ok()) m_flags |= wxTEXT_ATTR_BACKGROUND_COLOUR; + if (m_font.Ok()) m_flags |= wxTEXT_ATTR_FONT; + if (alignment != wxTEXT_ALIGNMENT_DEFAULT) + m_flags |= wxTEXT_ATTR_ALIGNMENT; +} + +void wxTextAttr::Init() +{ + m_textAlignment = wxTEXT_ALIGNMENT_DEFAULT; + m_flags = 0; + m_leftIndent = 0; + m_leftSubIndent = 0; + m_rightIndent = 0; +} + +/* static */ +wxTextAttr wxTextAttr::Combine(const wxTextAttr& attr, + const wxTextAttr& attrDef, + const wxTextCtrlBase *text) +{ + wxFont font = attr.GetFont(); + if ( !font.Ok() ) + { + font = attrDef.GetFont(); + + if ( text && !font.Ok() ) + font = text->GetFont(); + } + + wxColour colFg = attr.GetTextColour(); + if ( !colFg.Ok() ) + { + colFg = attrDef.GetTextColour(); + + if ( text && !colFg.Ok() ) + colFg = text->GetForegroundColour(); + } + + wxColour colBg = attr.GetBackgroundColour(); + if ( !colBg.Ok() ) + { + colBg = attrDef.GetBackgroundColour(); + + if ( text && !colBg.Ok() ) + colBg = text->GetBackgroundColour(); + } + + wxTextAttr newAttr(colFg, colBg, font); + + if (attr.HasAlignment()) + newAttr.SetAlignment(attr.GetAlignment()); + else if (attrDef.HasAlignment()) + newAttr.SetAlignment(attrDef.GetAlignment()); + + if (attr.HasTabs()) + newAttr.SetTabs(attr.GetTabs()); + else if (attrDef.HasTabs()) + newAttr.SetTabs(attrDef.GetTabs()); + + if (attr.HasLeftIndent()) + newAttr.SetLeftIndent(attr.GetLeftIndent(), attr.GetLeftSubIndent()); + else if (attrDef.HasLeftIndent()) + newAttr.SetLeftIndent(attrDef.GetLeftIndent(), attr.GetLeftSubIndent()); + + if (attr.HasRightIndent()) + newAttr.SetRightIndent(attr.GetRightIndent()); + else if (attrDef.HasRightIndent()) + newAttr.SetRightIndent(attrDef.GetRightIndent()); + + return newAttr; +} + +void wxTextAttr::operator= (const wxTextAttr& attr) +{ + m_font = attr.m_font; + m_colText = attr.m_colText; + m_colBack = attr.m_colBack; + m_textAlignment = attr.m_textAlignment; + m_leftIndent = attr.m_leftIndent; + m_leftSubIndent = attr.m_leftSubIndent; + m_rightIndent = attr.m_rightIndent; + m_tabs = attr.m_tabs; + m_flags = attr.m_flags; +} + + +// apply styling to text range +bool wxTextCtrlBase::SetStyle(long WXUNUSED(start), long WXUNUSED(end), + const wxTextAttr& WXUNUSED(style)) +{ + // to be implemented in derived TextCtrl classes + return false; +} + +// get the styling at the given position +bool wxTextCtrlBase::GetStyle(long WXUNUSED(position), wxTextAttr& WXUNUSED(style)) +{ + // to be implemented in derived TextCtrl classes + return false; +} + +// change default text attributes +bool wxTextCtrlBase::SetDefaultStyle(const wxTextAttr& style) +{ + // keep the old attributes if the new style doesn't specify them unless the + // new style is empty - then reset m_defaultStyle (as there is no other way + // to do it) + if ( style.IsDefault() ) + m_defaultStyle = style; + else + m_defaultStyle = wxTextAttr::Combine(style, m_defaultStyle, this); + + return true; +} + +// get default text attributes +const wxTextAttr& wxTextCtrlBase::GetDefaultStyle() const +{ + return m_defaultStyle; +} + +// ---------------------------------------------------------------------------- +// file IO functions +// ---------------------------------------------------------------------------- + +bool wxTextCtrlBase::DoLoadFile(const wxString& filename, int WXUNUSED(fileType)) +{ +#if wxUSE_FFILE + wxFFile file(filename); + if ( file.IsOpened() ) + { + wxString text; + if ( file.ReadAll(&text) ) + { + SetValue(text); + + DiscardEdits(); + + m_filename = filename; + + return true; + } + } + + wxLogError(_("File couldn't be loaded.")); +#endif // wxUSE_FFILE + + return false; +} + +bool wxTextCtrlBase::SaveFile(const wxString& filename, int fileType) +{ + wxString filenameToUse = filename.empty() ? m_filename : filename; + if ( filenameToUse.empty() ) + { + // what kind of message to give? is it an error or a program bug? + wxLogDebug(wxT("Can't save textctrl to file without filename.")); + + return false; + } + + return DoSaveFile(filenameToUse, fileType); +} + +bool wxTextCtrlBase::DoSaveFile(const wxString& filename, int WXUNUSED(fileType)) +{ +#if wxUSE_FFILE + wxFFile file(filename, _T("w")); + if ( file.IsOpened() && file.Write(GetValue()) ) + { + // if it worked, save for future calls + m_filename = filename; + + // it's not modified any longer + DiscardEdits(); + + return true; + } +#endif // wxUSE_FFILE + + wxLogError(_("The text couldn't be saved.")); + + return false; +} + +// ---------------------------------------------------------------------------- +// stream-like insertion operator +// ---------------------------------------------------------------------------- + +wxTextCtrl& wxTextCtrlBase::operator<<(const wxString& s) +{ + AppendText(s); + return *TEXTCTRL(this); +} + +wxTextCtrl& wxTextCtrlBase::operator<<(float f) +{ + wxString str; + str.Printf(wxT("%.2f"), f); + AppendText(str); + return *TEXTCTRL(this); +} + +wxTextCtrl& wxTextCtrlBase::operator<<(double d) +{ + wxString str; + str.Printf(wxT("%.2f"), d); + AppendText(str); + return *TEXTCTRL(this); +} + +wxTextCtrl& wxTextCtrlBase::operator<<(int i) +{ + wxString str; + str.Printf(wxT("%d"), i); + AppendText(str); + return *TEXTCTRL(this); +} + +wxTextCtrl& wxTextCtrlBase::operator<<(long i) +{ + wxString str; + str.Printf(wxT("%ld"), i); + AppendText(str); + return *TEXTCTRL(this); +} + +wxTextCtrl& wxTextCtrlBase::operator<<(const wxChar c) +{ + return operator<<(wxString(c)); +} + +// ---------------------------------------------------------------------------- +// streambuf methods implementation +// ---------------------------------------------------------------------------- + +#if wxHAS_TEXT_WINDOW_STREAM + +int wxTextCtrlBase::overflow(int c) +{ + AppendText((wxChar)c); + + // return something different from EOF + return 0; +} + +#endif // wxHAS_TEXT_WINDOW_STREAM + +// ---------------------------------------------------------------------------- +// clipboard stuff +// ---------------------------------------------------------------------------- + +bool wxTextCtrlBase::CanCopy() const +{ + // can copy if there's a selection + long from, to; + GetSelection(&from, &to); + return from != to; +} + +bool wxTextCtrlBase::CanCut() const +{ + // can cut if there's a selection and if we're not read only + return CanCopy() && IsEditable(); +} + +bool wxTextCtrlBase::CanPaste() const +{ + // can paste if we are not read only + return IsEditable(); +} + +// ---------------------------------------------------------------------------- +// emulating key presses +// ---------------------------------------------------------------------------- + +#ifdef __WIN32__ +// the generic version is unused in wxMSW +bool wxTextCtrlBase::EmulateKeyPress(const wxKeyEvent& WXUNUSED(event)) +{ + return false; +} +#else // !__WIN32__ +bool wxTextCtrlBase::EmulateKeyPress(const wxKeyEvent& event) +{ + wxChar ch = 0; + int keycode = event.GetKeyCode(); + switch ( keycode ) + { + case WXK_NUMPAD0: + case WXK_NUMPAD1: + case WXK_NUMPAD2: + case WXK_NUMPAD3: + case WXK_NUMPAD4: + case WXK_NUMPAD5: + case WXK_NUMPAD6: + case WXK_NUMPAD7: + case WXK_NUMPAD8: + case WXK_NUMPAD9: + ch = (wxChar)(_T('0') + keycode - WXK_NUMPAD0); + break; + + case WXK_MULTIPLY: + case WXK_NUMPAD_MULTIPLY: + ch = _T('*'); + break; + + case WXK_ADD: + case WXK_NUMPAD_ADD: + ch = _T('+'); + break; + + case WXK_SUBTRACT: + case WXK_NUMPAD_SUBTRACT: + ch = _T('-'); + break; + + case WXK_DECIMAL: + case WXK_NUMPAD_DECIMAL: + ch = _T('.'); + break; + + case WXK_DIVIDE: + case WXK_NUMPAD_DIVIDE: + ch = _T('/'); + break; + + case WXK_DELETE: + case WXK_NUMPAD_DELETE: + // delete the character at cursor + { + const long pos = GetInsertionPoint(); + if ( pos < GetLastPosition() ) + Remove(pos, pos + 1); + } + break; + + case WXK_BACK: + // delete the character before the cursor + { + const long pos = GetInsertionPoint(); + if ( pos > 0 ) + Remove(pos - 1, pos); + } + break; + + default: +#if wxUSE_UNICODE + if ( event.GetUnicodeKey() ) + { + ch = event.GetUnicodeKey(); + } + else +#endif + if ( keycode < 256 && keycode >= 0 && wxIsprint(keycode) ) + { + // FIXME this is not going to work for non letters... + if ( !event.ShiftDown() ) + { + keycode = wxTolower(keycode); + } + + ch = (wxChar)keycode; + } + else + { + ch = _T('\0'); + } + } + + if ( ch ) + { + WriteText(ch); + + return true; + } + + return false; +} +#endif // !__WIN32__ + +// ---------------------------------------------------------------------------- +// selection and ranges +// ---------------------------------------------------------------------------- + +void wxTextCtrlBase::SelectAll() +{ + SetSelection(0, GetLastPosition()); +} + +wxString wxTextCtrlBase::GetStringSelection() const +{ + long from, to; + GetSelection(&from, &to); + + return GetRange(from, to); +} + +wxString wxTextCtrlBase::GetRange(long from, long to) const +{ + wxString sel; + if ( from < to ) + { + sel = GetValue().Mid(from, to - from); + } + + return sel; +} + +// do the window-specific processing after processing the update event +void wxTextCtrlBase::DoUpdateWindowUI(wxUpdateUIEvent& event) +{ + // call inherited, but skip the wxControl's version, and call directly the + // wxWindow's one instead, because the only reason why we are overriding this + // function is that we want to use SetValue() instead of wxControl::SetLabel() + wxWindowBase::DoUpdateWindowUI(event); + + // update text + if ( event.GetSetText() ) + { + if ( event.GetText() != GetValue() ) + SetValue(event.GetText()); + } +} + +// ---------------------------------------------------------------------------- +// hit testing +// ---------------------------------------------------------------------------- + +wxTextCtrlHitTestResult +wxTextCtrlBase::HitTest(const wxPoint& pt, wxTextCoord *x, wxTextCoord *y) const +{ + // implement in terms of the other overload as the native ports typically + // can get the position and not (x, y) pair directly (although wxUniv + // directly gets x and y -- and so overrides this method as well) + long pos; + wxTextCtrlHitTestResult rc = HitTest(pt, &pos); + + if ( rc != wxTE_HT_UNKNOWN ) + { + PositionToXY(pos, x, y); + } + + return rc; +} + +wxTextCtrlHitTestResult +wxTextCtrlBase::HitTest(const wxPoint& WXUNUSED(pt), + long * WXUNUSED(pos)) const +{ + // not implemented + return wxTE_HT_UNKNOWN; +} + +// ---------------------------------------------------------------------------- +// events +// ---------------------------------------------------------------------------- + +void wxTextCtrlBase::SendTextUpdatedEvent() +{ + wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, GetId()); + + // do not do this as it could be very inefficient if the text control + // contains a lot of text and we're not using ref-counted wxString + // implementation -- instead, event.GetString() will query the control for + // its current text if needed + //event.SetString(GetValue()); + + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); +} + +#else // !wxUSE_TEXTCTRL + +// define this one even if !wxUSE_TEXTCTRL because it is also used by other +// controls (wxComboBox and wxSpinCtrl) + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TEXT_UPDATED) + +#endif // wxUSE_TEXTCTRL/!wxUSE_TEXTCTRL diff --git a/Source/3rd Party/wx/src/common/textfile.cpp b/Source/3rd Party/wx/src/common/textfile.cpp index 80dc4cc1c..d873e1d97 100644 --- a/Source/3rd Party/wx/src/common/textfile.cpp +++ b/Source/3rd Party/wx/src/common/textfile.cpp @@ -1,295 +1,295 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/textfile.cpp -// Purpose: implementation of wxTextFile class -// Author: Vadim Zeitlin -// Modified by: -// Created: 03.04.98 -// RCS-ID: $Id: textfile.cpp 49298 2007-10-21 18:05:49Z SC $ -// Copyright: (c) 1998 Vadim Zeitlin -// Licence: wxWindows licence -/////////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// headers -// ============================================================================ - -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif //__BORLANDC__ - -#if !wxUSE_FILE || !wxUSE_TEXTBUFFER - #undef wxUSE_TEXTFILE - #define wxUSE_TEXTFILE 0 -#endif // wxUSE_FILE - -#if wxUSE_TEXTFILE - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/intl.h" - #include "wx/file.h" - #include "wx/log.h" -#endif - -#include "wx/textfile.h" -#include "wx/filename.h" -#include "wx/buffer.h" - -// ============================================================================ -// wxTextFile class implementation -// ============================================================================ - -wxTextFile::wxTextFile(const wxString& strFileName) - : wxTextBuffer(strFileName) -{ -} - - -// ---------------------------------------------------------------------------- -// file operations -// ---------------------------------------------------------------------------- - -bool wxTextFile::OnExists() const -{ - return wxFile::Exists(m_strBufferName); -} - - -bool wxTextFile::OnOpen(const wxString &strBufferName, wxTextBufferOpenMode OpenMode) -{ - wxFile::OpenMode FileOpenMode; - - switch ( OpenMode ) - { - default: - wxFAIL_MSG( _T("unknown open mode in wxTextFile::Open") ); - // fall through - - case ReadAccess : - FileOpenMode = wxFile::read; - break; - - case WriteAccess : - FileOpenMode = wxFile::write; - break; - } - - return m_file.Open(strBufferName.c_str(), FileOpenMode); -} - - -bool wxTextFile::OnClose() -{ - return m_file.Close(); -} - - -bool wxTextFile::OnRead(const wxMBConv& conv) -{ - // file should be opened - wxASSERT_MSG( m_file.IsOpened(), _T("can't read closed file") ); - - // read the entire file in memory: this is not the most efficient thing to - // do but there is no good way to avoid it in Unicode build because if we - // read the file block by block we can't convert each block to Unicode - // separately (the last multibyte char in the block might be only partially - // read and so the conversion would fail) and, as the file contents is kept - // in memory by wxTextFile anyhow, it shouldn't be a big problem to read - // the file entirely - size_t bufSize = 0, - bufPos = 0; - char block[1024]; - wxCharBuffer buf; - - // first determine if the file is seekable or not and so whether we can - // determine its length in advance - wxFileOffset fileLength; - { - wxLogNull logNull; - fileLength = m_file.Length(); - } - - // some non-seekable files under /proc under Linux pretend that they're - // seekable but always return 0; others do return an error - const bool seekable = fileLength != wxInvalidOffset && fileLength != 0; - if ( seekable ) - { - // we know the required length, so set the buffer size in advance - bufSize = fileLength; - if ( !buf.extend(bufSize - 1 /* it adds 1 internally */) ) - return false; - - // if the file is seekable, also check that we're at its beginning - wxASSERT_MSG( m_file.Tell() == 0, _T("should be at start of file") ); - } - - for ( ;; ) - { - ssize_t nRead = m_file.Read(block, WXSIZEOF(block)); - - if ( nRead == wxInvalidOffset ) - { - // read error (error message already given in wxFile::Read) - return false; - } - - if ( nRead == 0 ) - { - // if no bytes have been read, presumably this is a valid-but-empty file - if ( bufPos == 0 ) - return true; - - // otherwise we've finished reading the file - break; - } - - if ( seekable ) - { - // this shouldn't happen but don't overwrite the buffer if it does - wxCHECK_MSG( bufPos + nRead <= bufSize, false, - _T("read more than file length?") ); - } - else // !seekable - { - // for non-seekable files we have to allocate more memory on the go - if ( !buf.extend(bufPos + nRead - 1 /* it adds 1 internally */) ) - return false; - } - - // append to the buffer - memcpy(buf.data() + bufPos, block, nRead); - bufPos += nRead; - } - - if ( !seekable ) - { - bufSize = bufPos; - } - - const wxString str(buf, conv, bufPos); - - // there's no risk of this happening in ANSI build -#if wxUSE_UNICODE - if ( bufSize > 4 && str.empty() ) - { - wxLogError(_("Failed to convert file \"%s\" to Unicode."), GetName()); - return false; - } -#endif // wxUSE_UNICODE - - free(buf.release()); // we don't need this memory any more - - - // now break the buffer in lines - - // last processed character, we need to know if it was a CR or not - wxChar chLast = '\0'; - - // the beginning of the current line, changes inside the loop - wxString::const_iterator lineStart = str.begin(); - const wxString::const_iterator end = str.end(); - for ( wxString::const_iterator p = lineStart; p != end; p++ ) - { - const wxChar ch = *p; - switch ( ch ) - { - case '\n': - // could be a DOS or Unix EOL - if ( chLast == '\r' ) - { - if ( p - 1 >= lineStart ) - { - AddLine(wxString(lineStart, p - 1), wxTextFileType_Dos); - } - else - { - // there were two line endings, so add an empty line: - AddLine(wxEmptyString, wxTextFileType_Dos); - } - } - else // bare '\n', Unix style - { - AddLine(wxString(lineStart, p), wxTextFileType_Unix); - } - - lineStart = p + 1; - break; - - case '\r': - if ( chLast == '\r' ) - { - if ( p - 1 >= lineStart ) - { - AddLine(wxString(lineStart, p - 1), wxTextFileType_Mac); - } - // Mac empty line - AddLine(wxEmptyString, wxTextFileType_Mac); - lineStart = p + 1; - } - //else: we don't know what this is yet -- could be a Mac EOL or - // start of DOS EOL so wait for next char - break; - - default: - if ( chLast == '\r' ) - { - // Mac line termination - if ( p - 1 >= lineStart ) - { - AddLine(wxString(lineStart, p - 1), wxTextFileType_Mac); - } - else - { - // there were two line endings, so add an empty line: - AddLine(wxEmptyString, wxTextFileType_Mac); - } - lineStart = p; - } - } - - chLast = ch; - } - - // anything in the last line? - if ( lineStart != end ) - { - // add unterminated last line - AddLine(wxString(lineStart, end), wxTextFileType_None); - } - - return true; -} - - -bool wxTextFile::OnWrite(wxTextFileType typeNew, const wxMBConv& conv) -{ - wxFileName fn = m_strBufferName; - - // We do NOT want wxPATH_NORM_CASE here, or the case will not - // be preserved. - if ( !fn.IsAbsolute() ) - fn.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | - wxPATH_NORM_ABSOLUTE | wxPATH_NORM_LONG); - - wxTempFile fileTmp(fn.GetFullPath()); - - if ( !fileTmp.IsOpened() ) { - wxLogError(_("can't write buffer '%s' to disk."), m_strBufferName.c_str()); - return false; - } - - size_t nCount = GetLineCount(); - for ( size_t n = 0; n < nCount; n++ ) { - fileTmp.Write(GetLine(n) + - GetEOL(typeNew == wxTextFileType_None ? GetLineType(n) - : typeNew), - conv); - } - - // replace the old file with this one - return fileTmp.Commit(); -} - -#endif // wxUSE_TEXTFILE +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/textfile.cpp +// Purpose: implementation of wxTextFile class +// Author: Vadim Zeitlin +// Modified by: +// Created: 03.04.98 +// RCS-ID: $Id: textfile.cpp 49298 2007-10-21 18:05:49Z SC $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// headers +// ============================================================================ + +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif //__BORLANDC__ + +#if !wxUSE_FILE || !wxUSE_TEXTBUFFER + #undef wxUSE_TEXTFILE + #define wxUSE_TEXTFILE 0 +#endif // wxUSE_FILE + +#if wxUSE_TEXTFILE + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/intl.h" + #include "wx/file.h" + #include "wx/log.h" +#endif + +#include "wx/textfile.h" +#include "wx/filename.h" +#include "wx/buffer.h" + +// ============================================================================ +// wxTextFile class implementation +// ============================================================================ + +wxTextFile::wxTextFile(const wxString& strFileName) + : wxTextBuffer(strFileName) +{ +} + + +// ---------------------------------------------------------------------------- +// file operations +// ---------------------------------------------------------------------------- + +bool wxTextFile::OnExists() const +{ + return wxFile::Exists(m_strBufferName); +} + + +bool wxTextFile::OnOpen(const wxString &strBufferName, wxTextBufferOpenMode OpenMode) +{ + wxFile::OpenMode FileOpenMode; + + switch ( OpenMode ) + { + default: + wxFAIL_MSG( _T("unknown open mode in wxTextFile::Open") ); + // fall through + + case ReadAccess : + FileOpenMode = wxFile::read; + break; + + case WriteAccess : + FileOpenMode = wxFile::write; + break; + } + + return m_file.Open(strBufferName.c_str(), FileOpenMode); +} + + +bool wxTextFile::OnClose() +{ + return m_file.Close(); +} + + +bool wxTextFile::OnRead(const wxMBConv& conv) +{ + // file should be opened + wxASSERT_MSG( m_file.IsOpened(), _T("can't read closed file") ); + + // read the entire file in memory: this is not the most efficient thing to + // do but there is no good way to avoid it in Unicode build because if we + // read the file block by block we can't convert each block to Unicode + // separately (the last multibyte char in the block might be only partially + // read and so the conversion would fail) and, as the file contents is kept + // in memory by wxTextFile anyhow, it shouldn't be a big problem to read + // the file entirely + size_t bufSize = 0, + bufPos = 0; + char block[1024]; + wxCharBuffer buf; + + // first determine if the file is seekable or not and so whether we can + // determine its length in advance + wxFileOffset fileLength; + { + wxLogNull logNull; + fileLength = m_file.Length(); + } + + // some non-seekable files under /proc under Linux pretend that they're + // seekable but always return 0; others do return an error + const bool seekable = fileLength != wxInvalidOffset && fileLength != 0; + if ( seekable ) + { + // we know the required length, so set the buffer size in advance + bufSize = fileLength; + if ( !buf.extend(bufSize - 1 /* it adds 1 internally */) ) + return false; + + // if the file is seekable, also check that we're at its beginning + wxASSERT_MSG( m_file.Tell() == 0, _T("should be at start of file") ); + } + + for ( ;; ) + { + ssize_t nRead = m_file.Read(block, WXSIZEOF(block)); + + if ( nRead == wxInvalidOffset ) + { + // read error (error message already given in wxFile::Read) + return false; + } + + if ( nRead == 0 ) + { + // if no bytes have been read, presumably this is a valid-but-empty file + if ( bufPos == 0 ) + return true; + + // otherwise we've finished reading the file + break; + } + + if ( seekable ) + { + // this shouldn't happen but don't overwrite the buffer if it does + wxCHECK_MSG( bufPos + nRead <= bufSize, false, + _T("read more than file length?") ); + } + else // !seekable + { + // for non-seekable files we have to allocate more memory on the go + if ( !buf.extend(bufPos + nRead - 1 /* it adds 1 internally */) ) + return false; + } + + // append to the buffer + memcpy(buf.data() + bufPos, block, nRead); + bufPos += nRead; + } + + if ( !seekable ) + { + bufSize = bufPos; + } + + const wxString str(buf, conv, bufPos); + + // there's no risk of this happening in ANSI build +#if wxUSE_UNICODE + if ( bufSize > 4 && str.empty() ) + { + wxLogError(_("Failed to convert file \"%s\" to Unicode."), GetName()); + return false; + } +#endif // wxUSE_UNICODE + + free(buf.release()); // we don't need this memory any more + + + // now break the buffer in lines + + // last processed character, we need to know if it was a CR or not + wxChar chLast = '\0'; + + // the beginning of the current line, changes inside the loop + wxString::const_iterator lineStart = str.begin(); + const wxString::const_iterator end = str.end(); + for ( wxString::const_iterator p = lineStart; p != end; p++ ) + { + const wxChar ch = *p; + switch ( ch ) + { + case '\n': + // could be a DOS or Unix EOL + if ( chLast == '\r' ) + { + if ( p - 1 >= lineStart ) + { + AddLine(wxString(lineStart, p - 1), wxTextFileType_Dos); + } + else + { + // there were two line endings, so add an empty line: + AddLine(wxEmptyString, wxTextFileType_Dos); + } + } + else // bare '\n', Unix style + { + AddLine(wxString(lineStart, p), wxTextFileType_Unix); + } + + lineStart = p + 1; + break; + + case '\r': + if ( chLast == '\r' ) + { + if ( p - 1 >= lineStart ) + { + AddLine(wxString(lineStart, p - 1), wxTextFileType_Mac); + } + // Mac empty line + AddLine(wxEmptyString, wxTextFileType_Mac); + lineStart = p + 1; + } + //else: we don't know what this is yet -- could be a Mac EOL or + // start of DOS EOL so wait for next char + break; + + default: + if ( chLast == '\r' ) + { + // Mac line termination + if ( p - 1 >= lineStart ) + { + AddLine(wxString(lineStart, p - 1), wxTextFileType_Mac); + } + else + { + // there were two line endings, so add an empty line: + AddLine(wxEmptyString, wxTextFileType_Mac); + } + lineStart = p; + } + } + + chLast = ch; + } + + // anything in the last line? + if ( lineStart != end ) + { + // add unterminated last line + AddLine(wxString(lineStart, end), wxTextFileType_None); + } + + return true; +} + + +bool wxTextFile::OnWrite(wxTextFileType typeNew, const wxMBConv& conv) +{ + wxFileName fn = m_strBufferName; + + // We do NOT want wxPATH_NORM_CASE here, or the case will not + // be preserved. + if ( !fn.IsAbsolute() ) + fn.Normalize(wxPATH_NORM_ENV_VARS | wxPATH_NORM_DOTS | wxPATH_NORM_TILDE | + wxPATH_NORM_ABSOLUTE | wxPATH_NORM_LONG); + + wxTempFile fileTmp(fn.GetFullPath()); + + if ( !fileTmp.IsOpened() ) { + wxLogError(_("can't write buffer '%s' to disk."), m_strBufferName.c_str()); + return false; + } + + size_t nCount = GetLineCount(); + for ( size_t n = 0; n < nCount; n++ ) { + fileTmp.Write(GetLine(n) + + GetEOL(typeNew == wxTextFileType_None ? GetLineType(n) + : typeNew), + conv); + } + + // replace the old file with this one + return fileTmp.Commit(); +} + +#endif // wxUSE_TEXTFILE diff --git a/Source/3rd Party/wx/src/common/timercmn.cpp b/Source/3rd Party/wx/src/common/timercmn.cpp index dd5fc39c0..43062b46d 100644 --- a/Source/3rd Party/wx/src/common/timercmn.cpp +++ b/Source/3rd Party/wx/src/common/timercmn.cpp @@ -1,88 +1,88 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: common/timercmn.cpp -// Purpose: wxTimerBase implementation -// Author: Julian Smart, Guillermo Rodriguez, Vadim Zeitlin -// Modified by: VZ: extracted all non-wxTimer stuff in stopwatch.cpp (20.06.03) -// Created: 04/01/98 -// RCS-ID: $Id: timercmn.cpp 35650 2005-09-23 12:56:45Z MR $ -// Copyright: (c) Julian Smart -// (c) 1999 Guillermo Rodriguez -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxWin headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_TIMER - -#ifndef WX_PRECOMP - #include "wx/timer.h" -#endif - -// ---------------------------------------------------------------------------- -// wxWin macros -// ---------------------------------------------------------------------------- - -IMPLEMENT_DYNAMIC_CLASS(wxTimerEvent, wxEvent) - -// ============================================================================ -// wxTimerBase implementation -// ============================================================================ - -wxTimerBase::~wxTimerBase() -{ - // this destructor is required for Darwin -} - -void wxTimerBase::Notify() -{ - // the base class version generates an event if it has owner - which it - // should because otherwise nobody can process timer events - wxCHECK_RET( m_owner, _T("wxTimer::Notify() should be overridden.") ); - - wxTimerEvent event(m_idTimer, m_milli); - event.SetEventObject(this); - (void)m_owner->ProcessEvent(event); -} - -bool wxTimerBase::Start(int milliseconds, bool oneShot) -{ - // under MSW timers only work when they're started from the main thread so - // let the caller know about it -#if wxUSE_THREADS - wxASSERT_MSG( wxThread::IsMain(), - _T("timer can only be started from the main thread") ); -#endif // wxUSE_THREADS - - if ( IsRunning() ) - { - // not stopping the already running timer might work for some - // platforms (no problems under MSW) but leads to mysterious crashes - // on the others (GTK), so to be on the safe side do it here - Stop(); - } - - if ( milliseconds != -1 ) - { - m_milli = milliseconds; - } - - m_oneShot = oneShot; - - return true; -} - -#endif // wxUSE_TIMER - +///////////////////////////////////////////////////////////////////////////// +// Name: common/timercmn.cpp +// Purpose: wxTimerBase implementation +// Author: Julian Smart, Guillermo Rodriguez, Vadim Zeitlin +// Modified by: VZ: extracted all non-wxTimer stuff in stopwatch.cpp (20.06.03) +// Created: 04/01/98 +// RCS-ID: $Id: timercmn.cpp 35650 2005-09-23 12:56:45Z MR $ +// Copyright: (c) Julian Smart +// (c) 1999 Guillermo Rodriguez +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxWin headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TIMER + +#ifndef WX_PRECOMP + #include "wx/timer.h" +#endif + +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + +IMPLEMENT_DYNAMIC_CLASS(wxTimerEvent, wxEvent) + +// ============================================================================ +// wxTimerBase implementation +// ============================================================================ + +wxTimerBase::~wxTimerBase() +{ + // this destructor is required for Darwin +} + +void wxTimerBase::Notify() +{ + // the base class version generates an event if it has owner - which it + // should because otherwise nobody can process timer events + wxCHECK_RET( m_owner, _T("wxTimer::Notify() should be overridden.") ); + + wxTimerEvent event(m_idTimer, m_milli); + event.SetEventObject(this); + (void)m_owner->ProcessEvent(event); +} + +bool wxTimerBase::Start(int milliseconds, bool oneShot) +{ + // under MSW timers only work when they're started from the main thread so + // let the caller know about it +#if wxUSE_THREADS + wxASSERT_MSG( wxThread::IsMain(), + _T("timer can only be started from the main thread") ); +#endif // wxUSE_THREADS + + if ( IsRunning() ) + { + // not stopping the already running timer might work for some + // platforms (no problems under MSW) but leads to mysterious crashes + // on the others (GTK), so to be on the safe side do it here + Stop(); + } + + if ( milliseconds != -1 ) + { + m_milli = milliseconds; + } + + m_oneShot = oneShot; + + return true; +} + +#endif // wxUSE_TIMER + diff --git a/Source/3rd Party/wx/src/common/tokenzr.cpp b/Source/3rd Party/wx/src/common/tokenzr.cpp index 448a6651f..b539458f8 100644 --- a/Source/3rd Party/wx/src/common/tokenzr.cpp +++ b/Source/3rd Party/wx/src/common/tokenzr.cpp @@ -1,229 +1,229 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/tokenzr.cpp -// Purpose: String tokenizer -// Author: Guilhem Lavaux -// Modified by: Vadim Zeitlin (almost full rewrite) -// Created: 04/22/98 -// RCS-ID: $Id: tokenzr.cpp 39694 2006-06-13 11:30:40Z ABX $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/tokenzr.h" - -#ifndef WX_PRECOMP - #include "wx/arrstr.h" -#endif - -// Required for wxIs... functions -#include - -// ============================================================================ -// implementation -// ============================================================================ - -// ---------------------------------------------------------------------------- -// wxStringTokenizer construction -// ---------------------------------------------------------------------------- - -wxStringTokenizer::wxStringTokenizer(const wxString& str, - const wxString& delims, - wxStringTokenizerMode mode) -{ - SetString(str, delims, mode); -} - -void wxStringTokenizer::SetString(const wxString& str, - const wxString& delims, - wxStringTokenizerMode mode) -{ - if ( mode == wxTOKEN_DEFAULT ) - { - // by default, we behave like strtok() if the delimiters are only - // whitespace characters and as wxTOKEN_RET_EMPTY otherwise (for - // whitespace delimiters, strtok() behaviour is better because we want - // to count consecutive spaces as one delimiter) - const wxChar *p; - for ( p = delims.c_str(); *p; p++ ) - { - if ( !wxIsspace(*p) ) - break; - } - - if ( *p ) - { - // not whitespace char in delims - mode = wxTOKEN_RET_EMPTY; - } - else - { - // only whitespaces - mode = wxTOKEN_STRTOK; - } - } - - m_delims = delims; - m_mode = mode; - - Reinit(str); -} - -void wxStringTokenizer::Reinit(const wxString& str) -{ - wxASSERT_MSG( IsOk(), _T("you should call SetString() first") ); - - m_string = str; - m_pos = 0; - m_lastDelim = _T('\0'); -} - -// ---------------------------------------------------------------------------- -// access to the tokens -// ---------------------------------------------------------------------------- - -// do we have more of them? -bool wxStringTokenizer::HasMoreTokens() const -{ - wxCHECK_MSG( IsOk(), false, _T("you should call SetString() first") ); - - if ( m_string.find_first_not_of(m_delims, m_pos) != wxString::npos ) - { - // there are non delimiter characters left, so we do have more tokens - return true; - } - - switch ( m_mode ) - { - case wxTOKEN_RET_EMPTY: - case wxTOKEN_RET_DELIMS: - // special hack for wxTOKEN_RET_EMPTY: we should return the initial - // empty token even if there are only delimiters after it - return m_pos == 0 && !m_string.empty(); - - case wxTOKEN_RET_EMPTY_ALL: - // special hack for wxTOKEN_RET_EMPTY_ALL: we can know if we had - // already returned the trailing empty token after the last - // delimiter by examining m_lastDelim: it is set to NUL if we run - // up to the end of the string in GetNextToken(), but if it is not - // NUL yet we still have this last token to return even if m_pos is - // already at m_string.length() - return m_pos < m_string.length() || m_lastDelim != _T('\0'); - - case wxTOKEN_INVALID: - case wxTOKEN_DEFAULT: - wxFAIL_MSG( _T("unexpected tokenizer mode") ); - // fall through - - case wxTOKEN_STRTOK: - // never return empty delimiters - break; - } - - return false; -} - -// count the number of (remaining) tokens in the string -size_t wxStringTokenizer::CountTokens() const -{ - wxCHECK_MSG( IsOk(), 0, _T("you should call SetString() first") ); - - // VZ: this function is IMHO not very useful, so it's probably not very - // important if its implementation here is not as efficient as it - // could be -- but OTOH like this we're sure to get the correct answer - // in all modes - wxStringTokenizer tkz(m_string.c_str() + m_pos, m_delims, m_mode); - - size_t count = 0; - while ( tkz.HasMoreTokens() ) - { - count++; - - (void)tkz.GetNextToken(); - } - - return count; -} - -// ---------------------------------------------------------------------------- -// token extraction -// ---------------------------------------------------------------------------- - -wxString wxStringTokenizer::GetNextToken() -{ - wxString token; - do - { - if ( !HasMoreTokens() ) - { - break; - } - - // find the end of this token - size_t pos = m_string.find_first_of(m_delims, m_pos); - - // and the start of the next one - if ( pos == wxString::npos ) - { - // no more delimiters, the token is everything till the end of - // string - token.assign(m_string, m_pos, wxString::npos); - - // skip the token - m_pos = m_string.length(); - - // it wasn't terminated - m_lastDelim = _T('\0'); - } - else // we found a delimiter at pos - { - // in wxTOKEN_RET_DELIMS mode we return the delimiter character - // with token, otherwise leave it out - size_t len = pos - m_pos; - if ( m_mode == wxTOKEN_RET_DELIMS ) - len++; - - token.assign(m_string, m_pos, len); - - // skip the token and the trailing delimiter - m_pos = pos + 1; - - m_lastDelim = m_string[pos]; - } - } - while ( !AllowEmpty() && token.empty() ); - - return token; -} - -// ---------------------------------------------------------------------------- -// public functions -// ---------------------------------------------------------------------------- - -wxArrayString wxStringTokenize(const wxString& str, - const wxString& delims, - wxStringTokenizerMode mode) -{ - wxArrayString tokens; - wxStringTokenizer tk(str, delims, mode); - while ( tk.HasMoreTokens() ) - { - tokens.Add(tk.GetNextToken()); - } - - return tokens; -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/tokenzr.cpp +// Purpose: String tokenizer +// Author: Guilhem Lavaux +// Modified by: Vadim Zeitlin (almost full rewrite) +// Created: 04/22/98 +// RCS-ID: $Id: tokenzr.cpp 39694 2006-06-13 11:30:40Z ABX $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/tokenzr.h" + +#ifndef WX_PRECOMP + #include "wx/arrstr.h" +#endif + +// Required for wxIs... functions +#include + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxStringTokenizer construction +// ---------------------------------------------------------------------------- + +wxStringTokenizer::wxStringTokenizer(const wxString& str, + const wxString& delims, + wxStringTokenizerMode mode) +{ + SetString(str, delims, mode); +} + +void wxStringTokenizer::SetString(const wxString& str, + const wxString& delims, + wxStringTokenizerMode mode) +{ + if ( mode == wxTOKEN_DEFAULT ) + { + // by default, we behave like strtok() if the delimiters are only + // whitespace characters and as wxTOKEN_RET_EMPTY otherwise (for + // whitespace delimiters, strtok() behaviour is better because we want + // to count consecutive spaces as one delimiter) + const wxChar *p; + for ( p = delims.c_str(); *p; p++ ) + { + if ( !wxIsspace(*p) ) + break; + } + + if ( *p ) + { + // not whitespace char in delims + mode = wxTOKEN_RET_EMPTY; + } + else + { + // only whitespaces + mode = wxTOKEN_STRTOK; + } + } + + m_delims = delims; + m_mode = mode; + + Reinit(str); +} + +void wxStringTokenizer::Reinit(const wxString& str) +{ + wxASSERT_MSG( IsOk(), _T("you should call SetString() first") ); + + m_string = str; + m_pos = 0; + m_lastDelim = _T('\0'); +} + +// ---------------------------------------------------------------------------- +// access to the tokens +// ---------------------------------------------------------------------------- + +// do we have more of them? +bool wxStringTokenizer::HasMoreTokens() const +{ + wxCHECK_MSG( IsOk(), false, _T("you should call SetString() first") ); + + if ( m_string.find_first_not_of(m_delims, m_pos) != wxString::npos ) + { + // there are non delimiter characters left, so we do have more tokens + return true; + } + + switch ( m_mode ) + { + case wxTOKEN_RET_EMPTY: + case wxTOKEN_RET_DELIMS: + // special hack for wxTOKEN_RET_EMPTY: we should return the initial + // empty token even if there are only delimiters after it + return m_pos == 0 && !m_string.empty(); + + case wxTOKEN_RET_EMPTY_ALL: + // special hack for wxTOKEN_RET_EMPTY_ALL: we can know if we had + // already returned the trailing empty token after the last + // delimiter by examining m_lastDelim: it is set to NUL if we run + // up to the end of the string in GetNextToken(), but if it is not + // NUL yet we still have this last token to return even if m_pos is + // already at m_string.length() + return m_pos < m_string.length() || m_lastDelim != _T('\0'); + + case wxTOKEN_INVALID: + case wxTOKEN_DEFAULT: + wxFAIL_MSG( _T("unexpected tokenizer mode") ); + // fall through + + case wxTOKEN_STRTOK: + // never return empty delimiters + break; + } + + return false; +} + +// count the number of (remaining) tokens in the string +size_t wxStringTokenizer::CountTokens() const +{ + wxCHECK_MSG( IsOk(), 0, _T("you should call SetString() first") ); + + // VZ: this function is IMHO not very useful, so it's probably not very + // important if its implementation here is not as efficient as it + // could be -- but OTOH like this we're sure to get the correct answer + // in all modes + wxStringTokenizer tkz(m_string.c_str() + m_pos, m_delims, m_mode); + + size_t count = 0; + while ( tkz.HasMoreTokens() ) + { + count++; + + (void)tkz.GetNextToken(); + } + + return count; +} + +// ---------------------------------------------------------------------------- +// token extraction +// ---------------------------------------------------------------------------- + +wxString wxStringTokenizer::GetNextToken() +{ + wxString token; + do + { + if ( !HasMoreTokens() ) + { + break; + } + + // find the end of this token + size_t pos = m_string.find_first_of(m_delims, m_pos); + + // and the start of the next one + if ( pos == wxString::npos ) + { + // no more delimiters, the token is everything till the end of + // string + token.assign(m_string, m_pos, wxString::npos); + + // skip the token + m_pos = m_string.length(); + + // it wasn't terminated + m_lastDelim = _T('\0'); + } + else // we found a delimiter at pos + { + // in wxTOKEN_RET_DELIMS mode we return the delimiter character + // with token, otherwise leave it out + size_t len = pos - m_pos; + if ( m_mode == wxTOKEN_RET_DELIMS ) + len++; + + token.assign(m_string, m_pos, len); + + // skip the token and the trailing delimiter + m_pos = pos + 1; + + m_lastDelim = m_string[pos]; + } + } + while ( !AllowEmpty() && token.empty() ); + + return token; +} + +// ---------------------------------------------------------------------------- +// public functions +// ---------------------------------------------------------------------------- + +wxArrayString wxStringTokenize(const wxString& str, + const wxString& delims, + wxStringTokenizerMode mode) +{ + wxArrayString tokens; + wxStringTokenizer tk(str, delims, mode); + while ( tk.HasMoreTokens() ) + { + tokens.Add(tk.GetNextToken()); + } + + return tokens; +} diff --git a/Source/3rd Party/wx/src/common/toplvcmn.cpp b/Source/3rd Party/wx/src/common/toplvcmn.cpp index badf84ed2..304dd3ca7 100644 --- a/Source/3rd Party/wx/src/common/toplvcmn.cpp +++ b/Source/3rd Party/wx/src/common/toplvcmn.cpp @@ -1,431 +1,431 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/toplvcmn.cpp -// Purpose: common (for all platforms) wxTopLevelWindow functions -// Author: Julian Smart, Vadim Zeitlin -// Created: 01/02/97 -// Id: $Id: toplvcmn.cpp 53617 2008-05-17 12:56:18Z VZ $ -// Copyright: (c) 1998 Robert Roebling and Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/toplevel.h" - -#ifndef WX_PRECOMP - #include "wx/dcclient.h" - #include "wx/app.h" -#endif // WX_PRECOMP - -#include "wx/display.h" - -// ---------------------------------------------------------------------------- -// event table -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxTopLevelWindowBase, wxWindow) - EVT_CLOSE(wxTopLevelWindowBase::OnCloseWindow) - EVT_SIZE(wxTopLevelWindowBase::OnSize) -END_EVENT_TABLE() - -// ============================================================================ -// implementation -// ============================================================================ - -IMPLEMENT_ABSTRACT_CLASS(wxTopLevelWindow, wxWindow) - -// ---------------------------------------------------------------------------- -// construction/destruction -// ---------------------------------------------------------------------------- - -wxTopLevelWindowBase::wxTopLevelWindowBase() -{ - // Unlike windows, top level windows are created hidden by default. - m_isShown = false; - m_winDefault = NULL; - m_winTmpDefault = NULL; -} - -wxTopLevelWindowBase::~wxTopLevelWindowBase() -{ - // don't let wxTheApp keep any stale pointers to us - if ( wxTheApp && wxTheApp->GetTopWindow() == this ) - wxTheApp->SetTopWindow(NULL); - - wxTopLevelWindows.DeleteObject(this); - - if ( IsLastBeforeExit() ) - { - // no other (important) windows left, quit the app - wxTheApp->ExitMainLoop(); - } -} - -bool wxTopLevelWindowBase::Destroy() -{ - // delayed destruction: the frame will be deleted during the next idle - // loop iteration - if ( !wxPendingDelete.Member(this) ) - wxPendingDelete.Append(this); - -#ifdef __WXMAC__ - // on mac we know that objects will always be deleted after this event - // has been handled, using Hide we avoid erratic redraws during window - // tear down - Hide(); -#else // !__WXMAC__ - // normally we want to hide the window immediately so that it doesn't get - // stuck on the screen while it's being destroyed, however we shouldn't - // hide the last visible window as then we might not get any idle events - // any more as no events will be sent to the hidden window and without idle - // events we won't prune wxPendingDelete list and the application won't - // terminate - for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(), - end = wxTopLevelWindows.end(); - i != end; - ++i ) - { - wxTopLevelWindow * const win = wx_static_cast(wxTopLevelWindow *, *i); - if ( win != this && win->IsShown() ) - { - // there remains at least one other visible TLW, we can hide this - // one - Hide(); - - break; - } - } -#endif // __WXMAC__/!__WXMAC__ - - return true; -} - -bool wxTopLevelWindowBase::IsLastBeforeExit() const -{ - // first of all, automatically exiting the app on last window close can be - // completely disabled at wxTheApp level - if ( !wxTheApp || !wxTheApp->GetExitOnFrameDelete() ) - return false; - - wxWindowList::const_iterator i; - const wxWindowList::const_iterator end = wxTopLevelWindows.end(); - - // then decide whether we should exit at all - for ( i = wxTopLevelWindows.begin(); i != end; ++i ) - { - wxTopLevelWindow * const win = wx_static_cast(wxTopLevelWindow *, *i); - if ( win->ShouldPreventAppExit() ) - { - // there remains at least one important TLW, don't exit - return false; - } - } - - // if yes, close all the other windows: this could still fail - for ( i = wxTopLevelWindows.begin(); i != end; ++i ) - { - // don't close twice the windows which are already marked for deletion - wxTopLevelWindow * const win = wx_static_cast(wxTopLevelWindow *, *i); - if ( !wxPendingDelete.Member(win) && !win->Close() ) - { - // one of the windows refused to close, don't exit - // - // NB: of course, by now some other windows could have been already - // closed but there is really nothing we can do about it as we - // have no way just to ask the window if it can close without - // forcing it to do it - return false; - } - } - - return true; -} - -// ---------------------------------------------------------------------------- -// wxTopLevelWindow geometry -// ---------------------------------------------------------------------------- - -void wxTopLevelWindowBase::SetMinSize(const wxSize& minSize) -{ - SetSizeHints( minSize.x, minSize.y, GetMaxWidth(), GetMaxHeight() ); -} - -void wxTopLevelWindowBase::SetMaxSize(const wxSize& maxSize) -{ - SetSizeHints( GetMinWidth(), GetMinHeight(), maxSize.x, maxSize.y ); -} - -// set the min/max size of the window -void wxTopLevelWindowBase::DoSetSizeHints(int minW, int minH, - int maxW, int maxH, - int WXUNUSED(incW), int WXUNUSED(incH)) -{ - // setting min width greater than max width leads to infinite loops under - // X11 and generally doesn't make any sense, so don't allow it - wxCHECK_RET( (minW == wxDefaultCoord || maxW == wxDefaultCoord || minW <= maxW) && - (minH == wxDefaultCoord || maxH == wxDefaultCoord || minH <= maxH), - _T("min width/height must be less than max width/height!") ); - - m_minWidth = minW; - m_maxWidth = maxW; - m_minHeight = minH; - m_maxHeight = maxH; -} - -void wxTopLevelWindowBase::GetRectForTopLevelChildren(int *x, int *y, int *w, int *h) -{ - GetPosition(x,y); - GetSize(w,h); -} - -/* static */ -wxSize wxTopLevelWindowBase::GetDefaultSize() -{ - wxSize size = wxGetClientDisplayRect().GetSize(); - - // create proportionally bigger windows on small screens - if ( size.x >= 1024 ) - size.x = 400; - else if ( size.x >= 800 ) - size.x = 300; - else if ( size.x >= 320 ) - size.x = 240; - - if ( size.y >= 768 ) - size.y = 250; - else if ( size.y > 200 ) - { - size.y *= 2; - size.y /= 3; - } - - return size; -} - -void wxTopLevelWindowBase::DoCentre(int dir) -{ - // on some platforms centering top level windows is impossible - // because they are always maximized by guidelines or limitations - if(IsAlwaysMaximized()) - return; - - // we need the display rect anyhow so store it first: notice that we should - // be centered on the same display as our parent window, the display of - // this window itself is not really defined yet - int nDisplay = wxDisplay::GetFromWindow(GetParent() ? GetParent() : this); - wxDisplay dpy(nDisplay == wxNOT_FOUND ? 0 : nDisplay); - const wxRect rectDisplay(dpy.GetClientArea()); - - // what should we centre this window on? - wxRect rectParent; - if ( !(dir & wxCENTRE_ON_SCREEN) && GetParent() ) - { - // centre on parent window: notice that we need screen coordinates for - // positioning this TLW - rectParent = GetParent()->GetScreenRect(); - - // if the parent is entirely off screen (happens at least with MDI - // parent frame under Mac but could happen elsewhere too if the frame - // was hidden/moved away for some reason), don't use it as otherwise - // this window wouldn't be visible at all - if ( !rectDisplay.Contains(rectParent.GetTopLeft()) && - !rectParent.Contains(rectParent.GetBottomRight()) ) - { - // this is enough to make IsEmpty() test below pass - rectParent.width = 0; - } - } - - if ( rectParent.IsEmpty() ) - { - // we were explicitely asked to centre this window on the entire screen - // or if we have no parent anyhow and so can't centre on it - rectParent = rectDisplay; - } - - // centering maximized window on screen is no-op - if((rectParent == rectDisplay) && IsMaximized()) - return; - - if ( !(dir & wxBOTH) ) - dir |= wxBOTH; // if neither is specified, center in both directions - - // the new window rect candidate - wxRect rect = GetRect().CentreIn(rectParent, dir & ~wxCENTRE_ON_SCREEN); - - // we don't want to place the window off screen if Centre() is called as - // this is (almost?) never wanted and it would be very difficult to prevent - // it from happening from the user code if we didn't check for it here - if ( !rectDisplay.Contains(rect.GetTopLeft()) ) - { - // move the window just enough to make the corner visible - int dx = rectDisplay.GetLeft() - rect.GetLeft(); - int dy = rectDisplay.GetTop() - rect.GetTop(); - rect.Offset(dx > 0 ? dx : 0, dy > 0 ? dy : 0); - } - - if ( !rectDisplay.Contains(rect.GetBottomRight()) ) - { - // do the same for this corner too - int dx = rectDisplay.GetRight() - rect.GetRight(); - int dy = rectDisplay.GetBottom() - rect.GetBottom(); - rect.Offset(dx < 0 ? dx : 0, dy < 0 ? dy : 0); - } - - // the window top left and bottom right corner are both visible now and - // although the window might still be not entirely on screen (with 2 - // staggered displays for example) we wouldn't be able to improve the - // layout much in such case, so we stop here - - // -1 could be valid coordinate here if there are several displays - SetSize(rect, wxSIZE_ALLOW_MINUS_ONE); -} - -// ---------------------------------------------------------------------------- -// wxTopLevelWindow size management: we exclude the areas taken by -// menu/status/toolbars from the client area, so the client area is what's -// really available for the frame contents -// ---------------------------------------------------------------------------- - -void wxTopLevelWindowBase::DoScreenToClient(int *x, int *y) const -{ - wxWindow::DoScreenToClient(x, y); - - // translate the wxWindow client coords to our client coords - wxPoint pt(GetClientAreaOrigin()); - if ( x ) - *x -= pt.x; - if ( y ) - *y -= pt.y; -} - -void wxTopLevelWindowBase::DoClientToScreen(int *x, int *y) const -{ - // our client area origin (0, 0) may be really something like (0, 30) for - // wxWindow if we have a toolbar, account for it before translating - wxPoint pt(GetClientAreaOrigin()); - if ( x ) - *x += pt.x; - if ( y ) - *y += pt.y; - - wxWindow::DoClientToScreen(x, y); -} - -bool wxTopLevelWindowBase::IsAlwaysMaximized() const -{ -#if defined(__SMARTPHONE__) || defined(__POCKETPC__) - return true; -#else - return false; -#endif -} - -// ---------------------------------------------------------------------------- -// event handlers -// ---------------------------------------------------------------------------- - -// default resizing behaviour - if only ONE subwindow, resize to fill the -// whole client area -void wxTopLevelWindowBase::DoLayout() -{ - // if we're using constraints or sizers - do use them - if ( GetAutoLayout() ) - { - Layout(); - } - else - { - // do we have _exactly_ one child? - wxWindow *child = (wxWindow *)NULL; - for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - wxWindow *win = node->GetData(); - - // exclude top level and managed windows (status bar isn't - // currently in the children list except under wxMac anyhow, but - // it makes no harm to test for it) - if ( !win->IsTopLevel() && !IsOneOfBars(win) ) - { - if ( child ) - { - return; // it's our second subwindow - nothing to do - } - - child = win; - } - } - - // do we have any children at all? - if ( child && child->IsShown() ) - { - // exactly one child - set it's size to fill the whole frame - int clientW, clientH; - DoGetClientSize(&clientW, &clientH); - - child->SetSize(0, 0, clientW, clientH); - } - } -} - -// The default implementation for the close window event. -void wxTopLevelWindowBase::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) -{ - Destroy(); -} - -bool wxTopLevelWindowBase::SendIconizeEvent(bool iconized) -{ - wxIconizeEvent event(GetId(), iconized); - event.SetEventObject(this); - - return GetEventHandler()->ProcessEvent(event); -} - -// do the window-specific processing after processing the update event -void wxTopLevelWindowBase::DoUpdateWindowUI(wxUpdateUIEvent& event) -{ - // call inherited, but skip the wxControl's version, and call directly the - // wxWindow's one instead, because the only reason why we are overriding this - // function is that we want to use SetTitle() instead of wxControl::SetLabel() - wxWindowBase::DoUpdateWindowUI(event); - - // update title - if ( event.GetSetText() ) - { - if ( event.GetText() != GetTitle() ) - SetTitle(event.GetText()); - } -} - -void wxTopLevelWindowBase::RequestUserAttention(int WXUNUSED(flags)) -{ - // it's probably better than do nothing, isn't it? - Raise(); -} - -void wxTopLevelWindowBase::RemoveChild(wxWindowBase *child) -{ - if ( child == m_winDefault ) - m_winDefault = NULL; - - if ( child == m_winTmpDefault ) - m_winTmpDefault = NULL; - - wxWindow::RemoveChild(child); -} +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/toplvcmn.cpp +// Purpose: common (for all platforms) wxTopLevelWindow functions +// Author: Julian Smart, Vadim Zeitlin +// Created: 01/02/97 +// Id: $Id: toplvcmn.cpp 53617 2008-05-17 12:56:18Z VZ $ +// Copyright: (c) 1998 Robert Roebling and Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/toplevel.h" + +#ifndef WX_PRECOMP + #include "wx/dcclient.h" + #include "wx/app.h" +#endif // WX_PRECOMP + +#include "wx/display.h" + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxTopLevelWindowBase, wxWindow) + EVT_CLOSE(wxTopLevelWindowBase::OnCloseWindow) + EVT_SIZE(wxTopLevelWindowBase::OnSize) +END_EVENT_TABLE() + +// ============================================================================ +// implementation +// ============================================================================ + +IMPLEMENT_ABSTRACT_CLASS(wxTopLevelWindow, wxWindow) + +// ---------------------------------------------------------------------------- +// construction/destruction +// ---------------------------------------------------------------------------- + +wxTopLevelWindowBase::wxTopLevelWindowBase() +{ + // Unlike windows, top level windows are created hidden by default. + m_isShown = false; + m_winDefault = NULL; + m_winTmpDefault = NULL; +} + +wxTopLevelWindowBase::~wxTopLevelWindowBase() +{ + // don't let wxTheApp keep any stale pointers to us + if ( wxTheApp && wxTheApp->GetTopWindow() == this ) + wxTheApp->SetTopWindow(NULL); + + wxTopLevelWindows.DeleteObject(this); + + if ( IsLastBeforeExit() ) + { + // no other (important) windows left, quit the app + wxTheApp->ExitMainLoop(); + } +} + +bool wxTopLevelWindowBase::Destroy() +{ + // delayed destruction: the frame will be deleted during the next idle + // loop iteration + if ( !wxPendingDelete.Member(this) ) + wxPendingDelete.Append(this); + +#ifdef __WXMAC__ + // on mac we know that objects will always be deleted after this event + // has been handled, using Hide we avoid erratic redraws during window + // tear down + Hide(); +#else // !__WXMAC__ + // normally we want to hide the window immediately so that it doesn't get + // stuck on the screen while it's being destroyed, however we shouldn't + // hide the last visible window as then we might not get any idle events + // any more as no events will be sent to the hidden window and without idle + // events we won't prune wxPendingDelete list and the application won't + // terminate + for ( wxWindowList::const_iterator i = wxTopLevelWindows.begin(), + end = wxTopLevelWindows.end(); + i != end; + ++i ) + { + wxTopLevelWindow * const win = wx_static_cast(wxTopLevelWindow *, *i); + if ( win != this && win->IsShown() ) + { + // there remains at least one other visible TLW, we can hide this + // one + Hide(); + + break; + } + } +#endif // __WXMAC__/!__WXMAC__ + + return true; +} + +bool wxTopLevelWindowBase::IsLastBeforeExit() const +{ + // first of all, automatically exiting the app on last window close can be + // completely disabled at wxTheApp level + if ( !wxTheApp || !wxTheApp->GetExitOnFrameDelete() ) + return false; + + wxWindowList::const_iterator i; + const wxWindowList::const_iterator end = wxTopLevelWindows.end(); + + // then decide whether we should exit at all + for ( i = wxTopLevelWindows.begin(); i != end; ++i ) + { + wxTopLevelWindow * const win = wx_static_cast(wxTopLevelWindow *, *i); + if ( win->ShouldPreventAppExit() ) + { + // there remains at least one important TLW, don't exit + return false; + } + } + + // if yes, close all the other windows: this could still fail + for ( i = wxTopLevelWindows.begin(); i != end; ++i ) + { + // don't close twice the windows which are already marked for deletion + wxTopLevelWindow * const win = wx_static_cast(wxTopLevelWindow *, *i); + if ( !wxPendingDelete.Member(win) && !win->Close() ) + { + // one of the windows refused to close, don't exit + // + // NB: of course, by now some other windows could have been already + // closed but there is really nothing we can do about it as we + // have no way just to ask the window if it can close without + // forcing it to do it + return false; + } + } + + return true; +} + +// ---------------------------------------------------------------------------- +// wxTopLevelWindow geometry +// ---------------------------------------------------------------------------- + +void wxTopLevelWindowBase::SetMinSize(const wxSize& minSize) +{ + SetSizeHints( minSize.x, minSize.y, GetMaxWidth(), GetMaxHeight() ); +} + +void wxTopLevelWindowBase::SetMaxSize(const wxSize& maxSize) +{ + SetSizeHints( GetMinWidth(), GetMinHeight(), maxSize.x, maxSize.y ); +} + +// set the min/max size of the window +void wxTopLevelWindowBase::DoSetSizeHints(int minW, int minH, + int maxW, int maxH, + int WXUNUSED(incW), int WXUNUSED(incH)) +{ + // setting min width greater than max width leads to infinite loops under + // X11 and generally doesn't make any sense, so don't allow it + wxCHECK_RET( (minW == wxDefaultCoord || maxW == wxDefaultCoord || minW <= maxW) && + (minH == wxDefaultCoord || maxH == wxDefaultCoord || minH <= maxH), + _T("min width/height must be less than max width/height!") ); + + m_minWidth = minW; + m_maxWidth = maxW; + m_minHeight = minH; + m_maxHeight = maxH; +} + +void wxTopLevelWindowBase::GetRectForTopLevelChildren(int *x, int *y, int *w, int *h) +{ + GetPosition(x,y); + GetSize(w,h); +} + +/* static */ +wxSize wxTopLevelWindowBase::GetDefaultSize() +{ + wxSize size = wxGetClientDisplayRect().GetSize(); + + // create proportionally bigger windows on small screens + if ( size.x >= 1024 ) + size.x = 400; + else if ( size.x >= 800 ) + size.x = 300; + else if ( size.x >= 320 ) + size.x = 240; + + if ( size.y >= 768 ) + size.y = 250; + else if ( size.y > 200 ) + { + size.y *= 2; + size.y /= 3; + } + + return size; +} + +void wxTopLevelWindowBase::DoCentre(int dir) +{ + // on some platforms centering top level windows is impossible + // because they are always maximized by guidelines or limitations + if(IsAlwaysMaximized()) + return; + + // we need the display rect anyhow so store it first: notice that we should + // be centered on the same display as our parent window, the display of + // this window itself is not really defined yet + int nDisplay = wxDisplay::GetFromWindow(GetParent() ? GetParent() : this); + wxDisplay dpy(nDisplay == wxNOT_FOUND ? 0 : nDisplay); + const wxRect rectDisplay(dpy.GetClientArea()); + + // what should we centre this window on? + wxRect rectParent; + if ( !(dir & wxCENTRE_ON_SCREEN) && GetParent() ) + { + // centre on parent window: notice that we need screen coordinates for + // positioning this TLW + rectParent = GetParent()->GetScreenRect(); + + // if the parent is entirely off screen (happens at least with MDI + // parent frame under Mac but could happen elsewhere too if the frame + // was hidden/moved away for some reason), don't use it as otherwise + // this window wouldn't be visible at all + if ( !rectDisplay.Contains(rectParent.GetTopLeft()) && + !rectParent.Contains(rectParent.GetBottomRight()) ) + { + // this is enough to make IsEmpty() test below pass + rectParent.width = 0; + } + } + + if ( rectParent.IsEmpty() ) + { + // we were explicitely asked to centre this window on the entire screen + // or if we have no parent anyhow and so can't centre on it + rectParent = rectDisplay; + } + + // centering maximized window on screen is no-op + if((rectParent == rectDisplay) && IsMaximized()) + return; + + if ( !(dir & wxBOTH) ) + dir |= wxBOTH; // if neither is specified, center in both directions + + // the new window rect candidate + wxRect rect = GetRect().CentreIn(rectParent, dir & ~wxCENTRE_ON_SCREEN); + + // we don't want to place the window off screen if Centre() is called as + // this is (almost?) never wanted and it would be very difficult to prevent + // it from happening from the user code if we didn't check for it here + if ( !rectDisplay.Contains(rect.GetTopLeft()) ) + { + // move the window just enough to make the corner visible + int dx = rectDisplay.GetLeft() - rect.GetLeft(); + int dy = rectDisplay.GetTop() - rect.GetTop(); + rect.Offset(dx > 0 ? dx : 0, dy > 0 ? dy : 0); + } + + if ( !rectDisplay.Contains(rect.GetBottomRight()) ) + { + // do the same for this corner too + int dx = rectDisplay.GetRight() - rect.GetRight(); + int dy = rectDisplay.GetBottom() - rect.GetBottom(); + rect.Offset(dx < 0 ? dx : 0, dy < 0 ? dy : 0); + } + + // the window top left and bottom right corner are both visible now and + // although the window might still be not entirely on screen (with 2 + // staggered displays for example) we wouldn't be able to improve the + // layout much in such case, so we stop here + + // -1 could be valid coordinate here if there are several displays + SetSize(rect, wxSIZE_ALLOW_MINUS_ONE); +} + +// ---------------------------------------------------------------------------- +// wxTopLevelWindow size management: we exclude the areas taken by +// menu/status/toolbars from the client area, so the client area is what's +// really available for the frame contents +// ---------------------------------------------------------------------------- + +void wxTopLevelWindowBase::DoScreenToClient(int *x, int *y) const +{ + wxWindow::DoScreenToClient(x, y); + + // translate the wxWindow client coords to our client coords + wxPoint pt(GetClientAreaOrigin()); + if ( x ) + *x -= pt.x; + if ( y ) + *y -= pt.y; +} + +void wxTopLevelWindowBase::DoClientToScreen(int *x, int *y) const +{ + // our client area origin (0, 0) may be really something like (0, 30) for + // wxWindow if we have a toolbar, account for it before translating + wxPoint pt(GetClientAreaOrigin()); + if ( x ) + *x += pt.x; + if ( y ) + *y += pt.y; + + wxWindow::DoClientToScreen(x, y); +} + +bool wxTopLevelWindowBase::IsAlwaysMaximized() const +{ +#if defined(__SMARTPHONE__) || defined(__POCKETPC__) + return true; +#else + return false; +#endif +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +// default resizing behaviour - if only ONE subwindow, resize to fill the +// whole client area +void wxTopLevelWindowBase::DoLayout() +{ + // if we're using constraints or sizers - do use them + if ( GetAutoLayout() ) + { + Layout(); + } + else + { + // do we have _exactly_ one child? + wxWindow *child = (wxWindow *)NULL; + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindow *win = node->GetData(); + + // exclude top level and managed windows (status bar isn't + // currently in the children list except under wxMac anyhow, but + // it makes no harm to test for it) + if ( !win->IsTopLevel() && !IsOneOfBars(win) ) + { + if ( child ) + { + return; // it's our second subwindow - nothing to do + } + + child = win; + } + } + + // do we have any children at all? + if ( child && child->IsShown() ) + { + // exactly one child - set it's size to fill the whole frame + int clientW, clientH; + DoGetClientSize(&clientW, &clientH); + + child->SetSize(0, 0, clientW, clientH); + } + } +} + +// The default implementation for the close window event. +void wxTopLevelWindowBase::OnCloseWindow(wxCloseEvent& WXUNUSED(event)) +{ + Destroy(); +} + +bool wxTopLevelWindowBase::SendIconizeEvent(bool iconized) +{ + wxIconizeEvent event(GetId(), iconized); + event.SetEventObject(this); + + return GetEventHandler()->ProcessEvent(event); +} + +// do the window-specific processing after processing the update event +void wxTopLevelWindowBase::DoUpdateWindowUI(wxUpdateUIEvent& event) +{ + // call inherited, but skip the wxControl's version, and call directly the + // wxWindow's one instead, because the only reason why we are overriding this + // function is that we want to use SetTitle() instead of wxControl::SetLabel() + wxWindowBase::DoUpdateWindowUI(event); + + // update title + if ( event.GetSetText() ) + { + if ( event.GetText() != GetTitle() ) + SetTitle(event.GetText()); + } +} + +void wxTopLevelWindowBase::RequestUserAttention(int WXUNUSED(flags)) +{ + // it's probably better than do nothing, isn't it? + Raise(); +} + +void wxTopLevelWindowBase::RemoveChild(wxWindowBase *child) +{ + if ( child == m_winDefault ) + m_winDefault = NULL; + + if ( child == m_winTmpDefault ) + m_winTmpDefault = NULL; + + wxWindow::RemoveChild(child); +} diff --git a/Source/3rd Party/wx/src/common/treebase.cpp b/Source/3rd Party/wx/src/common/treebase.cpp index 2299e994e..8613ab1d3 100644 --- a/Source/3rd Party/wx/src/common/treebase.cpp +++ b/Source/3rd Party/wx/src/common/treebase.cpp @@ -1,239 +1,239 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: treebase.cpp -// Purpose: Base wxTreeCtrl classes -// Author: Julian Smart -// Created: 01/02/97 -// Modified: -// Id: $Id: treebase.cpp 51356 2008-01-24 11:23:30Z VZ $ -// Copyright: (c) 1998 Robert Roebling, Julian Smart et al -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================= -// declarations -// ============================================================================= - -// ----------------------------------------------------------------------------- -// headers -// ----------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_TREECTRL - -#include "wx/treectrl.h" -#include "wx/imaglist.h" - -// ---------------------------------------------------------------------------- -// events -// ---------------------------------------------------------------------------- - -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_DRAG) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_RDRAG) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_LABEL_EDIT) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_DELETE_ITEM) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_GET_INFO) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SET_INFO) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDING) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSING) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SEL_CHANGED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SEL_CHANGING) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_KEY_DOWN) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_ACTIVATED) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_DRAG) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP) -DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MENU) - -// ---------------------------------------------------------------------------- -// Tree event -// ---------------------------------------------------------------------------- - -IMPLEMENT_ABSTRACT_CLASS(wxTreeEvent, wxNotifyEvent) - - -wxTreeEvent::wxTreeEvent(wxEventType commandType, - wxTreeCtrlBase *tree, - const wxTreeItemId& item) - : wxNotifyEvent(commandType, tree->GetId()), - m_item(item) -{ - m_editCancelled = false; - - SetEventObject(tree); - - if ( item.IsOk() ) - SetClientObject(tree->GetItemData(item)); -} - -wxTreeEvent::wxTreeEvent(wxEventType commandType, int id) - : wxNotifyEvent(commandType, id) -{ - m_itemOld = 0l; - m_editCancelled = false; -} - -wxTreeEvent::wxTreeEvent(const wxTreeEvent & event) - : wxNotifyEvent(event) -{ - m_evtKey = event.m_evtKey; - m_item = event.m_item; - m_itemOld = event.m_itemOld; - m_pointDrag = event.m_pointDrag; - m_label = event.m_label; - m_editCancelled = event.m_editCancelled; -} - -// ---------------------------------------------------------------------------- -// wxTreeCtrlBase -// ---------------------------------------------------------------------------- - -wxTreeCtrlBase::~wxTreeCtrlBase() -{ - if (m_ownsImageListNormal) - delete m_imageListNormal; - if (m_ownsImageListState) - delete m_imageListState; -} - -static void -wxGetBestTreeSize(const wxTreeCtrlBase* treeCtrl, wxTreeItemId id, wxSize& size) -{ - wxRect rect; - - if ( treeCtrl->GetBoundingRect(id, rect, true /* just the item */) ) - { - // Translate to logical position so we get the full extent -#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) - rect.x += treeCtrl->GetScrollPos(wxHORIZONTAL); - rect.y += treeCtrl->GetScrollPos(wxVERTICAL); -#endif - - size.IncTo(wxSize(rect.GetRight(), rect.GetBottom())); - } - - wxTreeItemIdValue cookie; - for ( wxTreeItemId item = treeCtrl->GetFirstChild(id, cookie); - item.IsOk(); - item = treeCtrl->GetNextChild(id, cookie) ) - { - wxGetBestTreeSize(treeCtrl, item, size); - } -} - -wxSize wxTreeCtrlBase::DoGetBestSize() const -{ - wxSize size; - - // this doesn't really compute the total bounding rectangle of all items - // but a not too bad guess of it which has the advantage of not having to - // examine all (potentially hundreds or thousands) items in the control - - if (GetQuickBestSize()) - { - for ( wxTreeItemId item = GetRootItem(); - item.IsOk(); - item = GetLastChild(item) ) - { - wxRect rect; - - // last parameter is "true" to get only the dimensions of the text - // label, we don't want to get the entire item width as it's determined - // by the current size - if ( GetBoundingRect(item, rect, true) ) - { - if ( size.x < rect.x + rect.width ) - size.x = rect.x + rect.width; - if ( size.y < rect.y + rect.height ) - size.y = rect.y + rect.height; - } - } - } - else // use precise, if potentially slow, size computation method - { - // iterate over all items recursively - wxTreeItemId idRoot = GetRootItem(); - if ( idRoot.IsOk() ) - wxGetBestTreeSize(this, idRoot, size); - } - - // need some minimal size even for empty tree - if ( !size.x || !size.y ) - size = wxControl::DoGetBestSize(); - else - { - // Add border size - size += GetWindowBorderSize(); - - CacheBestSize(size); - } - - return size; -} - -void wxTreeCtrlBase::ExpandAll() -{ - if ( IsEmpty() ) - return; - - ExpandAllChildren(GetRootItem()); -} - -void wxTreeCtrlBase::ExpandAllChildren(const wxTreeItemId& item) -{ - // expand this item first, this might result in its children being added on - // the fly - if ( item != GetRootItem() || !HasFlag(wxTR_HIDE_ROOT) ) - Expand(item); - //else: expanding hidden root item is unsupported and unnecessary - - // then (recursively) expand all the children - wxTreeItemIdValue cookie; - for ( wxTreeItemId idCurr = GetFirstChild(item, cookie); - idCurr.IsOk(); - idCurr = GetNextChild(item, cookie) ) - { - ExpandAllChildren(idCurr); - } -} - -void wxTreeCtrlBase::CollapseAll() -{ - if ( IsEmpty() ) - return; - - CollapseAllChildren(GetRootItem()); -} - -void wxTreeCtrlBase::CollapseAllChildren(const wxTreeItemId& item) -{ - // first (recursively) collapse all the children - wxTreeItemIdValue cookie; - for ( wxTreeItemId idCurr = GetFirstChild(item, cookie); - idCurr.IsOk(); - idCurr = GetNextChild(item, cookie) ) - { - CollapseAllChildren(idCurr); - } - - // then collapse this element too - Collapse(item); -} - -bool wxTreeCtrlBase::IsEmpty() const -{ - return !GetRootItem().IsOk(); -} - -#endif // wxUSE_TREECTRL - +///////////////////////////////////////////////////////////////////////////// +// Name: treebase.cpp +// Purpose: Base wxTreeCtrl classes +// Author: Julian Smart +// Created: 01/02/97 +// Modified: +// Id: $Id: treebase.cpp 51356 2008-01-24 11:23:30Z VZ $ +// Copyright: (c) 1998 Robert Roebling, Julian Smart et al +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================= +// declarations +// ============================================================================= + +// ----------------------------------------------------------------------------- +// headers +// ----------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_TREECTRL + +#include "wx/treectrl.h" +#include "wx/imaglist.h" + +// ---------------------------------------------------------------------------- +// events +// ---------------------------------------------------------------------------- + +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_DRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_RDRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_LABEL_EDIT) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_DELETE_ITEM) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_GET_INFO) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SET_INFO) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_EXPANDING) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_COLLAPSING) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SEL_CHANGED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_SEL_CHANGING) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_KEY_DOWN) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_ACTIVATED) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_END_DRAG) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP) +DEFINE_EVENT_TYPE(wxEVT_COMMAND_TREE_ITEM_MENU) + +// ---------------------------------------------------------------------------- +// Tree event +// ---------------------------------------------------------------------------- + +IMPLEMENT_ABSTRACT_CLASS(wxTreeEvent, wxNotifyEvent) + + +wxTreeEvent::wxTreeEvent(wxEventType commandType, + wxTreeCtrlBase *tree, + const wxTreeItemId& item) + : wxNotifyEvent(commandType, tree->GetId()), + m_item(item) +{ + m_editCancelled = false; + + SetEventObject(tree); + + if ( item.IsOk() ) + SetClientObject(tree->GetItemData(item)); +} + +wxTreeEvent::wxTreeEvent(wxEventType commandType, int id) + : wxNotifyEvent(commandType, id) +{ + m_itemOld = 0l; + m_editCancelled = false; +} + +wxTreeEvent::wxTreeEvent(const wxTreeEvent & event) + : wxNotifyEvent(event) +{ + m_evtKey = event.m_evtKey; + m_item = event.m_item; + m_itemOld = event.m_itemOld; + m_pointDrag = event.m_pointDrag; + m_label = event.m_label; + m_editCancelled = event.m_editCancelled; +} + +// ---------------------------------------------------------------------------- +// wxTreeCtrlBase +// ---------------------------------------------------------------------------- + +wxTreeCtrlBase::~wxTreeCtrlBase() +{ + if (m_ownsImageListNormal) + delete m_imageListNormal; + if (m_ownsImageListState) + delete m_imageListState; +} + +static void +wxGetBestTreeSize(const wxTreeCtrlBase* treeCtrl, wxTreeItemId id, wxSize& size) +{ + wxRect rect; + + if ( treeCtrl->GetBoundingRect(id, rect, true /* just the item */) ) + { + // Translate to logical position so we get the full extent +#if defined(__WXMSW__) && !defined(__WXUNIVERSAL__) + rect.x += treeCtrl->GetScrollPos(wxHORIZONTAL); + rect.y += treeCtrl->GetScrollPos(wxVERTICAL); +#endif + + size.IncTo(wxSize(rect.GetRight(), rect.GetBottom())); + } + + wxTreeItemIdValue cookie; + for ( wxTreeItemId item = treeCtrl->GetFirstChild(id, cookie); + item.IsOk(); + item = treeCtrl->GetNextChild(id, cookie) ) + { + wxGetBestTreeSize(treeCtrl, item, size); + } +} + +wxSize wxTreeCtrlBase::DoGetBestSize() const +{ + wxSize size; + + // this doesn't really compute the total bounding rectangle of all items + // but a not too bad guess of it which has the advantage of not having to + // examine all (potentially hundreds or thousands) items in the control + + if (GetQuickBestSize()) + { + for ( wxTreeItemId item = GetRootItem(); + item.IsOk(); + item = GetLastChild(item) ) + { + wxRect rect; + + // last parameter is "true" to get only the dimensions of the text + // label, we don't want to get the entire item width as it's determined + // by the current size + if ( GetBoundingRect(item, rect, true) ) + { + if ( size.x < rect.x + rect.width ) + size.x = rect.x + rect.width; + if ( size.y < rect.y + rect.height ) + size.y = rect.y + rect.height; + } + } + } + else // use precise, if potentially slow, size computation method + { + // iterate over all items recursively + wxTreeItemId idRoot = GetRootItem(); + if ( idRoot.IsOk() ) + wxGetBestTreeSize(this, idRoot, size); + } + + // need some minimal size even for empty tree + if ( !size.x || !size.y ) + size = wxControl::DoGetBestSize(); + else + { + // Add border size + size += GetWindowBorderSize(); + + CacheBestSize(size); + } + + return size; +} + +void wxTreeCtrlBase::ExpandAll() +{ + if ( IsEmpty() ) + return; + + ExpandAllChildren(GetRootItem()); +} + +void wxTreeCtrlBase::ExpandAllChildren(const wxTreeItemId& item) +{ + // expand this item first, this might result in its children being added on + // the fly + if ( item != GetRootItem() || !HasFlag(wxTR_HIDE_ROOT) ) + Expand(item); + //else: expanding hidden root item is unsupported and unnecessary + + // then (recursively) expand all the children + wxTreeItemIdValue cookie; + for ( wxTreeItemId idCurr = GetFirstChild(item, cookie); + idCurr.IsOk(); + idCurr = GetNextChild(item, cookie) ) + { + ExpandAllChildren(idCurr); + } +} + +void wxTreeCtrlBase::CollapseAll() +{ + if ( IsEmpty() ) + return; + + CollapseAllChildren(GetRootItem()); +} + +void wxTreeCtrlBase::CollapseAllChildren(const wxTreeItemId& item) +{ + // first (recursively) collapse all the children + wxTreeItemIdValue cookie; + for ( wxTreeItemId idCurr = GetFirstChild(item, cookie); + idCurr.IsOk(); + idCurr = GetNextChild(item, cookie) ) + { + CollapseAllChildren(idCurr); + } + + // then collapse this element too + Collapse(item); +} + +bool wxTreeCtrlBase::IsEmpty() const +{ + return !GetRootItem().IsOk(); +} + +#endif // wxUSE_TREECTRL + diff --git a/Source/3rd Party/wx/src/common/txtstrm.cpp b/Source/3rd Party/wx/src/common/txtstrm.cpp index 0da50befd..3dad17012 100644 --- a/Source/3rd Party/wx/src/common/txtstrm.cpp +++ b/Source/3rd Party/wx/src/common/txtstrm.cpp @@ -1,520 +1,520 @@ -/////////////////////////////////////////////////////////////////////////////// -// Name: src/common/txtstrm.cpp -// Purpose: Text stream classes -// Author: Guilhem Lavaux -// Modified by: -// Created: 28/06/98 -// RCS-ID: $Id: txtstrm.cpp 48920 2007-09-24 13:11:36Z JS $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#include "wx/txtstrm.h" -#include - - -// ---------------------------------------------------------------------------- -// constants -// ---------------------------------------------------------------------------- - -// Unix: "\n" -// Dos: "\r\n" -// Mac: "\r" - -// ---------------------------------------------------------------------------- -// wxTextInputStream -// ---------------------------------------------------------------------------- - -#if wxUSE_UNICODE -wxTextInputStream::wxTextInputStream(wxInputStream &s, - const wxString &sep, - const wxMBConv& conv) - : m_input(s), m_separators(sep), m_conv(conv.Clone()) -{ - memset((void*)m_lastBytes, 0, 10); -} -#else -wxTextInputStream::wxTextInputStream(wxInputStream &s, const wxString &sep) - : m_input(s), m_separators(sep) -{ - memset((void*)m_lastBytes, 0, 10); -} -#endif - -wxTextInputStream::~wxTextInputStream() -{ -#if wxUSE_UNICODE - delete m_conv; -#endif // wxUSE_UNICODE -} - -void wxTextInputStream::UngetLast() -{ - size_t byteCount = 0; - while(m_lastBytes[byteCount]) // pseudo ANSI strlen (even for Unicode!) - byteCount++; - m_input.Ungetch(m_lastBytes, byteCount); - memset((void*)m_lastBytes, 0, 10); -} - -wxChar wxTextInputStream::NextChar() -{ -#if wxUSE_UNICODE - wxChar wbuf[2]; - memset((void*)m_lastBytes, 0, 10); - for(size_t inlen = 0; inlen < 9; inlen++) - { - // actually read the next character - m_lastBytes[inlen] = m_input.GetC(); - - if(m_input.LastRead() <= 0) - return wxEOT; - - if ( m_conv->ToWChar(wbuf, WXSIZEOF(wbuf), m_lastBytes, inlen + 1) - != wxCONV_FAILED ) - return wbuf[0]; - } - // there should be no encoding which requires more than nine bytes for one character... - return wxEOT; -#else - m_lastBytes[0] = m_input.GetC(); - - if(m_input.LastRead() <= 0) - return wxEOT; - - return m_lastBytes[0]; -#endif - -} - -wxChar wxTextInputStream::NextNonSeparators() -{ - for (;;) - { - wxChar c = NextChar(); - if (c == wxEOT) return (wxChar) 0; - - if (c != wxT('\n') && - c != wxT('\r') && - !m_separators.Contains(c)) - return c; - } - -} - -bool wxTextInputStream::EatEOL(const wxChar &c) -{ - if (c == wxT('\n')) return true; // eat on UNIX - - if (c == wxT('\r')) // eat on both Mac and DOS - { - wxChar c2 = NextChar(); - if(c2 == wxEOT) return true; // end of stream reached, had enough :-) - - if (c2 != wxT('\n')) UngetLast(); // Don't eat on Mac - return true; - } - - return false; -} - -wxUint32 wxTextInputStream::Read32(int base) -{ - wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); - if(!m_input) return 0; - - wxString word = ReadWord(); - if(word.empty()) - return 0; - return wxStrtoul(word.c_str(), 0, base); -} - -wxUint16 wxTextInputStream::Read16(int base) -{ - return (wxUint16)Read32(base); -} - -wxUint8 wxTextInputStream::Read8(int base) -{ - return (wxUint8)Read32(base); -} - -wxInt32 wxTextInputStream::Read32S(int base) -{ - wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); - if(!m_input) return 0; - - wxString word = ReadWord(); - if(word.empty()) - return 0; - return wxStrtol(word.c_str(), 0, base); -} - -wxInt16 wxTextInputStream::Read16S(int base) -{ - return (wxInt16)Read32S(base); -} - -wxInt8 wxTextInputStream::Read8S(int base) -{ - return (wxInt8)Read32S(base); -} - -double wxTextInputStream::ReadDouble() -{ - if(!m_input) return 0; - wxString word = ReadWord(); - if(word.empty()) - return 0; - return wxStrtod(word.c_str(), 0); -} - -#if WXWIN_COMPATIBILITY_2_6 - -wxString wxTextInputStream::ReadString() -{ - return ReadLine(); -} - -#endif // WXWIN_COMPATIBILITY_2_6 - -wxString wxTextInputStream::ReadLine() -{ - wxString line; - - while ( !m_input.Eof() ) - { - wxChar c = NextChar(); - if(c == wxEOT) - break; - - if (EatEOL(c)) - break; - - line += c; - } - - return line; -} - -wxString wxTextInputStream::ReadWord() -{ - wxString word; - - if ( !m_input ) - return word; - - wxChar c = NextNonSeparators(); - if ( !c ) - return word; - - word += c; - - while ( !m_input.Eof() ) - { - c = NextChar(); - if(c == wxEOT) - break; - - if (m_separators.Contains(c)) - break; - - if (EatEOL(c)) - break; - - word += c; - } - - return word; -} - -wxTextInputStream& wxTextInputStream::operator>>(wxString& word) -{ - word = ReadWord(); - return *this; -} - -wxTextInputStream& wxTextInputStream::operator>>(char& c) -{ - c = m_input.GetC(); - if(m_input.LastRead() <= 0) c = 0; - - if (EatEOL(c)) - c = '\n'; - - return *this; -} - -#if wxUSE_UNICODE && wxWCHAR_T_IS_REAL_TYPE - -wxTextInputStream& wxTextInputStream::operator>>(wchar_t& wc) -{ - wc = GetChar(); - - return *this; -} - -#endif // wxUSE_UNICODE - -wxTextInputStream& wxTextInputStream::operator>>(wxInt16& i) -{ - i = (wxInt16)Read16(); - return *this; -} - -wxTextInputStream& wxTextInputStream::operator>>(wxInt32& i) -{ - i = (wxInt32)Read32(); - return *this; -} - -wxTextInputStream& wxTextInputStream::operator>>(wxUint16& i) -{ - i = Read16(); - return *this; -} - -wxTextInputStream& wxTextInputStream::operator>>(wxUint32& i) -{ - i = Read32(); - return *this; -} - -wxTextInputStream& wxTextInputStream::operator>>(double& i) -{ - i = ReadDouble(); - return *this; -} - -wxTextInputStream& wxTextInputStream::operator>>(float& f) -{ - f = (float)ReadDouble(); - return *this; -} - - - -#if wxUSE_UNICODE -wxTextOutputStream::wxTextOutputStream(wxOutputStream& s, - wxEOL mode, - const wxMBConv& conv) - : m_output(s), m_conv(conv.Clone()) -#else -wxTextOutputStream::wxTextOutputStream(wxOutputStream& s, wxEOL mode) - : m_output(s) -#endif -{ - m_mode = mode; - if (m_mode == wxEOL_NATIVE) - { -#if defined(__WXMSW__) || defined(__WXPM__) - m_mode = wxEOL_DOS; -#elif defined(__WXMAC__) && !defined(__DARWIN__) - m_mode = wxEOL_MAC; -#else - m_mode = wxEOL_UNIX; -#endif - } -} - -wxTextOutputStream::~wxTextOutputStream() -{ -#if wxUSE_UNICODE - delete m_conv; -#endif // wxUSE_UNICODE -} - -void wxTextOutputStream::SetMode(wxEOL mode) -{ - m_mode = mode; - if (m_mode == wxEOL_NATIVE) - { -#if defined(__WXMSW__) || defined(__WXPM__) - m_mode = wxEOL_DOS; -#elif defined(__WXMAC__) && !defined(__DARWIN__) - m_mode = wxEOL_MAC; -#else - m_mode = wxEOL_UNIX; -#endif - } -} - -void wxTextOutputStream::Write32(wxUint32 i) -{ - wxString str; - str.Printf(wxT("%u"), i); - - WriteString(str); -} - -void wxTextOutputStream::Write16(wxUint16 i) -{ - wxString str; - str.Printf(wxT("%u"), (unsigned)i); - - WriteString(str); -} - -void wxTextOutputStream::Write8(wxUint8 i) -{ - wxString str; - str.Printf(wxT("%u"), (unsigned)i); - - WriteString(str); -} - -void wxTextOutputStream::WriteDouble(double d) -{ - wxString str; - - str.Printf(wxT("%f"), d); - WriteString(str); -} - -void wxTextOutputStream::WriteString(const wxString& string) -{ - size_t len = string.length(); - - wxString out; - out.reserve(len); - - for ( size_t i = 0; i < len; i++ ) - { - const wxChar c = string[i]; - if ( c == wxT('\n') ) - { - switch ( m_mode ) - { - case wxEOL_DOS: - out << _T("\r\n"); - continue; - - case wxEOL_MAC: - out << _T('\r'); - continue; - - default: - wxFAIL_MSG( _T("unknown EOL mode in wxTextOutputStream") ); - // fall through - - case wxEOL_UNIX: - // don't treat '\n' specially - ; - } - } - - out << c; - } - -#if wxUSE_UNICODE - wxCharBuffer buffer = m_conv->cWC2MB(out, out.length(), &len); - m_output.Write(buffer, len); -#else - m_output.Write(out.c_str(), out.length() ); -#endif -} - -wxTextOutputStream& wxTextOutputStream::PutChar(wxChar c) -{ -#if wxUSE_UNICODE - WriteString( wxString(&c, *m_conv, 1) ); -#else - WriteString( wxString(&c, wxConvLocal, 1) ); -#endif - return *this; -} - -wxTextOutputStream& wxTextOutputStream::operator<<(const wxChar *string) -{ - WriteString( wxString(string) ); - return *this; -} - -wxTextOutputStream& wxTextOutputStream::operator<<(const wxString& string) -{ - WriteString( string ); - return *this; -} - -wxTextOutputStream& wxTextOutputStream::operator<<(char c) -{ - WriteString( wxString::FromAscii(c) ); - - return *this; -} - -#if wxUSE_UNICODE && wxWCHAR_T_IS_REAL_TYPE - -wxTextOutputStream& wxTextOutputStream::operator<<(wchar_t wc) -{ - WriteString( wxString(&wc, *m_conv, 1) ); - - return *this; -} - -#endif // wxUSE_UNICODE - -wxTextOutputStream& wxTextOutputStream::operator<<(wxInt16 c) -{ - wxString str; - str.Printf(wxT("%d"), (signed int)c); - WriteString(str); - - return *this; -} - -wxTextOutputStream& wxTextOutputStream::operator<<(wxInt32 c) -{ - wxString str; - str.Printf(wxT("%ld"), (signed long)c); - WriteString(str); - - return *this; -} - -wxTextOutputStream& wxTextOutputStream::operator<<(wxUint16 c) -{ - wxString str; - str.Printf(wxT("%u"), (unsigned int)c); - WriteString(str); - - return *this; -} - -wxTextOutputStream& wxTextOutputStream::operator<<(wxUint32 c) -{ - wxString str; - str.Printf(wxT("%lu"), (unsigned long)c); - WriteString(str); - - return *this; -} - -wxTextOutputStream &wxTextOutputStream::operator<<(double f) -{ - WriteDouble(f); - return *this; -} - -wxTextOutputStream& wxTextOutputStream::operator<<(float f) -{ - WriteDouble((double)f); - return *this; -} - -wxTextOutputStream &endl( wxTextOutputStream &stream ) -{ - return stream.PutChar(wxT('\n')); -} - -#endif - // wxUSE_STREAMS +/////////////////////////////////////////////////////////////////////////////// +// Name: src/common/txtstrm.cpp +// Purpose: Text stream classes +// Author: Guilhem Lavaux +// Modified by: +// Created: 28/06/98 +// RCS-ID: $Id: txtstrm.cpp 48920 2007-09-24 13:11:36Z JS $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#include "wx/txtstrm.h" +#include + + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// Unix: "\n" +// Dos: "\r\n" +// Mac: "\r" + +// ---------------------------------------------------------------------------- +// wxTextInputStream +// ---------------------------------------------------------------------------- + +#if wxUSE_UNICODE +wxTextInputStream::wxTextInputStream(wxInputStream &s, + const wxString &sep, + const wxMBConv& conv) + : m_input(s), m_separators(sep), m_conv(conv.Clone()) +{ + memset((void*)m_lastBytes, 0, 10); +} +#else +wxTextInputStream::wxTextInputStream(wxInputStream &s, const wxString &sep) + : m_input(s), m_separators(sep) +{ + memset((void*)m_lastBytes, 0, 10); +} +#endif + +wxTextInputStream::~wxTextInputStream() +{ +#if wxUSE_UNICODE + delete m_conv; +#endif // wxUSE_UNICODE +} + +void wxTextInputStream::UngetLast() +{ + size_t byteCount = 0; + while(m_lastBytes[byteCount]) // pseudo ANSI strlen (even for Unicode!) + byteCount++; + m_input.Ungetch(m_lastBytes, byteCount); + memset((void*)m_lastBytes, 0, 10); +} + +wxChar wxTextInputStream::NextChar() +{ +#if wxUSE_UNICODE + wxChar wbuf[2]; + memset((void*)m_lastBytes, 0, 10); + for(size_t inlen = 0; inlen < 9; inlen++) + { + // actually read the next character + m_lastBytes[inlen] = m_input.GetC(); + + if(m_input.LastRead() <= 0) + return wxEOT; + + if ( m_conv->ToWChar(wbuf, WXSIZEOF(wbuf), m_lastBytes, inlen + 1) + != wxCONV_FAILED ) + return wbuf[0]; + } + // there should be no encoding which requires more than nine bytes for one character... + return wxEOT; +#else + m_lastBytes[0] = m_input.GetC(); + + if(m_input.LastRead() <= 0) + return wxEOT; + + return m_lastBytes[0]; +#endif + +} + +wxChar wxTextInputStream::NextNonSeparators() +{ + for (;;) + { + wxChar c = NextChar(); + if (c == wxEOT) return (wxChar) 0; + + if (c != wxT('\n') && + c != wxT('\r') && + !m_separators.Contains(c)) + return c; + } + +} + +bool wxTextInputStream::EatEOL(const wxChar &c) +{ + if (c == wxT('\n')) return true; // eat on UNIX + + if (c == wxT('\r')) // eat on both Mac and DOS + { + wxChar c2 = NextChar(); + if(c2 == wxEOT) return true; // end of stream reached, had enough :-) + + if (c2 != wxT('\n')) UngetLast(); // Don't eat on Mac + return true; + } + + return false; +} + +wxUint32 wxTextInputStream::Read32(int base) +{ + wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); + if(!m_input) return 0; + + wxString word = ReadWord(); + if(word.empty()) + return 0; + return wxStrtoul(word.c_str(), 0, base); +} + +wxUint16 wxTextInputStream::Read16(int base) +{ + return (wxUint16)Read32(base); +} + +wxUint8 wxTextInputStream::Read8(int base) +{ + return (wxUint8)Read32(base); +} + +wxInt32 wxTextInputStream::Read32S(int base) +{ + wxASSERT_MSG( !base || (base > 1 && base <= 36), _T("invalid base") ); + if(!m_input) return 0; + + wxString word = ReadWord(); + if(word.empty()) + return 0; + return wxStrtol(word.c_str(), 0, base); +} + +wxInt16 wxTextInputStream::Read16S(int base) +{ + return (wxInt16)Read32S(base); +} + +wxInt8 wxTextInputStream::Read8S(int base) +{ + return (wxInt8)Read32S(base); +} + +double wxTextInputStream::ReadDouble() +{ + if(!m_input) return 0; + wxString word = ReadWord(); + if(word.empty()) + return 0; + return wxStrtod(word.c_str(), 0); +} + +#if WXWIN_COMPATIBILITY_2_6 + +wxString wxTextInputStream::ReadString() +{ + return ReadLine(); +} + +#endif // WXWIN_COMPATIBILITY_2_6 + +wxString wxTextInputStream::ReadLine() +{ + wxString line; + + while ( !m_input.Eof() ) + { + wxChar c = NextChar(); + if(c == wxEOT) + break; + + if (EatEOL(c)) + break; + + line += c; + } + + return line; +} + +wxString wxTextInputStream::ReadWord() +{ + wxString word; + + if ( !m_input ) + return word; + + wxChar c = NextNonSeparators(); + if ( !c ) + return word; + + word += c; + + while ( !m_input.Eof() ) + { + c = NextChar(); + if(c == wxEOT) + break; + + if (m_separators.Contains(c)) + break; + + if (EatEOL(c)) + break; + + word += c; + } + + return word; +} + +wxTextInputStream& wxTextInputStream::operator>>(wxString& word) +{ + word = ReadWord(); + return *this; +} + +wxTextInputStream& wxTextInputStream::operator>>(char& c) +{ + c = m_input.GetC(); + if(m_input.LastRead() <= 0) c = 0; + + if (EatEOL(c)) + c = '\n'; + + return *this; +} + +#if wxUSE_UNICODE && wxWCHAR_T_IS_REAL_TYPE + +wxTextInputStream& wxTextInputStream::operator>>(wchar_t& wc) +{ + wc = GetChar(); + + return *this; +} + +#endif // wxUSE_UNICODE + +wxTextInputStream& wxTextInputStream::operator>>(wxInt16& i) +{ + i = (wxInt16)Read16(); + return *this; +} + +wxTextInputStream& wxTextInputStream::operator>>(wxInt32& i) +{ + i = (wxInt32)Read32(); + return *this; +} + +wxTextInputStream& wxTextInputStream::operator>>(wxUint16& i) +{ + i = Read16(); + return *this; +} + +wxTextInputStream& wxTextInputStream::operator>>(wxUint32& i) +{ + i = Read32(); + return *this; +} + +wxTextInputStream& wxTextInputStream::operator>>(double& i) +{ + i = ReadDouble(); + return *this; +} + +wxTextInputStream& wxTextInputStream::operator>>(float& f) +{ + f = (float)ReadDouble(); + return *this; +} + + + +#if wxUSE_UNICODE +wxTextOutputStream::wxTextOutputStream(wxOutputStream& s, + wxEOL mode, + const wxMBConv& conv) + : m_output(s), m_conv(conv.Clone()) +#else +wxTextOutputStream::wxTextOutputStream(wxOutputStream& s, wxEOL mode) + : m_output(s) +#endif +{ + m_mode = mode; + if (m_mode == wxEOL_NATIVE) + { +#if defined(__WXMSW__) || defined(__WXPM__) + m_mode = wxEOL_DOS; +#elif defined(__WXMAC__) && !defined(__DARWIN__) + m_mode = wxEOL_MAC; +#else + m_mode = wxEOL_UNIX; +#endif + } +} + +wxTextOutputStream::~wxTextOutputStream() +{ +#if wxUSE_UNICODE + delete m_conv; +#endif // wxUSE_UNICODE +} + +void wxTextOutputStream::SetMode(wxEOL mode) +{ + m_mode = mode; + if (m_mode == wxEOL_NATIVE) + { +#if defined(__WXMSW__) || defined(__WXPM__) + m_mode = wxEOL_DOS; +#elif defined(__WXMAC__) && !defined(__DARWIN__) + m_mode = wxEOL_MAC; +#else + m_mode = wxEOL_UNIX; +#endif + } +} + +void wxTextOutputStream::Write32(wxUint32 i) +{ + wxString str; + str.Printf(wxT("%u"), i); + + WriteString(str); +} + +void wxTextOutputStream::Write16(wxUint16 i) +{ + wxString str; + str.Printf(wxT("%u"), (unsigned)i); + + WriteString(str); +} + +void wxTextOutputStream::Write8(wxUint8 i) +{ + wxString str; + str.Printf(wxT("%u"), (unsigned)i); + + WriteString(str); +} + +void wxTextOutputStream::WriteDouble(double d) +{ + wxString str; + + str.Printf(wxT("%f"), d); + WriteString(str); +} + +void wxTextOutputStream::WriteString(const wxString& string) +{ + size_t len = string.length(); + + wxString out; + out.reserve(len); + + for ( size_t i = 0; i < len; i++ ) + { + const wxChar c = string[i]; + if ( c == wxT('\n') ) + { + switch ( m_mode ) + { + case wxEOL_DOS: + out << _T("\r\n"); + continue; + + case wxEOL_MAC: + out << _T('\r'); + continue; + + default: + wxFAIL_MSG( _T("unknown EOL mode in wxTextOutputStream") ); + // fall through + + case wxEOL_UNIX: + // don't treat '\n' specially + ; + } + } + + out << c; + } + +#if wxUSE_UNICODE + wxCharBuffer buffer = m_conv->cWC2MB(out, out.length(), &len); + m_output.Write(buffer, len); +#else + m_output.Write(out.c_str(), out.length() ); +#endif +} + +wxTextOutputStream& wxTextOutputStream::PutChar(wxChar c) +{ +#if wxUSE_UNICODE + WriteString( wxString(&c, *m_conv, 1) ); +#else + WriteString( wxString(&c, wxConvLocal, 1) ); +#endif + return *this; +} + +wxTextOutputStream& wxTextOutputStream::operator<<(const wxChar *string) +{ + WriteString( wxString(string) ); + return *this; +} + +wxTextOutputStream& wxTextOutputStream::operator<<(const wxString& string) +{ + WriteString( string ); + return *this; +} + +wxTextOutputStream& wxTextOutputStream::operator<<(char c) +{ + WriteString( wxString::FromAscii(c) ); + + return *this; +} + +#if wxUSE_UNICODE && wxWCHAR_T_IS_REAL_TYPE + +wxTextOutputStream& wxTextOutputStream::operator<<(wchar_t wc) +{ + WriteString( wxString(&wc, *m_conv, 1) ); + + return *this; +} + +#endif // wxUSE_UNICODE + +wxTextOutputStream& wxTextOutputStream::operator<<(wxInt16 c) +{ + wxString str; + str.Printf(wxT("%d"), (signed int)c); + WriteString(str); + + return *this; +} + +wxTextOutputStream& wxTextOutputStream::operator<<(wxInt32 c) +{ + wxString str; + str.Printf(wxT("%ld"), (signed long)c); + WriteString(str); + + return *this; +} + +wxTextOutputStream& wxTextOutputStream::operator<<(wxUint16 c) +{ + wxString str; + str.Printf(wxT("%u"), (unsigned int)c); + WriteString(str); + + return *this; +} + +wxTextOutputStream& wxTextOutputStream::operator<<(wxUint32 c) +{ + wxString str; + str.Printf(wxT("%lu"), (unsigned long)c); + WriteString(str); + + return *this; +} + +wxTextOutputStream &wxTextOutputStream::operator<<(double f) +{ + WriteDouble(f); + return *this; +} + +wxTextOutputStream& wxTextOutputStream::operator<<(float f) +{ + WriteDouble((double)f); + return *this; +} + +wxTextOutputStream &endl( wxTextOutputStream &stream ) +{ + return stream.PutChar(wxT('\n')); +} + +#endif + // wxUSE_STREAMS diff --git a/Source/3rd Party/wx/src/common/unictabl.inc b/Source/3rd Party/wx/src/common/unictabl.inc index 13ee276af..d75491642 100644 --- a/Source/3rd Party/wx/src/common/unictabl.inc +++ b/Source/3rd Party/wx/src/common/unictabl.inc @@ -1,872 +1,872 @@ - - -/* - * This file is #included by encconv.cpp - * - * CVS-ID: $Id: unictabl.inc 40398 2006-07-31 16:28:43Z VS $ - * - * *** *** CAUTION! *** *** - * Do not modify this file by hand! It is generated by shell - * script $(WXWIN)/misc/unictabl/regenerate - * - * Parts of this file are based on tables published by Unicode, Inc. - * Original tables are freely available at - * ftp://ftp.unicode.org/Public/MAPPINGS - * - * Original copyright info as present in mapping tables follows: - * - * - * Copyright (c) 1991-1999 Unicode, Inc. All Rights reserved. - * - * This file is provided as-is by Unicode, Inc. (The Unicode Consortium). - * No claims are made as to fitness for any particular purpose. No - * warranties of any kind are expressed or implied. The recipient - * agrees to determine applicability of information provided. If this - * file has been provided on optical media by Unicode, Inc., the sole - * remedy for any claim will be exchange of defective media within 90 - * days of receipt. - * - * Unicode, Inc. hereby grants the right to freely use the information - * supplied in this file in the creation of products supporting the - * Unicode Standard, and to make copies of this file in any form for - * internal or external distribution as long as this notice remains - * attached. - */ - - - - -/* - * ISO8859_1 to Unicode recoding table - * based on file mappings/8859-1.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__ISO8859_1[128] = { - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, - 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, - 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, - 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, - 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, - 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, - 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, - 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, - 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, - 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, - 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, - 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, - 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF - }; - - -/* - * ISO8859_10 to Unicode recoding table - * based on file mappings/8859-10.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__ISO8859_10[128] = { - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, - 0x00A0, 0x0104, 0x0112, 0x0122, 0x012A, 0x0128, 0x0136, 0x00A7, - 0x013B, 0x0110, 0x0160, 0x0166, 0x017D, 0x00AD, 0x016A, 0x014A, - 0x00B0, 0x0105, 0x0113, 0x0123, 0x012B, 0x0129, 0x0137, 0x00B7, - 0x013C, 0x0111, 0x0161, 0x0167, 0x017E, 0x2015, 0x016B, 0x014B, - 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, - 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x00CF, - 0x00D0, 0x0145, 0x014C, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0168, - 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, - 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, - 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x00EF, - 0x00F0, 0x0146, 0x014D, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0169, - 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x0138 - }; - - -/* - * ISO8859_13 to Unicode recoding table - * based on file mappings/8859-13.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__ISO8859_13[128] = { - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, - 0x00A0, 0x201D, 0x00A2, 0x00A3, 0x00A4, 0x201E, 0x00A6, 0x00A7, - 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, - 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x201C, 0x00B5, 0x00B6, 0x00B7, - 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, - 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, - 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, - 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, - 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, - 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, - 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, - 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, - 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x2019 - }; - - -/* - * ISO8859_14 to Unicode recoding table - * based on file mappings/8859-14.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__ISO8859_14[128] = { - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, - 0x00A0, 0x1E02, 0x1E03, 0x00A3, 0x010A, 0x010B, 0x1E0A, 0x00A7, - 0x1E80, 0x00A9, 0x1E82, 0x1E0B, 0x1EF2, 0x00AD, 0x00AE, 0x0178, - 0x1E1E, 0x1E1F, 0x0120, 0x0121, 0x1E40, 0x1E41, 0x00B6, 0x1E56, - 0x1E81, 0x1E57, 0x1E83, 0x1E60, 0x1EF3, 0x1E84, 0x1E85, 0x1E61, - 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, - 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, - 0x0174, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x1E6A, - 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x0176, 0x00DF, - 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, - 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, - 0x0175, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x1E6B, - 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x0177, 0x00FF - }; - - -/* - * ISO8859_15 to Unicode recoding table - * based on file mappings/8859-15.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__ISO8859_15[128] = { - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, - 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7, - 0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, - 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7, - 0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF, - 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, - 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, - 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, - 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, - 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, - 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, - 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, - 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF - }; - - -/* - * ISO8859_2 to Unicode recoding table - * based on file mappings/8859-2.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__ISO8859_2[128] = { - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, - 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, - 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B, - 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, - 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C, - 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, - 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, - 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, - 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, - 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, - 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, - 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, - 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9 - }; - - -/* - * ISO8859_3 to Unicode recoding table - * based on file mappings/8859-3.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__ISO8859_3[128] = { - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, - 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0x0000, 0x0124, 0x00A7, - 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0x0000, 0x017B, - 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7, - 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0x0000, 0x017C, - 0x00C0, 0x00C1, 0x00C2, 0x0000, 0x00C4, 0x010A, 0x0108, 0x00C7, - 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, - 0x0000, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7, - 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF, - 0x00E0, 0x00E1, 0x00E2, 0x0000, 0x00E4, 0x010B, 0x0109, 0x00E7, - 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, - 0x0000, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7, - 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9 - }; - - -/* - * ISO8859_4 to Unicode recoding table - * based on file mappings/8859-4.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__ISO8859_4[128] = { - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, - 0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7, - 0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF, - 0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7, - 0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B, - 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, - 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A, - 0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7, - 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF, - 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, - 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B, - 0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7, - 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9 - }; - - -/* - * ISO8859_5 to Unicode recoding table - * based on file mappings/8859-5.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__ISO8859_5[128] = { - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, - 0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, - 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F, - 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, - 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, - 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, - 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, - 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, - 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, - 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, - 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, - 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, - 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F - }; - - -/* - * ISO8859_6 to Unicode recoding table - * based on file mappings/8859-6.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__ISO8859_6[128] = { - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, - 0x00A0, 0x0000, 0x0000, 0x0000, 0x00A4, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x060C, 0x00AD, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x061B, 0x0000, 0x0000, 0x0000, 0x061F, - 0x0000, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, - 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, - 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, - 0x0638, 0x0639, 0x063A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, - 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, - 0x0650, 0x0651, 0x0652, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 - }; - - -/* - * ISO8859_7 to Unicode recoding table - * based on file mappings/8859-7.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__ISO8859_7[128] = { - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, - 0x00A0, 0x2018, 0x2019, 0x00A3, 0x0000, 0x0000, 0x00A6, 0x00A7, - 0x00A8, 0x00A9, 0x0000, 0x00AB, 0x00AC, 0x00AD, 0x0000, 0x2015, - 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x00B7, - 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, - 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, - 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, - 0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, - 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, - 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, - 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, - 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, - 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000 - }; - - -/* - * ISO8859_8 to Unicode recoding table - * based on file mappings/8859-8.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__ISO8859_8[128] = { - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, - 0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, - 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x203E, - 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, - 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2017, - 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, - 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, - 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, - 0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 - }; - - -/* - * ISO8859_9 to Unicode recoding table - * based on file mappings/8859-9.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__ISO8859_9[128] = { - 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, - 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, - 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, - 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, - 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, - 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, - 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, - 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, - 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, - 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, - 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, - 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, - 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, - 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, - 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, - 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF - }; - - -/* - * CP1250 to Unicode recoding table - * based on file mappings/CP1250.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__CP1250[128] = { - 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021, - 0x0000, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179, - 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, - 0x0000, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A, - 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7, - 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B, - 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7, - 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C, - 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, - 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, - 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, - 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, - 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, - 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, - 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, - 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9 - }; - - -/* - * CP1251 to Unicode recoding table - * based on file mappings/CP1251.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__CP1251[128] = { - 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, - 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, - 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, - 0x0000, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, - 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, - 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, - 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, - 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457, - 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, - 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, - 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, - 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, - 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, - 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, - 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, - 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F - }; - - -/* - * CP1252 to Unicode recoding table - * based on file mappings/CP1252.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__CP1252[128] = { - 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, - 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017D, 0x0000, - 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, - 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x017E, 0x0178, - 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, - 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, - 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, - 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, - 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, - 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, - 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, - 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, - 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, - 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, - 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, - 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF - }; - - -/* - * CP1253 to Unicode recoding table - * based on file mappings/CP1253.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__CP1253[128] = { - 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, - 0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, - 0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000, - 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, - 0x00A8, 0x00A9, 0x0000, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015, - 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7, - 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, - 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, - 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, - 0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, - 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, - 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, - 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, - 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, - 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000 - }; - - -/* - * CP1254 to Unicode recoding table - * based on file mappings/CP1254.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__CP1254[128] = { - 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, - 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000, - 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, - 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178, - 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, - 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, - 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, - 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, - 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, - 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, - 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, - 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, - 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, - 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, - 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, - 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF - }; - - -/* - * CP1255 to Unicode recoding table - * based on file mappings/CP1255.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__CP1255[128] = { - 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, - 0x02C6, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000, - 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, - 0x02DC, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000, - 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AA, 0x00A5, 0x00A6, 0x00A7, - 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, - 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, - 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, - 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, - 0x05B8, 0x05B9, 0x0000, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, - 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3, - 0x05F4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, - 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, - 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, - 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, - 0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x200E, 0x200F, 0x0000 - }; - - -/* - * CP1256 to Unicode recoding table - * based on file mappings/CP1256.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__CP1256[128] = { - 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, - 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688, - 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, - 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA, - 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, - 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, - 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, - 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F, - 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, - 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, - 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, - 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0641, 0x0642, 0x0643, - 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7, - 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF, - 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7, - 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2 - }; - - -/* - * CP1257 to Unicode recoding table - * based on file mappings/CP1257.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__CP1257[128] = { - 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021, - 0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x00A8, 0x02C7, 0x00B8, - 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, - 0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x00AF, 0x02DB, 0x0000, - 0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x0000, 0x00A6, 0x00A7, - 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, - 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, - 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, - 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, - 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, - 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, - 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, - 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, - 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, - 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, - 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9 - }; - - -/* - * KOI8 to Unicode recoding table - * based on file mappings/KOI8-R.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__KOI8[128] = { - 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, - 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, - 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248, - 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, - 0x2550, 0x2551, 0x2552, 0x0451, 0x2553, 0x2554, 0x2555, 0x2556, - 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E, - 0x255F, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565, - 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0x00A9, - 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, - 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, - 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, - 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, - 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, - 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, - 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, - 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A - }; - - -/* - * KOI8_U to Unicode recoding table - * based on file mappings/KOI8-U.TXT by Unicode Consortium - */ - -static const wxUint16 encoding_table__KOI8_U[128] = { - 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, - 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, - 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248, - 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, - 0x2550, 0x2551, 0x2552, 0x0451, 0x0454, 0x2554, 0x0456, 0x0457, - 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x0491, 0x255D, 0x255E, - 0x255F, 0x2560, 0x2561, 0x0401, 0x0403, 0x2563, 0x0406, 0x0407, - 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x0490, 0x256C, 0x00A9, - 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, - 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, - 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, - 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, - 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, - 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, - 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, - 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A - }; - - - - - -/* - * - * Unicode to 7bit ASCII fallback - * (for use with wxRECODE_SUBSTITUTE recoding mode) - * - */ - -static const struct { - wxUint16 c /*code*/; - wxUint8 s /*inaccurate substitution*/; -} encoding_unicode_fallback[] = { - - {0x00AB, 0x22}, - {0x00BB, 0x22}, - {0x00C0, 0x41}, - {0x00C1, 0x41}, - {0x00C2, 0x41}, - {0x00C3, 0x41}, - {0x00C4, 0x41}, - {0x00C5, 0x41}, - {0x00C7, 0x43}, - {0x00C8, 0x45}, - {0x00C9, 0x45}, - {0x00CA, 0x45}, - {0x00CB, 0x45}, - {0x00CC, 0x49}, - {0x00CD, 0x49}, - {0x00CE, 0x49}, - {0x00CF, 0x49}, - {0x00D1, 0x4E}, - {0x00D2, 0x4F}, - {0x00D3, 0x4F}, - {0x00D4, 0x4F}, - {0x00D5, 0x4F}, - {0x00D6, 0x4F}, - {0x00D8, 0x4F}, - {0x00D9, 0x55}, - {0x00DA, 0x55}, - {0x00DB, 0x55}, - {0x00DC, 0x55}, - {0x00DD, 0x59}, - {0x00E0, 0x61}, - {0x00E1, 0x61}, - {0x00E2, 0x61}, - {0x00E3, 0x61}, - {0x00E4, 0x61}, - {0x00E5, 0x61}, - {0x00E7, 0x63}, - {0x00E8, 0x65}, - {0x00E9, 0x65}, - {0x00EA, 0x65}, - {0x00EB, 0x65}, - {0x00EC, 0x69}, - {0x00ED, 0x69}, - {0x00EE, 0x69}, - {0x00EF, 0x69}, - {0x00F1, 0x6E}, - {0x00F2, 0x6F}, - {0x00F3, 0x6F}, - {0x00F4, 0x6F}, - {0x00F5, 0x6F}, - {0x00F6, 0x6F}, - {0x00F8, 0x6F}, - {0x00F9, 0x75}, - {0x00FA, 0x75}, - {0x00FB, 0x75}, - {0x00FC, 0x75}, - {0x00FD, 0x79}, - {0x00FF, 0x79}, - {0x0100, 0x41}, - {0x0101, 0x61}, - {0x0102, 0x41}, - {0x0103, 0x61}, - {0x0104, 0x41}, - {0x0105, 0x61}, - {0x0106, 0x43}, - {0x0107, 0x63}, - {0x0108, 0x43}, - {0x0109, 0x63}, - {0x010A, 0x43}, - {0x010B, 0x63}, - {0x010C, 0x43}, - {0x010D, 0x63}, - {0x010E, 0x44}, - {0x010F, 0x64}, - {0x0110, 0x44}, - {0x0111, 0x64}, - {0x0112, 0x45}, - {0x0113, 0x65}, - {0x0116, 0x45}, - {0x0117, 0x65}, - {0x0118, 0x45}, - {0x0119, 0x65}, - {0x011A, 0x45}, - {0x011B, 0x65}, - {0x011C, 0x47}, - {0x011D, 0x67}, - {0x011E, 0x47}, - {0x011F, 0x67}, - {0x0120, 0x47}, - {0x0121, 0x67}, - {0x0122, 0x47}, - {0x0123, 0x67}, - {0x0124, 0x48}, - {0x0125, 0x68}, - {0x0126, 0x48}, - {0x0127, 0x68}, - {0x0128, 0x49}, - {0x0129, 0x69}, - {0x012A, 0x49}, - {0x012B, 0x69}, - {0x012E, 0x49}, - {0x012F, 0x69}, - {0x0130, 0x49}, - {0x0134, 0x4A}, - {0x0135, 0x6A}, - {0x0136, 0x4B}, - {0x0137, 0x6B}, - {0x0139, 0x4C}, - {0x013A, 0x6C}, - {0x013B, 0x4C}, - {0x013C, 0x6C}, - {0x013D, 0x4C}, - {0x013E, 0x6C}, - {0x0141, 0x4C}, - {0x0142, 0x6C}, - {0x0143, 0x4E}, - {0x0144, 0x6E}, - {0x0145, 0x4E}, - {0x0146, 0x6E}, - {0x0147, 0x4E}, - {0x0148, 0x6E}, - {0x014C, 0x4F}, - {0x014D, 0x6F}, - {0x0150, 0x4F}, - {0x0151, 0x6F}, - {0x0154, 0x52}, - {0x0155, 0x72}, - {0x0156, 0x52}, - {0x0157, 0x72}, - {0x0158, 0x52}, - {0x0159, 0x72}, - {0x015A, 0x53}, - {0x015B, 0x73}, - {0x015C, 0x53}, - {0x015D, 0x73}, - {0x015E, 0x53}, - {0x015F, 0x73}, - {0x0160, 0x53}, - {0x0161, 0x73}, - {0x0162, 0x54}, - {0x0163, 0x74}, - {0x0164, 0x54}, - {0x0165, 0x74}, - {0x0166, 0x54}, - {0x0167, 0x74}, - {0x0168, 0x55}, - {0x0169, 0x75}, - {0x016A, 0x55}, - {0x016B, 0x75}, - {0x016C, 0x55}, - {0x016D, 0x75}, - {0x016E, 0x55}, - {0x016F, 0x75}, - {0x0170, 0x55}, - {0x0171, 0x75}, - {0x0172, 0x55}, - {0x0173, 0x75}, - {0x0174, 0x57}, - {0x0175, 0x77}, - {0x0176, 0x59}, - {0x0177, 0x79}, - {0x0178, 0x59}, - {0x0179, 0x5A}, - {0x017A, 0x7A}, - {0x017B, 0x5A}, - {0x017C, 0x7A}, - {0x017D, 0x5A}, - {0x017E, 0x7A}, - {0x0192, 0x66}, - {0x1E02, 0x42}, - {0x1E03, 0x62}, - {0x1E0A, 0x44}, - {0x1E0B, 0x64}, - {0x1E1E, 0x46}, - {0x1E1F, 0x66}, - {0x1E40, 0x4D}, - {0x1E41, 0x6D}, - {0x1E56, 0x50}, - {0x1E57, 0x70}, - {0x1E60, 0x53}, - {0x1E61, 0x73}, - {0x1E6A, 0x54}, - {0x1E6B, 0x74}, - {0x1E80, 0x57}, - {0x1E81, 0x77}, - {0x1E82, 0x57}, - {0x1E83, 0x77}, - {0x1E84, 0x57}, - {0x1E85, 0x77}, - {0x1EF2, 0x59}, - {0x1EF3, 0x79}, - {0x2013, 0x2D}, - {0x2014, 0x2D}, - {0x2018, 0x27}, - {0x2019, 0x27}, - {0x201A, 0x27}, - {0x201C, 0x22}, - {0x201D, 0x22}, - {0x201E, 0x22}, - {0x2039, 0x27}, - {0x203A, 0x27}, - {0, 0} - }; - -static const unsigned encoding_unicode_fallback_count = 200; - - - - -/* - * - * Table of all supported encodings: - * - */ - -static const struct { - wxFontEncoding encoding; // encoding identifier - const wxUint16 *table; // 8bit to unicode table -} encodings_list[] = { - - { wxFONTENCODING_ISO8859_1, encoding_table__ISO8859_1}, - { wxFONTENCODING_ISO8859_10, encoding_table__ISO8859_10}, - { wxFONTENCODING_ISO8859_13, encoding_table__ISO8859_13}, - { wxFONTENCODING_ISO8859_14, encoding_table__ISO8859_14}, - { wxFONTENCODING_ISO8859_15, encoding_table__ISO8859_15}, - { wxFONTENCODING_ISO8859_2, encoding_table__ISO8859_2}, - { wxFONTENCODING_ISO8859_3, encoding_table__ISO8859_3}, - { wxFONTENCODING_ISO8859_4, encoding_table__ISO8859_4}, - { wxFONTENCODING_ISO8859_5, encoding_table__ISO8859_5}, - { wxFONTENCODING_ISO8859_6, encoding_table__ISO8859_6}, - { wxFONTENCODING_ISO8859_7, encoding_table__ISO8859_7}, - { wxFONTENCODING_ISO8859_8, encoding_table__ISO8859_8}, - { wxFONTENCODING_ISO8859_9, encoding_table__ISO8859_9}, - { wxFONTENCODING_CP1250, encoding_table__CP1250}, - { wxFONTENCODING_CP1251, encoding_table__CP1251}, - { wxFONTENCODING_CP1252, encoding_table__CP1252}, - { wxFONTENCODING_CP1253, encoding_table__CP1253}, - { wxFONTENCODING_CP1254, encoding_table__CP1254}, - { wxFONTENCODING_CP1255, encoding_table__CP1255}, - { wxFONTENCODING_CP1256, encoding_table__CP1256}, - { wxFONTENCODING_CP1257, encoding_table__CP1257}, - { wxFONTENCODING_KOI8, encoding_table__KOI8}, - { wxFONTENCODING_KOI8_U, encoding_table__KOI8_U}, - {wxFONTENCODING_MAX /*anything*/, NULL} - }; + + +/* + * This file is #included by encconv.cpp + * + * CVS-ID: $Id: unictabl.inc 40398 2006-07-31 16:28:43Z VS $ + * + * *** *** CAUTION! *** *** + * Do not modify this file by hand! It is generated by shell + * script $(WXWIN)/misc/unictabl/regenerate + * + * Parts of this file are based on tables published by Unicode, Inc. + * Original tables are freely available at + * ftp://ftp.unicode.org/Public/MAPPINGS + * + * Original copyright info as present in mapping tables follows: + * + * + * Copyright (c) 1991-1999 Unicode, Inc. All Rights reserved. + * + * This file is provided as-is by Unicode, Inc. (The Unicode Consortium). + * No claims are made as to fitness for any particular purpose. No + * warranties of any kind are expressed or implied. The recipient + * agrees to determine applicability of information provided. If this + * file has been provided on optical media by Unicode, Inc., the sole + * remedy for any claim will be exchange of defective media within 90 + * days of receipt. + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form for + * internal or external distribution as long as this notice remains + * attached. + */ + + + + +/* + * ISO8859_1 to Unicode recoding table + * based on file mappings/8859-1.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__ISO8859_1[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF + }; + + +/* + * ISO8859_10 to Unicode recoding table + * based on file mappings/8859-10.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__ISO8859_10[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0112, 0x0122, 0x012A, 0x0128, 0x0136, 0x00A7, + 0x013B, 0x0110, 0x0160, 0x0166, 0x017D, 0x00AD, 0x016A, 0x014A, + 0x00B0, 0x0105, 0x0113, 0x0123, 0x012B, 0x0129, 0x0137, 0x00B7, + 0x013C, 0x0111, 0x0161, 0x0167, 0x017E, 0x2015, 0x016B, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x0145, 0x014C, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x0168, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x0146, 0x014D, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x0169, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x0138 + }; + + +/* + * ISO8859_13 to Unicode recoding table + * based on file mappings/8859-13.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__ISO8859_13[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x201D, 0x00A2, 0x00A3, 0x00A4, 0x201E, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x201C, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x2019 + }; + + +/* + * ISO8859_14 to Unicode recoding table + * based on file mappings/8859-14.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__ISO8859_14[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x1E02, 0x1E03, 0x00A3, 0x010A, 0x010B, 0x1E0A, 0x00A7, + 0x1E80, 0x00A9, 0x1E82, 0x1E0B, 0x1EF2, 0x00AD, 0x00AE, 0x0178, + 0x1E1E, 0x1E1F, 0x0120, 0x0121, 0x1E40, 0x1E41, 0x00B6, 0x1E56, + 0x1E81, 0x1E57, 0x1E83, 0x1E60, 0x1EF3, 0x1E84, 0x1E85, 0x1E61, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x0174, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x1E6A, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x0176, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x0175, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x1E6B, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x0177, 0x00FF + }; + + +/* + * ISO8859_15 to Unicode recoding table + * based on file mappings/8859-15.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__ISO8859_15[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AC, 0x00A5, 0x0160, 0x00A7, + 0x0161, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x017D, 0x00B5, 0x00B6, 0x00B7, + 0x017E, 0x00B9, 0x00BA, 0x00BB, 0x0152, 0x0153, 0x0178, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF + }; + + +/* + * ISO8859_2 to Unicode recoding table + * based on file mappings/8859-2.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__ISO8859_2[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x02D8, 0x0141, 0x00A4, 0x013D, 0x015A, 0x00A7, + 0x00A8, 0x0160, 0x015E, 0x0164, 0x0179, 0x00AD, 0x017D, 0x017B, + 0x00B0, 0x0105, 0x02DB, 0x0142, 0x00B4, 0x013E, 0x015B, 0x02C7, + 0x00B8, 0x0161, 0x015F, 0x0165, 0x017A, 0x02DD, 0x017E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9 + }; + + +/* + * ISO8859_3 to Unicode recoding table + * based on file mappings/8859-3.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__ISO8859_3[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0126, 0x02D8, 0x00A3, 0x00A4, 0x0000, 0x0124, 0x00A7, + 0x00A8, 0x0130, 0x015E, 0x011E, 0x0134, 0x00AD, 0x0000, 0x017B, + 0x00B0, 0x0127, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x0125, 0x00B7, + 0x00B8, 0x0131, 0x015F, 0x011F, 0x0135, 0x00BD, 0x0000, 0x017C, + 0x00C0, 0x00C1, 0x00C2, 0x0000, 0x00C4, 0x010A, 0x0108, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x0000, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x0120, 0x00D6, 0x00D7, + 0x011C, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x016C, 0x015C, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x0000, 0x00E4, 0x010B, 0x0109, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x0000, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x0121, 0x00F6, 0x00F7, + 0x011D, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x016D, 0x015D, 0x02D9 + }; + + +/* + * ISO8859_4 to Unicode recoding table + * based on file mappings/8859-4.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__ISO8859_4[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0104, 0x0138, 0x0156, 0x00A4, 0x0128, 0x013B, 0x00A7, + 0x00A8, 0x0160, 0x0112, 0x0122, 0x0166, 0x00AD, 0x017D, 0x00AF, + 0x00B0, 0x0105, 0x02DB, 0x0157, 0x00B4, 0x0129, 0x013C, 0x02C7, + 0x00B8, 0x0161, 0x0113, 0x0123, 0x0167, 0x014A, 0x017E, 0x014B, + 0x0100, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x012E, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x0116, 0x00CD, 0x00CE, 0x012A, + 0x0110, 0x0145, 0x014C, 0x0136, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x0172, 0x00DA, 0x00DB, 0x00DC, 0x0168, 0x016A, 0x00DF, + 0x0101, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x012F, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x0117, 0x00ED, 0x00EE, 0x012B, + 0x0111, 0x0146, 0x014D, 0x0137, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x0173, 0x00FA, 0x00FB, 0x00FC, 0x0169, 0x016B, 0x02D9 + }; + + +/* + * ISO8859_5 to Unicode recoding table + * based on file mappings/8859-5.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__ISO8859_5[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0401, 0x0402, 0x0403, 0x0404, 0x0405, 0x0406, 0x0407, + 0x0408, 0x0409, 0x040A, 0x040B, 0x040C, 0x00AD, 0x040E, 0x040F, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F, + 0x2116, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, + 0x0458, 0x0459, 0x045A, 0x045B, 0x045C, 0x00A7, 0x045E, 0x045F + }; + + +/* + * ISO8859_6 to Unicode recoding table + * based on file mappings/8859-6.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__ISO8859_6[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0000, 0x0000, 0x0000, 0x00A4, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x060C, 0x00AD, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x061B, 0x0000, 0x0000, 0x0000, 0x061F, + 0x0000, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x0637, + 0x0638, 0x0639, 0x063A, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0640, 0x0641, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, + 0x0648, 0x0649, 0x064A, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, + 0x0650, 0x0651, 0x0652, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }; + + +/* + * ISO8859_7 to Unicode recoding table + * based on file mappings/8859-7.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__ISO8859_7[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x2018, 0x2019, 0x00A3, 0x0000, 0x0000, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x0000, 0x00AB, 0x00AC, 0x00AD, 0x0000, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x0385, 0x0386, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000 + }; + + +/* + * ISO8859_8 to Unicode recoding table + * based on file mappings/8859-8.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__ISO8859_8[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x203E, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x2017, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 + }; + + +/* + * ISO8859_9 to Unicode recoding table + * based on file mappings/8859-9.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__ISO8859_9[128] = { + 0x0080, 0x0081, 0x0082, 0x0083, 0x0084, 0x0085, 0x0086, 0x0087, + 0x0088, 0x0089, 0x008A, 0x008B, 0x008C, 0x008D, 0x008E, 0x008F, + 0x0090, 0x0091, 0x0092, 0x0093, 0x0094, 0x0095, 0x0096, 0x0097, + 0x0098, 0x0099, 0x009A, 0x009B, 0x009C, 0x009D, 0x009E, 0x009F, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF + }; + + +/* + * CP1250 to Unicode recoding table + * based on file mappings/CP1250.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__CP1250[128] = { + 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021, + 0x0000, 0x2030, 0x0160, 0x2039, 0x015A, 0x0164, 0x017D, 0x0179, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0161, 0x203A, 0x015B, 0x0165, 0x017E, 0x017A, + 0x00A0, 0x02C7, 0x02D8, 0x0141, 0x00A4, 0x0104, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x015E, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x017B, + 0x00B0, 0x00B1, 0x02DB, 0x0142, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x0105, 0x015F, 0x00BB, 0x013D, 0x02DD, 0x013E, 0x017C, + 0x0154, 0x00C1, 0x00C2, 0x0102, 0x00C4, 0x0139, 0x0106, 0x00C7, + 0x010C, 0x00C9, 0x0118, 0x00CB, 0x011A, 0x00CD, 0x00CE, 0x010E, + 0x0110, 0x0143, 0x0147, 0x00D3, 0x00D4, 0x0150, 0x00D6, 0x00D7, + 0x0158, 0x016E, 0x00DA, 0x0170, 0x00DC, 0x00DD, 0x0162, 0x00DF, + 0x0155, 0x00E1, 0x00E2, 0x0103, 0x00E4, 0x013A, 0x0107, 0x00E7, + 0x010D, 0x00E9, 0x0119, 0x00EB, 0x011B, 0x00ED, 0x00EE, 0x010F, + 0x0111, 0x0144, 0x0148, 0x00F3, 0x00F4, 0x0151, 0x00F6, 0x00F7, + 0x0159, 0x016F, 0x00FA, 0x0171, 0x00FC, 0x00FD, 0x0163, 0x02D9 + }; + + +/* + * CP1251 to Unicode recoding table + * based on file mappings/CP1251.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__CP1251[128] = { + 0x0402, 0x0403, 0x201A, 0x0453, 0x201E, 0x2026, 0x2020, 0x2021, + 0x20AC, 0x2030, 0x0409, 0x2039, 0x040A, 0x040C, 0x040B, 0x040F, + 0x0452, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0459, 0x203A, 0x045A, 0x045C, 0x045B, 0x045F, + 0x00A0, 0x040E, 0x045E, 0x0408, 0x00A4, 0x0490, 0x00A6, 0x00A7, + 0x0401, 0x00A9, 0x0404, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x0407, + 0x00B0, 0x00B1, 0x0406, 0x0456, 0x0491, 0x00B5, 0x00B6, 0x00B7, + 0x0451, 0x2116, 0x0454, 0x00BB, 0x0458, 0x0405, 0x0455, 0x0457, + 0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, + 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F, + 0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, + 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F, + 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, + 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F, + 0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, + 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F + }; + + +/* + * CP1252 to Unicode recoding table + * based on file mappings/CP1252.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__CP1252[128] = { + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x017D, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x017E, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x00D0, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x00DD, 0x00DE, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x00F0, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x00FD, 0x00FE, 0x00FF + }; + + +/* + * CP1253 to Unicode recoding table + * based on file mappings/CP1253.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__CP1253[128] = { + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000, + 0x00A0, 0x0385, 0x0386, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x0000, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x2015, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x0384, 0x00B5, 0x00B6, 0x00B7, + 0x0388, 0x0389, 0x038A, 0x00BB, 0x038C, 0x00BD, 0x038E, 0x038F, + 0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, + 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, + 0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, + 0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x03AC, 0x03AD, 0x03AE, 0x03AF, + 0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, + 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, + 0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7, + 0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000 + }; + + +/* + * CP1254 to Unicode recoding table + * based on file mappings/CP1254.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__CP1254[128] = { + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0x0000, 0x0000, 0x0178, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00AA, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00BA, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x00C0, 0x00C1, 0x00C2, 0x00C3, 0x00C4, 0x00C5, 0x00C6, 0x00C7, + 0x00C8, 0x00C9, 0x00CA, 0x00CB, 0x00CC, 0x00CD, 0x00CE, 0x00CF, + 0x011E, 0x00D1, 0x00D2, 0x00D3, 0x00D4, 0x00D5, 0x00D6, 0x00D7, + 0x00D8, 0x00D9, 0x00DA, 0x00DB, 0x00DC, 0x0130, 0x015E, 0x00DF, + 0x00E0, 0x00E1, 0x00E2, 0x00E3, 0x00E4, 0x00E5, 0x00E6, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x00EC, 0x00ED, 0x00EE, 0x00EF, + 0x011F, 0x00F1, 0x00F2, 0x00F3, 0x00F4, 0x00F5, 0x00F6, 0x00F7, + 0x00F8, 0x00F9, 0x00FA, 0x00FB, 0x00FC, 0x0131, 0x015F, 0x00FF + }; + + +/* + * CP1255 to Unicode recoding table + * based on file mappings/CP1255.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__CP1255[128] = { + 0x20AC, 0x0000, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0000, 0x2039, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x02DC, 0x2122, 0x0000, 0x203A, 0x0000, 0x0000, 0x0000, 0x0000, + 0x00A0, 0x00A1, 0x00A2, 0x00A3, 0x20AA, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x00D7, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x00F7, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00BF, + 0x05B0, 0x05B1, 0x05B2, 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, + 0x05B8, 0x05B9, 0x0000, 0x05BB, 0x05BC, 0x05BD, 0x05BE, 0x05BF, + 0x05C0, 0x05C1, 0x05C2, 0x05C3, 0x05F0, 0x05F1, 0x05F2, 0x05F3, + 0x05F4, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, + 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF, + 0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, + 0x05E8, 0x05E9, 0x05EA, 0x0000, 0x0000, 0x200E, 0x200F, 0x0000 + }; + + +/* + * CP1256 to Unicode recoding table + * based on file mappings/CP1256.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__CP1256[128] = { + 0x20AC, 0x067E, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021, + 0x02C6, 0x2030, 0x0679, 0x2039, 0x0152, 0x0686, 0x0698, 0x0688, + 0x06AF, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x06A9, 0x2122, 0x0691, 0x203A, 0x0153, 0x200C, 0x200D, 0x06BA, + 0x00A0, 0x060C, 0x00A2, 0x00A3, 0x00A4, 0x00A5, 0x00A6, 0x00A7, + 0x00A8, 0x00A9, 0x06BE, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00AF, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00B8, 0x00B9, 0x061B, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x061F, + 0x06C1, 0x0621, 0x0622, 0x0623, 0x0624, 0x0625, 0x0626, 0x0627, + 0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, + 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x0636, 0x00D7, + 0x0637, 0x0638, 0x0639, 0x063A, 0x0640, 0x0641, 0x0642, 0x0643, + 0x00E0, 0x0644, 0x00E2, 0x0645, 0x0646, 0x0647, 0x0648, 0x00E7, + 0x00E8, 0x00E9, 0x00EA, 0x00EB, 0x0649, 0x064A, 0x00EE, 0x00EF, + 0x064B, 0x064C, 0x064D, 0x064E, 0x00F4, 0x064F, 0x0650, 0x00F7, + 0x0651, 0x00F9, 0x0652, 0x00FB, 0x00FC, 0x200E, 0x200F, 0x06D2 + }; + + +/* + * CP1257 to Unicode recoding table + * based on file mappings/CP1257.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__CP1257[128] = { + 0x20AC, 0x0000, 0x201A, 0x0000, 0x201E, 0x2026, 0x2020, 0x2021, + 0x0000, 0x2030, 0x0000, 0x2039, 0x0000, 0x00A8, 0x02C7, 0x00B8, + 0x0000, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014, + 0x0000, 0x2122, 0x0000, 0x203A, 0x0000, 0x00AF, 0x02DB, 0x0000, + 0x00A0, 0x0000, 0x00A2, 0x00A3, 0x00A4, 0x0000, 0x00A6, 0x00A7, + 0x00D8, 0x00A9, 0x0156, 0x00AB, 0x00AC, 0x00AD, 0x00AE, 0x00C6, + 0x00B0, 0x00B1, 0x00B2, 0x00B3, 0x00B4, 0x00B5, 0x00B6, 0x00B7, + 0x00F8, 0x00B9, 0x0157, 0x00BB, 0x00BC, 0x00BD, 0x00BE, 0x00E6, + 0x0104, 0x012E, 0x0100, 0x0106, 0x00C4, 0x00C5, 0x0118, 0x0112, + 0x010C, 0x00C9, 0x0179, 0x0116, 0x0122, 0x0136, 0x012A, 0x013B, + 0x0160, 0x0143, 0x0145, 0x00D3, 0x014C, 0x00D5, 0x00D6, 0x00D7, + 0x0172, 0x0141, 0x015A, 0x016A, 0x00DC, 0x017B, 0x017D, 0x00DF, + 0x0105, 0x012F, 0x0101, 0x0107, 0x00E4, 0x00E5, 0x0119, 0x0113, + 0x010D, 0x00E9, 0x017A, 0x0117, 0x0123, 0x0137, 0x012B, 0x013C, + 0x0161, 0x0144, 0x0146, 0x00F3, 0x014D, 0x00F5, 0x00F6, 0x00F7, + 0x0173, 0x0142, 0x015B, 0x016B, 0x00FC, 0x017C, 0x017E, 0x02D9 + }; + + +/* + * KOI8 to Unicode recoding table + * based on file mappings/KOI8-R.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__KOI8[128] = { + 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, + 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, + 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248, + 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, + 0x2550, 0x2551, 0x2552, 0x0451, 0x2553, 0x2554, 0x2555, 0x2556, + 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x255C, 0x255D, 0x255E, + 0x255F, 0x2560, 0x2561, 0x0401, 0x2562, 0x2563, 0x2564, 0x2565, + 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x256B, 0x256C, 0x00A9, + 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, + 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, + 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, + 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, + 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, + 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, + 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, + 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A + }; + + +/* + * KOI8_U to Unicode recoding table + * based on file mappings/KOI8-U.TXT by Unicode Consortium + */ + +static const wxUint16 encoding_table__KOI8_U[128] = { + 0x2500, 0x2502, 0x250C, 0x2510, 0x2514, 0x2518, 0x251C, 0x2524, + 0x252C, 0x2534, 0x253C, 0x2580, 0x2584, 0x2588, 0x258C, 0x2590, + 0x2591, 0x2592, 0x2593, 0x2320, 0x25A0, 0x2219, 0x221A, 0x2248, + 0x2264, 0x2265, 0x00A0, 0x2321, 0x00B0, 0x00B2, 0x00B7, 0x00F7, + 0x2550, 0x2551, 0x2552, 0x0451, 0x0454, 0x2554, 0x0456, 0x0457, + 0x2557, 0x2558, 0x2559, 0x255A, 0x255B, 0x0491, 0x255D, 0x255E, + 0x255F, 0x2560, 0x2561, 0x0401, 0x0403, 0x2563, 0x0406, 0x0407, + 0x2566, 0x2567, 0x2568, 0x2569, 0x256A, 0x0490, 0x256C, 0x00A9, + 0x044E, 0x0430, 0x0431, 0x0446, 0x0434, 0x0435, 0x0444, 0x0433, + 0x0445, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, + 0x043F, 0x044F, 0x0440, 0x0441, 0x0442, 0x0443, 0x0436, 0x0432, + 0x044C, 0x044B, 0x0437, 0x0448, 0x044D, 0x0449, 0x0447, 0x044A, + 0x042E, 0x0410, 0x0411, 0x0426, 0x0414, 0x0415, 0x0424, 0x0413, + 0x0425, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, + 0x041F, 0x042F, 0x0420, 0x0421, 0x0422, 0x0423, 0x0416, 0x0412, + 0x042C, 0x042B, 0x0417, 0x0428, 0x042D, 0x0429, 0x0427, 0x042A + }; + + + + + +/* + * + * Unicode to 7bit ASCII fallback + * (for use with wxRECODE_SUBSTITUTE recoding mode) + * + */ + +static const struct { + wxUint16 c /*code*/; + wxUint8 s /*inaccurate substitution*/; +} encoding_unicode_fallback[] = { + + {0x00AB, 0x22}, + {0x00BB, 0x22}, + {0x00C0, 0x41}, + {0x00C1, 0x41}, + {0x00C2, 0x41}, + {0x00C3, 0x41}, + {0x00C4, 0x41}, + {0x00C5, 0x41}, + {0x00C7, 0x43}, + {0x00C8, 0x45}, + {0x00C9, 0x45}, + {0x00CA, 0x45}, + {0x00CB, 0x45}, + {0x00CC, 0x49}, + {0x00CD, 0x49}, + {0x00CE, 0x49}, + {0x00CF, 0x49}, + {0x00D1, 0x4E}, + {0x00D2, 0x4F}, + {0x00D3, 0x4F}, + {0x00D4, 0x4F}, + {0x00D5, 0x4F}, + {0x00D6, 0x4F}, + {0x00D8, 0x4F}, + {0x00D9, 0x55}, + {0x00DA, 0x55}, + {0x00DB, 0x55}, + {0x00DC, 0x55}, + {0x00DD, 0x59}, + {0x00E0, 0x61}, + {0x00E1, 0x61}, + {0x00E2, 0x61}, + {0x00E3, 0x61}, + {0x00E4, 0x61}, + {0x00E5, 0x61}, + {0x00E7, 0x63}, + {0x00E8, 0x65}, + {0x00E9, 0x65}, + {0x00EA, 0x65}, + {0x00EB, 0x65}, + {0x00EC, 0x69}, + {0x00ED, 0x69}, + {0x00EE, 0x69}, + {0x00EF, 0x69}, + {0x00F1, 0x6E}, + {0x00F2, 0x6F}, + {0x00F3, 0x6F}, + {0x00F4, 0x6F}, + {0x00F5, 0x6F}, + {0x00F6, 0x6F}, + {0x00F8, 0x6F}, + {0x00F9, 0x75}, + {0x00FA, 0x75}, + {0x00FB, 0x75}, + {0x00FC, 0x75}, + {0x00FD, 0x79}, + {0x00FF, 0x79}, + {0x0100, 0x41}, + {0x0101, 0x61}, + {0x0102, 0x41}, + {0x0103, 0x61}, + {0x0104, 0x41}, + {0x0105, 0x61}, + {0x0106, 0x43}, + {0x0107, 0x63}, + {0x0108, 0x43}, + {0x0109, 0x63}, + {0x010A, 0x43}, + {0x010B, 0x63}, + {0x010C, 0x43}, + {0x010D, 0x63}, + {0x010E, 0x44}, + {0x010F, 0x64}, + {0x0110, 0x44}, + {0x0111, 0x64}, + {0x0112, 0x45}, + {0x0113, 0x65}, + {0x0116, 0x45}, + {0x0117, 0x65}, + {0x0118, 0x45}, + {0x0119, 0x65}, + {0x011A, 0x45}, + {0x011B, 0x65}, + {0x011C, 0x47}, + {0x011D, 0x67}, + {0x011E, 0x47}, + {0x011F, 0x67}, + {0x0120, 0x47}, + {0x0121, 0x67}, + {0x0122, 0x47}, + {0x0123, 0x67}, + {0x0124, 0x48}, + {0x0125, 0x68}, + {0x0126, 0x48}, + {0x0127, 0x68}, + {0x0128, 0x49}, + {0x0129, 0x69}, + {0x012A, 0x49}, + {0x012B, 0x69}, + {0x012E, 0x49}, + {0x012F, 0x69}, + {0x0130, 0x49}, + {0x0134, 0x4A}, + {0x0135, 0x6A}, + {0x0136, 0x4B}, + {0x0137, 0x6B}, + {0x0139, 0x4C}, + {0x013A, 0x6C}, + {0x013B, 0x4C}, + {0x013C, 0x6C}, + {0x013D, 0x4C}, + {0x013E, 0x6C}, + {0x0141, 0x4C}, + {0x0142, 0x6C}, + {0x0143, 0x4E}, + {0x0144, 0x6E}, + {0x0145, 0x4E}, + {0x0146, 0x6E}, + {0x0147, 0x4E}, + {0x0148, 0x6E}, + {0x014C, 0x4F}, + {0x014D, 0x6F}, + {0x0150, 0x4F}, + {0x0151, 0x6F}, + {0x0154, 0x52}, + {0x0155, 0x72}, + {0x0156, 0x52}, + {0x0157, 0x72}, + {0x0158, 0x52}, + {0x0159, 0x72}, + {0x015A, 0x53}, + {0x015B, 0x73}, + {0x015C, 0x53}, + {0x015D, 0x73}, + {0x015E, 0x53}, + {0x015F, 0x73}, + {0x0160, 0x53}, + {0x0161, 0x73}, + {0x0162, 0x54}, + {0x0163, 0x74}, + {0x0164, 0x54}, + {0x0165, 0x74}, + {0x0166, 0x54}, + {0x0167, 0x74}, + {0x0168, 0x55}, + {0x0169, 0x75}, + {0x016A, 0x55}, + {0x016B, 0x75}, + {0x016C, 0x55}, + {0x016D, 0x75}, + {0x016E, 0x55}, + {0x016F, 0x75}, + {0x0170, 0x55}, + {0x0171, 0x75}, + {0x0172, 0x55}, + {0x0173, 0x75}, + {0x0174, 0x57}, + {0x0175, 0x77}, + {0x0176, 0x59}, + {0x0177, 0x79}, + {0x0178, 0x59}, + {0x0179, 0x5A}, + {0x017A, 0x7A}, + {0x017B, 0x5A}, + {0x017C, 0x7A}, + {0x017D, 0x5A}, + {0x017E, 0x7A}, + {0x0192, 0x66}, + {0x1E02, 0x42}, + {0x1E03, 0x62}, + {0x1E0A, 0x44}, + {0x1E0B, 0x64}, + {0x1E1E, 0x46}, + {0x1E1F, 0x66}, + {0x1E40, 0x4D}, + {0x1E41, 0x6D}, + {0x1E56, 0x50}, + {0x1E57, 0x70}, + {0x1E60, 0x53}, + {0x1E61, 0x73}, + {0x1E6A, 0x54}, + {0x1E6B, 0x74}, + {0x1E80, 0x57}, + {0x1E81, 0x77}, + {0x1E82, 0x57}, + {0x1E83, 0x77}, + {0x1E84, 0x57}, + {0x1E85, 0x77}, + {0x1EF2, 0x59}, + {0x1EF3, 0x79}, + {0x2013, 0x2D}, + {0x2014, 0x2D}, + {0x2018, 0x27}, + {0x2019, 0x27}, + {0x201A, 0x27}, + {0x201C, 0x22}, + {0x201D, 0x22}, + {0x201E, 0x22}, + {0x2039, 0x27}, + {0x203A, 0x27}, + {0, 0} + }; + +static const unsigned encoding_unicode_fallback_count = 200; + + + + +/* + * + * Table of all supported encodings: + * + */ + +static const struct { + wxFontEncoding encoding; // encoding identifier + const wxUint16 *table; // 8bit to unicode table +} encodings_list[] = { + + { wxFONTENCODING_ISO8859_1, encoding_table__ISO8859_1}, + { wxFONTENCODING_ISO8859_10, encoding_table__ISO8859_10}, + { wxFONTENCODING_ISO8859_13, encoding_table__ISO8859_13}, + { wxFONTENCODING_ISO8859_14, encoding_table__ISO8859_14}, + { wxFONTENCODING_ISO8859_15, encoding_table__ISO8859_15}, + { wxFONTENCODING_ISO8859_2, encoding_table__ISO8859_2}, + { wxFONTENCODING_ISO8859_3, encoding_table__ISO8859_3}, + { wxFONTENCODING_ISO8859_4, encoding_table__ISO8859_4}, + { wxFONTENCODING_ISO8859_5, encoding_table__ISO8859_5}, + { wxFONTENCODING_ISO8859_6, encoding_table__ISO8859_6}, + { wxFONTENCODING_ISO8859_7, encoding_table__ISO8859_7}, + { wxFONTENCODING_ISO8859_8, encoding_table__ISO8859_8}, + { wxFONTENCODING_ISO8859_9, encoding_table__ISO8859_9}, + { wxFONTENCODING_CP1250, encoding_table__CP1250}, + { wxFONTENCODING_CP1251, encoding_table__CP1251}, + { wxFONTENCODING_CP1252, encoding_table__CP1252}, + { wxFONTENCODING_CP1253, encoding_table__CP1253}, + { wxFONTENCODING_CP1254, encoding_table__CP1254}, + { wxFONTENCODING_CP1255, encoding_table__CP1255}, + { wxFONTENCODING_CP1256, encoding_table__CP1256}, + { wxFONTENCODING_CP1257, encoding_table__CP1257}, + { wxFONTENCODING_KOI8, encoding_table__KOI8}, + { wxFONTENCODING_KOI8_U, encoding_table__KOI8_U}, + {wxFONTENCODING_MAX /*anything*/, NULL} + }; diff --git a/Source/3rd Party/wx/src/common/uri.cpp b/Source/3rd Party/wx/src/common/uri.cpp index 682b85a0d..9ff50a0cc 100644 --- a/Source/3rd Party/wx/src/common/uri.cpp +++ b/Source/3rd Party/wx/src/common/uri.cpp @@ -1,1295 +1,1295 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: uri.cpp -// Purpose: Implementation of a uri parser -// Author: Ryan Norton -// Created: 10/26/04 -// RCS-ID: $Id: uri.cpp 58728 2009-02-07 22:03:30Z VZ $ -// Copyright: (c) 2004 Ryan Norton -// Licence: wxWindows -///////////////////////////////////////////////////////////////////////////// - -// =========================================================================== -// declarations -// =========================================================================== - -// --------------------------------------------------------------------------- -// headers -// --------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/uri.h" - -// --------------------------------------------------------------------------- -// definitions -// --------------------------------------------------------------------------- - -IMPLEMENT_CLASS(wxURI, wxObject) - -// =========================================================================== -// implementation -// =========================================================================== - -// --------------------------------------------------------------------------- -// utilities -// --------------------------------------------------------------------------- - -// --------------------------------------------------------------------------- -// -// wxURI -// -// --------------------------------------------------------------------------- - -// --------------------------------------------------------------------------- -// Constructors -// --------------------------------------------------------------------------- - -wxURI::wxURI() : m_hostType(wxURI_REGNAME), m_fields(0) -{ -} - -wxURI::wxURI(const wxString& uri) : m_hostType(wxURI_REGNAME), m_fields(0) -{ - Create(uri); -} - -wxURI::wxURI(const wxURI& uri) : wxObject(), m_hostType(wxURI_REGNAME), m_fields(0) -{ - Assign(uri); -} - -// --------------------------------------------------------------------------- -// Destructor and cleanup -// --------------------------------------------------------------------------- - -wxURI::~wxURI() -{ - Clear(); -} - -void wxURI::Clear() -{ - m_scheme = m_userinfo = m_server = m_port = m_path = - m_query = m_fragment = wxEmptyString; - - m_hostType = wxURI_REGNAME; - - m_fields = 0; -} - -// --------------------------------------------------------------------------- -// Create -// -// This creates the URI - all we do here is call the main parsing method -// --------------------------------------------------------------------------- - -const wxChar* wxURI::Create(const wxString& uri) -{ - if (m_fields) - Clear(); - - return Parse(uri); -} - -// --------------------------------------------------------------------------- -// Escape Methods -// -// TranslateEscape unencodes a 3 character URL escape sequence -// -// Escape encodes an invalid URI character into a 3 character sequence -// -// IsEscape determines if the input string contains an escape sequence, -// if it does, then it moves the input string past the escape sequence -// -// Unescape unencodes all 3 character URL escape sequences in a wxString -// --------------------------------------------------------------------------- - -wxChar wxURI::TranslateEscape(const wxChar* s) -{ - wxASSERT_MSG( IsHex(s[0]) && IsHex(s[1]), wxT("Invalid escape sequence!")); - - return wx_truncate_cast(wxChar, (CharToHex(s[0]) << 4 ) | CharToHex(s[1])); -} - -wxString wxURI::Unescape(const wxString& uri) -{ - wxString new_uri; - - for(size_t i = 0; i < uri.length(); ++i) - { - if (uri[i] == wxT('%')) - { - new_uri += wxURI::TranslateEscape( &(uri.c_str()[i+1]) ); - i += 2; - } - else - new_uri += uri[i]; - } - - return new_uri; -} - -void wxURI::Escape(wxString& s, const wxChar& c) -{ - const wxChar* hdig = wxT("0123456789abcdef"); - s += wxT('%'); - s += hdig[(c >> 4) & 15]; - s += hdig[c & 15]; -} - -bool wxURI::IsEscape(const wxChar*& uri) -{ - // pct-encoded = "%" HEXDIG HEXDIG - if(*uri == wxT('%') && IsHex(*(uri+1)) && IsHex(*(uri+2))) - return true; - else - return false; -} - -// --------------------------------------------------------------------------- -// GetUser -// GetPassword -// -// Gets the username and password via the old URL method. -// --------------------------------------------------------------------------- -wxString wxURI::GetUser() const -{ - // if there is no colon at all, find() returns npos and this method returns - // the entire string which is correct as it means that password was omitted - return m_userinfo(0, m_userinfo.find(':')); -} - -wxString wxURI::GetPassword() const -{ - size_t posColon = m_userinfo.find(':'); - - if ( posColon == wxString::npos ) - return wxT(""); - - return m_userinfo(posColon + 1, wxString::npos); -} - -// --------------------------------------------------------------------------- -// BuildURI -// -// BuildURI() builds the entire URI into a useable -// representation, including proper identification characters such as slashes -// -// BuildUnescapedURI() does the same thing as BuildURI(), only it unescapes -// the components that accept escape sequences -// --------------------------------------------------------------------------- - -wxString wxURI::BuildURI() const -{ - wxString ret; - - if (HasScheme()) - ret = ret + m_scheme + wxT(":"); - - if (HasServer()) - { - ret += wxT("//"); - - if (HasUserInfo()) - ret = ret + m_userinfo + wxT("@"); - - ret += m_server; - - if (HasPort()) - ret = ret + wxT(":") + m_port; - } - - ret += m_path; - - if (HasQuery()) - ret = ret + wxT("?") + m_query; - - if (HasFragment()) - ret = ret + wxT("#") + m_fragment; - - return ret; -} - -wxString wxURI::BuildUnescapedURI() const -{ - wxString ret; - - if (HasScheme()) - ret = ret + m_scheme + wxT(":"); - - if (HasServer()) - { - ret += wxT("//"); - - if (HasUserInfo()) - ret = ret + wxURI::Unescape(m_userinfo) + wxT("@"); - - if (m_hostType == wxURI_REGNAME) - ret += wxURI::Unescape(m_server); - else - ret += m_server; - - if (HasPort()) - ret = ret + wxT(":") + m_port; - } - - ret += wxURI::Unescape(m_path); - - if (HasQuery()) - ret = ret + wxT("?") + wxURI::Unescape(m_query); - - if (HasFragment()) - ret = ret + wxT("#") + wxURI::Unescape(m_fragment); - - return ret; -} - -// --------------------------------------------------------------------------- -// Assignment -// --------------------------------------------------------------------------- - -wxURI& wxURI::Assign(const wxURI& uri) -{ - //assign fields - m_fields = uri.m_fields; - - //ref over components - m_scheme = uri.m_scheme; - m_userinfo = uri.m_userinfo; - m_server = uri.m_server; - m_hostType = uri.m_hostType; - m_port = uri.m_port; - m_path = uri.m_path; - m_query = uri.m_query; - m_fragment = uri.m_fragment; - - return *this; -} - -wxURI& wxURI::operator = (const wxURI& uri) -{ - return Assign(uri); -} - -wxURI& wxURI::operator = (const wxString& string) -{ - Create(string); - return *this; -} - -// --------------------------------------------------------------------------- -// Comparison -// --------------------------------------------------------------------------- - -bool wxURI::operator == (const wxURI& uri) const -{ - if (HasScheme()) - { - if(m_scheme != uri.m_scheme) - return false; - } - else if (uri.HasScheme()) - return false; - - - if (HasServer()) - { - if (HasUserInfo()) - { - if (m_userinfo != uri.m_userinfo) - return false; - } - else if (uri.HasUserInfo()) - return false; - - if (m_server != uri.m_server || - m_hostType != uri.m_hostType) - return false; - - if (HasPort()) - { - if(m_port != uri.m_port) - return false; - } - else if (uri.HasPort()) - return false; - } - else if (uri.HasServer()) - return false; - - - if (HasPath()) - { - if(m_path != uri.m_path) - return false; - } - else if (uri.HasPath()) - return false; - - if (HasQuery()) - { - if (m_query != uri.m_query) - return false; - } - else if (uri.HasQuery()) - return false; - - if (HasFragment()) - { - if (m_fragment != uri.m_fragment) - return false; - } - else if (uri.HasFragment()) - return false; - - return true; -} - -// --------------------------------------------------------------------------- -// IsReference -// -// if there is no authority or scheme, it is a reference -// --------------------------------------------------------------------------- - -bool wxURI::IsReference() const -{ return !HasScheme() || !HasServer(); } - -// --------------------------------------------------------------------------- -// Parse -// -// Master URI parsing method. Just calls the individual parsing methods -// -// URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] -// URI-reference = URI / relative -// --------------------------------------------------------------------------- - -const wxChar* wxURI::Parse(const wxChar* uri) -{ - uri = ParseScheme(uri); - uri = ParseAuthority(uri); - uri = ParsePath(uri); - uri = ParseQuery(uri); - return ParseFragment(uri); -} - -// --------------------------------------------------------------------------- -// ParseXXX -// -// Individual parsers for each URI component -// --------------------------------------------------------------------------- - -const wxChar* wxURI::ParseScheme(const wxChar* uri) -{ - wxASSERT(uri != NULL); - - //copy of the uri - used for figuring out - //length of each component - const wxChar* uricopy = uri; - - //Does the uri have a scheme (first character alpha)? - if (IsAlpha(*uri)) - { - m_scheme += *uri++; - - //scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) - while (IsAlpha(*uri) || IsDigit(*uri) || - *uri == wxT('+') || - *uri == wxT('-') || - *uri == wxT('.')) - { - m_scheme += *uri++; - } - - //valid scheme? - if (*uri == wxT(':')) - { - //mark the scheme as valid - m_fields |= wxURI_SCHEME; - - //move reference point up to input buffer - uricopy = ++uri; - } - else - //relative uri with relative path reference - m_scheme = wxEmptyString; - } -// else - //relative uri with _possible_ relative path reference - - return uricopy; -} - -const wxChar* wxURI::ParseAuthority(const wxChar* uri) -{ - // authority = [ userinfo "@" ] host [ ":" port ] - if (*uri == wxT('/') && *(uri+1) == wxT('/')) - { - //skip past the two slashes - uri += 2; - - // ############# DEVIATION FROM RFC ######################### - // Don't parse the server component for file URIs - if(m_scheme != wxT("file")) - { - //normal way - uri = ParseUserInfo(uri); - uri = ParseServer(uri); - return ParsePort(uri); - } - } - - return uri; -} - -const wxChar* wxURI::ParseUserInfo(const wxChar* uri) -{ - wxASSERT(uri != NULL); - - //copy of the uri - used for figuring out - //length of each component - const wxChar* uricopy = uri; - - // userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) - while(*uri && *uri != wxT('@') && *uri != wxT('/') && *uri != wxT('#') && *uri != wxT('?')) - { - if(IsUnreserved(*uri) || - IsSubDelim(*uri) || *uri == wxT(':')) - m_userinfo += *uri++; - else if (IsEscape(uri)) - { - m_userinfo += *uri++; - m_userinfo += *uri++; - m_userinfo += *uri++; - } - else - Escape(m_userinfo, *uri++); - } - - if(*uri == wxT('@')) - { - //valid userinfo - m_fields |= wxURI_USERINFO; - - uricopy = ++uri; - } - else - m_userinfo = wxEmptyString; - - return uricopy; -} - -const wxChar* wxURI::ParseServer(const wxChar* uri) -{ - wxASSERT(uri != NULL); - - //copy of the uri - used for figuring out - //length of each component - const wxChar* uricopy = uri; - - // host = IP-literal / IPv4address / reg-name - // IP-literal = "[" ( IPv6address / IPvFuture ) "]" - if (*uri == wxT('[')) - { - ++uri; //some compilers don't support *&ing a ++* - if (ParseIPv6address(uri) && *uri == wxT(']')) - { - ++uri; - m_hostType = wxURI_IPV6ADDRESS; - - wxStringBufferLength theBuffer(m_server, uri - uricopy); - wxTmemcpy(theBuffer, uricopy, uri-uricopy); - theBuffer.SetLength(uri-uricopy); - } - else - { - uri = uricopy; - - ++uri; //some compilers don't support *&ing a ++* - if (ParseIPvFuture(uri) && *uri == wxT(']')) - { - ++uri; - m_hostType = wxURI_IPVFUTURE; - - wxStringBufferLength theBuffer(m_server, uri - uricopy); - wxTmemcpy(theBuffer, uricopy, uri-uricopy); - theBuffer.SetLength(uri-uricopy); - } - else - uri = uricopy; - } - } - else - { - if (ParseIPv4address(uri)) - { - m_hostType = wxURI_IPV4ADDRESS; - - wxStringBufferLength theBuffer(m_server, uri - uricopy); - wxTmemcpy(theBuffer, uricopy, uri-uricopy); - theBuffer.SetLength(uri-uricopy); - } - else - uri = uricopy; - } - - if(m_hostType == wxURI_REGNAME) - { - uri = uricopy; - // reg-name = *( unreserved / pct-encoded / sub-delims ) - while(*uri && *uri != wxT('/') && *uri != wxT(':') && *uri != wxT('#') && *uri != wxT('?')) - { - if(IsUnreserved(*uri) || IsSubDelim(*uri)) - m_server += *uri++; - else if (IsEscape(uri)) - { - m_server += *uri++; - m_server += *uri++; - m_server += *uri++; - } - else - Escape(m_server, *uri++); - } - } - - //mark the server as valid - m_fields |= wxURI_SERVER; - - return uri; -} - - -const wxChar* wxURI::ParsePort(const wxChar* uri) -{ - wxASSERT(uri != NULL); - - // port = *DIGIT - if(*uri == wxT(':')) - { - ++uri; - while(IsDigit(*uri)) - { - m_port += *uri++; - } - - //mark the port as valid - m_fields |= wxURI_PORT; - } - - return uri; -} - -const wxChar* wxURI::ParsePath(const wxChar* uri, bool bReference, bool bNormalize) -{ - wxASSERT(uri != NULL); - - //copy of the uri - used for figuring out - //length of each component - const wxChar* uricopy = uri; - - /// hier-part = "//" authority path-abempty - /// / path-absolute - /// / path-rootless - /// / path-empty - /// - /// relative-part = "//" authority path-abempty - /// / path-absolute - /// / path-noscheme - /// / path-empty - /// - /// path-abempty = *( "/" segment ) - /// path-absolute = "/" [ segment-nz *( "/" segment ) ] - /// path-noscheme = segment-nz-nc *( "/" segment ) - /// path-rootless = segment-nz *( "/" segment ) - /// path-empty = 0 - /// - /// segment = *pchar - /// segment-nz = 1*pchar - /// segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) - /// ; non-zero-length segment without any colon ":" - /// - /// pchar = unreserved / pct-encoded / sub-delims / ":" / "@" - if (*uri == wxT('/')) - { - m_path += *uri++; - - while(*uri && *uri != wxT('#') && *uri != wxT('?')) - { - if( IsUnreserved(*uri) || IsSubDelim(*uri) || - *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/')) - m_path += *uri++; - else if (IsEscape(uri)) - { - m_path += *uri++; - m_path += *uri++; - m_path += *uri++; - } - else - Escape(m_path, *uri++); - } - - if (bNormalize) - { - wxStringBufferLength theBuffer(m_path, m_path.length() + 1); -#if wxUSE_STL - wxTmemcpy(theBuffer, m_path.c_str(), m_path.length()+1); -#endif - Normalize(theBuffer, true); - theBuffer.SetLength(wxStrlen(theBuffer)); - } - //mark the path as valid - m_fields |= wxURI_PATH; - } - else if(*uri) //Relative path - { - if (bReference) - { - //no colon allowed - while(*uri && *uri != wxT('#') && *uri != wxT('?')) - { - if(IsUnreserved(*uri) || IsSubDelim(*uri) || - *uri == wxT('@') || *uri == wxT('/')) - m_path += *uri++; - else if (IsEscape(uri)) - { - m_path += *uri++; - m_path += *uri++; - m_path += *uri++; - } - else - Escape(m_path, *uri++); - } - } - else - { - while(*uri && *uri != wxT('#') && *uri != wxT('?')) - { - if(IsUnreserved(*uri) || IsSubDelim(*uri) || - *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/')) - m_path += *uri++; - else if (IsEscape(uri)) - { - m_path += *uri++; - m_path += *uri++; - m_path += *uri++; - } - else - Escape(m_path, *uri++); - } - } - - if (uri != uricopy) - { - if (bNormalize) - { - wxStringBufferLength theBuffer(m_path, m_path.length() + 1); -#if wxUSE_STL - wxTmemcpy(theBuffer, m_path.c_str(), m_path.length()+1); -#endif - Normalize(theBuffer); - theBuffer.SetLength(wxStrlen(theBuffer)); - } - - //mark the path as valid - m_fields |= wxURI_PATH; - } - } - - return uri; -} - - -const wxChar* wxURI::ParseQuery(const wxChar* uri) -{ - wxASSERT(uri != NULL); - - // query = *( pchar / "/" / "?" ) - if (*uri == wxT('?')) - { - ++uri; - while(*uri && *uri != wxT('#')) - { - if (IsUnreserved(*uri) || IsSubDelim(*uri) || - *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/') || *uri == wxT('?')) - m_query += *uri++; - else if (IsEscape(uri)) - { - m_query += *uri++; - m_query += *uri++; - m_query += *uri++; - } - else - Escape(m_query, *uri++); - } - - //mark the server as valid - m_fields |= wxURI_QUERY; - } - - return uri; -} - - -const wxChar* wxURI::ParseFragment(const wxChar* uri) -{ - wxASSERT(uri != NULL); - - // fragment = *( pchar / "/" / "?" ) - if (*uri == wxT('#')) - { - ++uri; - while(*uri) - { - if (IsUnreserved(*uri) || IsSubDelim(*uri) || - *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/') || *uri == wxT('?')) - m_fragment += *uri++; - else if (IsEscape(uri)) - { - m_fragment += *uri++; - m_fragment += *uri++; - m_fragment += *uri++; - } - else - Escape(m_fragment, *uri++); - } - - //mark the server as valid - m_fields |= wxURI_FRAGMENT; - } - - return uri; -} - -// --------------------------------------------------------------------------- -// Resolve -// -// Builds missing components of this uri from a base uri -// -// A version of the algorithm outlined in the RFC is used here -// (it is shown in comments) -// -// Note that an empty URI inherits all components -// --------------------------------------------------------------------------- - -void wxURI::Resolve(const wxURI& base, int flags) -{ - wxASSERT_MSG(!base.IsReference(), - wxT("wxURI to inherit from must not be a reference!")); - - // If we arn't being strict, enable the older (pre-RFC2396) - // loophole that allows this uri to inherit other - // properties from the base uri - even if the scheme - // is defined - if ( !(flags & wxURI_STRICT) && - HasScheme() && base.HasScheme() && - m_scheme == base.m_scheme ) - { - m_fields -= wxURI_SCHEME; - } - - - // Do nothing if this is an absolute wxURI - // if defined(R.scheme) then - // T.scheme = R.scheme; - // T.authority = R.authority; - // T.path = remove_dot_segments(R.path); - // T.query = R.query; - if (HasScheme()) - { - return; - } - - //No scheme - inherit - m_scheme = base.m_scheme; - m_fields |= wxURI_SCHEME; - - // All we need to do for relative URIs with an - // authority component is just inherit the scheme - // if defined(R.authority) then - // T.authority = R.authority; - // T.path = remove_dot_segments(R.path); - // T.query = R.query; - if (HasServer()) - { - return; - } - - //No authority - inherit - if (base.HasUserInfo()) - { - m_userinfo = base.m_userinfo; - m_fields |= wxURI_USERINFO; - } - - m_server = base.m_server; - m_hostType = base.m_hostType; - m_fields |= wxURI_SERVER; - - if (base.HasPort()) - { - m_port = base.m_port; - m_fields |= wxURI_PORT; - } - - - // Simple path inheritance from base - if (!HasPath()) - { - // T.path = Base.path; - m_path = base.m_path; - m_fields |= wxURI_PATH; - - - // if defined(R.query) then - // T.query = R.query; - // else - // T.query = Base.query; - // endif; - if (!HasQuery()) - { - m_query = base.m_query; - m_fields |= wxURI_QUERY; - } - } - else - { - // if (R.path starts-with "/") then - // T.path = remove_dot_segments(R.path); - // else - // T.path = merge(Base.path, R.path); - // T.path = remove_dot_segments(T.path); - // endif; - // T.query = R.query; - if (m_path.empty() || m_path[0u] != wxT('/')) - { - //Merge paths - const wxChar* op = m_path.c_str(); - const wxChar* bp = base.m_path.c_str() + base.m_path.Length(); - - //not a ending directory? move up - if (base.m_path[0] && *(bp-1) != wxT('/')) - UpTree(base.m_path, bp); - - //normalize directories - while(*op == wxT('.') && *(op+1) == wxT('.') && - (*(op+2) == '\0' || *(op+2) == wxT('/')) ) - { - UpTree(base.m_path, bp); - - if (*(op+2) == '\0') - op += 2; - else - op += 3; - } - - m_path = base.m_path.substr(0, bp - base.m_path.c_str()) + - m_path.substr((op - m_path.c_str()), m_path.Length()); - } - } - - //T.fragment = R.fragment; -} - -// --------------------------------------------------------------------------- -// UpTree -// -// Moves a URI path up a directory -// --------------------------------------------------------------------------- - -//static -void wxURI::UpTree(const wxChar* uristart, const wxChar*& uri) -{ - if (uri != uristart && *(uri-1) == wxT('/')) - { - uri -= 2; - } - - for(;uri != uristart; --uri) - { - if (*uri == wxT('/')) - { - ++uri; - break; - } - } - - //!!!TODO:HACK!!!// - if (uri == uristart && *uri == wxT('/')) - ++uri; - //!!!// -} - -// --------------------------------------------------------------------------- -// Normalize -// -// Normalizes directories in-place -// -// I.E. ./ and . are ignored -// -// ../ and .. are removed if a directory is before it, along -// with that directory (leading .. and ../ are kept) -// --------------------------------------------------------------------------- - -//static -void wxURI::Normalize(wxChar* s, bool bIgnoreLeads) -{ - wxChar* cp = s; - wxChar* bp = s; - - if(s[0] == wxT('/')) - ++bp; - - while(*cp) - { - if (*cp == wxT('.') && (*(cp+1) == wxT('/') || *(cp+1) == '\0') - && (bp == cp || *(cp-1) == wxT('/'))) - { - //. _or_ ./ - ignore - if (*(cp+1) == '\0') - cp += 1; - else - cp += 2; - } - else if (*cp == wxT('.') && *(cp+1) == wxT('.') && - (*(cp+2) == wxT('/') || *(cp+2) == '\0') - && (bp == cp || *(cp-1) == wxT('/'))) - { - //.. _or_ ../ - go up the tree - if (s != bp) - { - UpTree((const wxChar*)bp, (const wxChar*&)s); - - if (*(cp+2) == '\0') - cp += 2; - else - cp += 3; - } - else if (!bIgnoreLeads) - - { - *bp++ = *cp++; - *bp++ = *cp++; - if (*cp) - *bp++ = *cp++; - - s = bp; - } - else - { - if (*(cp+2) == '\0') - cp += 2; - else - cp += 3; - } - } - else - *s++ = *cp++; - } - - *s = '\0'; -} - -// --------------------------------------------------------------------------- -// ParseH16 -// -// Parses 1 to 4 hex values. Returns true if the first character of the input -// string is a valid hex character. It is the caller's responsability to move -// the input string back to its original position on failure. -// --------------------------------------------------------------------------- - -bool wxURI::ParseH16(const wxChar*& uri) -{ - // h16 = 1*4HEXDIG - if(!IsHex(*++uri)) - return false; - - if(IsHex(*++uri) && IsHex(*++uri) && IsHex(*++uri)) - ++uri; - - return true; -} - -// --------------------------------------------------------------------------- -// ParseIPXXX -// -// Parses a certain version of an IP address and moves the input string past -// it. Returns true if the input string contains the proper version of an ip -// address. It is the caller's responsability to move the input string back -// to its original position on failure. -// --------------------------------------------------------------------------- - -bool wxURI::ParseIPv4address(const wxChar*& uri) -{ - //IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet - // - //dec-octet = DIGIT ; 0-9 - // / %x31-39 DIGIT ; 10-99 - // / "1" 2DIGIT ; 100-199 - // / "2" %x30-34 DIGIT ; 200-249 - // / "25" %x30-35 ; 250-255 - size_t iIPv4 = 0; - if (IsDigit(*uri)) - { - ++iIPv4; - - - //each ip part must be between 0-255 (dupe of version in for loop) - if( IsDigit(*++uri) && IsDigit(*++uri) && - //100 or less (note !) - !( (*(uri-2) < wxT('2')) || - //240 or less - (*(uri-2) == wxT('2') && - (*(uri-1) < wxT('5') || (*(uri-1) == wxT('5') && *uri <= wxT('5'))) - ) - ) - ) - { - return false; - } - - if(IsDigit(*uri))++uri; - - //compilers should unroll this loop - for(; iIPv4 < 4; ++iIPv4) - { - if (*uri != wxT('.') || !IsDigit(*++uri)) - break; - - //each ip part must be between 0-255 - if( IsDigit(*++uri) && IsDigit(*++uri) && - //100 or less (note !) - !( (*(uri-2) < wxT('2')) || - //240 or less - (*(uri-2) == wxT('2') && - (*(uri-1) < wxT('5') || (*(uri-1) == wxT('5') && *uri <= wxT('5'))) - ) - ) - ) - { - return false; - } - if(IsDigit(*uri))++uri; - } - } - return iIPv4 == 4; -} - -bool wxURI::ParseIPv6address(const wxChar*& uri) -{ - // IPv6address = 6( h16 ":" ) ls32 - // / "::" 5( h16 ":" ) ls32 - // / [ h16 ] "::" 4( h16 ":" ) ls32 - // / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 - // / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 - // / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 - // / [ *4( h16 ":" ) h16 ] "::" ls32 - // / [ *5( h16 ":" ) h16 ] "::" h16 - // / [ *6( h16 ":" ) h16 ] "::" - - size_t numPrefix = 0, - maxPostfix; - - bool bEndHex = false; - - for( ; numPrefix < 6; ++numPrefix) - { - if(!ParseH16(uri)) - { - --uri; - bEndHex = true; - break; - } - - if(*uri != wxT(':')) - { - break; - } - } - - if(!bEndHex && !ParseH16(uri)) - { - --uri; - - if (numPrefix) - return false; - - if (*uri == wxT(':')) - { - if (*++uri != wxT(':')) - return false; - - maxPostfix = 5; - } - else - maxPostfix = 6; - } - else - { - if (*uri != wxT(':') || *(uri+1) != wxT(':')) - { - if (numPrefix != 6) - return false; - - while (*--uri != wxT(':')) {} - ++uri; - - const wxChar* uristart = uri; - //parse ls32 - // ls32 = ( h16 ":" h16 ) / IPv4address - if (ParseH16(uri) && *uri == wxT(':') && ParseH16(uri)) - return true; - - uri = uristart; - - if (ParseIPv4address(uri)) - return true; - else - return false; - } - else - { - uri += 2; - - if (numPrefix > 3) - maxPostfix = 0; - else - maxPostfix = 4 - numPrefix; - } - } - - bool bAllowAltEnding = maxPostfix == 0; - - for(; maxPostfix != 0; --maxPostfix) - { - if(!ParseH16(uri) || *uri != wxT(':')) - return false; - } - - if(numPrefix <= 4) - { - const wxChar* uristart = uri; - //parse ls32 - // ls32 = ( h16 ":" h16 ) / IPv4address - if (ParseH16(uri) && *uri == wxT(':') && ParseH16(uri)) - return true; - - uri = uristart; - - if (ParseIPv4address(uri)) - return true; - - uri = uristart; - - if (!bAllowAltEnding) - return false; - } - - if(numPrefix <= 5 && ParseH16(uri)) - return true; - - return true; -} - -bool wxURI::ParseIPvFuture(const wxChar*& uri) -{ - // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) - if (*++uri != wxT('v') || !IsHex(*++uri)) - return false; - - while (IsHex(*++uri)) {} - - if (*uri != wxT('.') || !(IsUnreserved(*++uri) || IsSubDelim(*uri) || *uri == wxT(':'))) - return false; - - while(IsUnreserved(*++uri) || IsSubDelim(*uri) || *uri == wxT(':')) {} - - return true; -} - - -// --------------------------------------------------------------------------- -// CharToHex -// -// Converts a character into a numeric hexidecimal value, or 0 if the -// passed in character is not a valid hex character -// --------------------------------------------------------------------------- - -//static -wxChar wxURI::CharToHex(const wxChar& c) -{ - if ((c >= wxT('A')) && (c <= wxT('Z'))) return wxChar(c - wxT('A') + 0x0A); - if ((c >= wxT('a')) && (c <= wxT('z'))) return wxChar(c - wxT('a') + 0x0a); - if ((c >= wxT('0')) && (c <= wxT('9'))) return wxChar(c - wxT('0') + 0x00); - - return 0; -} - -// --------------------------------------------------------------------------- -// IsXXX -// -// Returns true if the passed in character meets the criteria of the method -// --------------------------------------------------------------------------- - -//! unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" -bool wxURI::IsUnreserved (const wxChar& c) -{ return IsAlpha(c) || IsDigit(c) || - c == wxT('-') || - c == wxT('.') || - c == wxT('_') || - c == wxT('~') //tilde - ; -} - -bool wxURI::IsReserved (const wxChar& c) -{ - return IsGenDelim(c) || IsSubDelim(c); -} - -//! gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" -bool wxURI::IsGenDelim (const wxChar& c) -{ - return c == wxT(':') || - c == wxT('/') || - c == wxT('?') || - c == wxT('#') || - c == wxT('[') || - c == wxT(']') || - c == wxT('@'); -} - -//! sub-delims = "!" / "$" / "&" / "'" / "(" / ")" -//! / "*" / "+" / "," / ";" / "=" -bool wxURI::IsSubDelim (const wxChar& c) -{ - return c == wxT('!') || - c == wxT('$') || - c == wxT('&') || - c == wxT('\'') || - c == wxT('(') || - c == wxT(')') || - c == wxT('*') || - c == wxT('+') || - c == wxT(',') || - c == wxT(';') || - c == wxT('=') - ; -} - -bool wxURI::IsHex(const wxChar& c) -{ return IsDigit(c) || (c >= wxT('a') && c <= wxT('f')) || (c >= wxT('A') && c <= wxT('F')); } - -bool wxURI::IsAlpha(const wxChar& c) -{ return (c >= wxT('a') && c <= wxT('z')) || (c >= wxT('A') && c <= wxT('Z')); } - -bool wxURI::IsDigit(const wxChar& c) -{ return c >= wxT('0') && c <= wxT('9'); } - - -//end of uri.cpp - - - +///////////////////////////////////////////////////////////////////////////// +// Name: uri.cpp +// Purpose: Implementation of a uri parser +// Author: Ryan Norton +// Created: 10/26/04 +// RCS-ID: $Id: uri.cpp 58728 2009-02-07 22:03:30Z VZ $ +// Copyright: (c) 2004 Ryan Norton +// Licence: wxWindows +///////////////////////////////////////////////////////////////////////////// + +// =========================================================================== +// declarations +// =========================================================================== + +// --------------------------------------------------------------------------- +// headers +// --------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/uri.h" + +// --------------------------------------------------------------------------- +// definitions +// --------------------------------------------------------------------------- + +IMPLEMENT_CLASS(wxURI, wxObject) + +// =========================================================================== +// implementation +// =========================================================================== + +// --------------------------------------------------------------------------- +// utilities +// --------------------------------------------------------------------------- + +// --------------------------------------------------------------------------- +// +// wxURI +// +// --------------------------------------------------------------------------- + +// --------------------------------------------------------------------------- +// Constructors +// --------------------------------------------------------------------------- + +wxURI::wxURI() : m_hostType(wxURI_REGNAME), m_fields(0) +{ +} + +wxURI::wxURI(const wxString& uri) : m_hostType(wxURI_REGNAME), m_fields(0) +{ + Create(uri); +} + +wxURI::wxURI(const wxURI& uri) : wxObject(), m_hostType(wxURI_REGNAME), m_fields(0) +{ + Assign(uri); +} + +// --------------------------------------------------------------------------- +// Destructor and cleanup +// --------------------------------------------------------------------------- + +wxURI::~wxURI() +{ + Clear(); +} + +void wxURI::Clear() +{ + m_scheme = m_userinfo = m_server = m_port = m_path = + m_query = m_fragment = wxEmptyString; + + m_hostType = wxURI_REGNAME; + + m_fields = 0; +} + +// --------------------------------------------------------------------------- +// Create +// +// This creates the URI - all we do here is call the main parsing method +// --------------------------------------------------------------------------- + +const wxChar* wxURI::Create(const wxString& uri) +{ + if (m_fields) + Clear(); + + return Parse(uri); +} + +// --------------------------------------------------------------------------- +// Escape Methods +// +// TranslateEscape unencodes a 3 character URL escape sequence +// +// Escape encodes an invalid URI character into a 3 character sequence +// +// IsEscape determines if the input string contains an escape sequence, +// if it does, then it moves the input string past the escape sequence +// +// Unescape unencodes all 3 character URL escape sequences in a wxString +// --------------------------------------------------------------------------- + +wxChar wxURI::TranslateEscape(const wxChar* s) +{ + wxASSERT_MSG( IsHex(s[0]) && IsHex(s[1]), wxT("Invalid escape sequence!")); + + return wx_truncate_cast(wxChar, (CharToHex(s[0]) << 4 ) | CharToHex(s[1])); +} + +wxString wxURI::Unescape(const wxString& uri) +{ + wxString new_uri; + + for(size_t i = 0; i < uri.length(); ++i) + { + if (uri[i] == wxT('%')) + { + new_uri += wxURI::TranslateEscape( &(uri.c_str()[i+1]) ); + i += 2; + } + else + new_uri += uri[i]; + } + + return new_uri; +} + +void wxURI::Escape(wxString& s, const wxChar& c) +{ + const wxChar* hdig = wxT("0123456789abcdef"); + s += wxT('%'); + s += hdig[(c >> 4) & 15]; + s += hdig[c & 15]; +} + +bool wxURI::IsEscape(const wxChar*& uri) +{ + // pct-encoded = "%" HEXDIG HEXDIG + if(*uri == wxT('%') && IsHex(*(uri+1)) && IsHex(*(uri+2))) + return true; + else + return false; +} + +// --------------------------------------------------------------------------- +// GetUser +// GetPassword +// +// Gets the username and password via the old URL method. +// --------------------------------------------------------------------------- +wxString wxURI::GetUser() const +{ + // if there is no colon at all, find() returns npos and this method returns + // the entire string which is correct as it means that password was omitted + return m_userinfo(0, m_userinfo.find(':')); +} + +wxString wxURI::GetPassword() const +{ + size_t posColon = m_userinfo.find(':'); + + if ( posColon == wxString::npos ) + return wxT(""); + + return m_userinfo(posColon + 1, wxString::npos); +} + +// --------------------------------------------------------------------------- +// BuildURI +// +// BuildURI() builds the entire URI into a useable +// representation, including proper identification characters such as slashes +// +// BuildUnescapedURI() does the same thing as BuildURI(), only it unescapes +// the components that accept escape sequences +// --------------------------------------------------------------------------- + +wxString wxURI::BuildURI() const +{ + wxString ret; + + if (HasScheme()) + ret = ret + m_scheme + wxT(":"); + + if (HasServer()) + { + ret += wxT("//"); + + if (HasUserInfo()) + ret = ret + m_userinfo + wxT("@"); + + ret += m_server; + + if (HasPort()) + ret = ret + wxT(":") + m_port; + } + + ret += m_path; + + if (HasQuery()) + ret = ret + wxT("?") + m_query; + + if (HasFragment()) + ret = ret + wxT("#") + m_fragment; + + return ret; +} + +wxString wxURI::BuildUnescapedURI() const +{ + wxString ret; + + if (HasScheme()) + ret = ret + m_scheme + wxT(":"); + + if (HasServer()) + { + ret += wxT("//"); + + if (HasUserInfo()) + ret = ret + wxURI::Unescape(m_userinfo) + wxT("@"); + + if (m_hostType == wxURI_REGNAME) + ret += wxURI::Unescape(m_server); + else + ret += m_server; + + if (HasPort()) + ret = ret + wxT(":") + m_port; + } + + ret += wxURI::Unescape(m_path); + + if (HasQuery()) + ret = ret + wxT("?") + wxURI::Unescape(m_query); + + if (HasFragment()) + ret = ret + wxT("#") + wxURI::Unescape(m_fragment); + + return ret; +} + +// --------------------------------------------------------------------------- +// Assignment +// --------------------------------------------------------------------------- + +wxURI& wxURI::Assign(const wxURI& uri) +{ + //assign fields + m_fields = uri.m_fields; + + //ref over components + m_scheme = uri.m_scheme; + m_userinfo = uri.m_userinfo; + m_server = uri.m_server; + m_hostType = uri.m_hostType; + m_port = uri.m_port; + m_path = uri.m_path; + m_query = uri.m_query; + m_fragment = uri.m_fragment; + + return *this; +} + +wxURI& wxURI::operator = (const wxURI& uri) +{ + return Assign(uri); +} + +wxURI& wxURI::operator = (const wxString& string) +{ + Create(string); + return *this; +} + +// --------------------------------------------------------------------------- +// Comparison +// --------------------------------------------------------------------------- + +bool wxURI::operator == (const wxURI& uri) const +{ + if (HasScheme()) + { + if(m_scheme != uri.m_scheme) + return false; + } + else if (uri.HasScheme()) + return false; + + + if (HasServer()) + { + if (HasUserInfo()) + { + if (m_userinfo != uri.m_userinfo) + return false; + } + else if (uri.HasUserInfo()) + return false; + + if (m_server != uri.m_server || + m_hostType != uri.m_hostType) + return false; + + if (HasPort()) + { + if(m_port != uri.m_port) + return false; + } + else if (uri.HasPort()) + return false; + } + else if (uri.HasServer()) + return false; + + + if (HasPath()) + { + if(m_path != uri.m_path) + return false; + } + else if (uri.HasPath()) + return false; + + if (HasQuery()) + { + if (m_query != uri.m_query) + return false; + } + else if (uri.HasQuery()) + return false; + + if (HasFragment()) + { + if (m_fragment != uri.m_fragment) + return false; + } + else if (uri.HasFragment()) + return false; + + return true; +} + +// --------------------------------------------------------------------------- +// IsReference +// +// if there is no authority or scheme, it is a reference +// --------------------------------------------------------------------------- + +bool wxURI::IsReference() const +{ return !HasScheme() || !HasServer(); } + +// --------------------------------------------------------------------------- +// Parse +// +// Master URI parsing method. Just calls the individual parsing methods +// +// URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] +// URI-reference = URI / relative +// --------------------------------------------------------------------------- + +const wxChar* wxURI::Parse(const wxChar* uri) +{ + uri = ParseScheme(uri); + uri = ParseAuthority(uri); + uri = ParsePath(uri); + uri = ParseQuery(uri); + return ParseFragment(uri); +} + +// --------------------------------------------------------------------------- +// ParseXXX +// +// Individual parsers for each URI component +// --------------------------------------------------------------------------- + +const wxChar* wxURI::ParseScheme(const wxChar* uri) +{ + wxASSERT(uri != NULL); + + //copy of the uri - used for figuring out + //length of each component + const wxChar* uricopy = uri; + + //Does the uri have a scheme (first character alpha)? + if (IsAlpha(*uri)) + { + m_scheme += *uri++; + + //scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) + while (IsAlpha(*uri) || IsDigit(*uri) || + *uri == wxT('+') || + *uri == wxT('-') || + *uri == wxT('.')) + { + m_scheme += *uri++; + } + + //valid scheme? + if (*uri == wxT(':')) + { + //mark the scheme as valid + m_fields |= wxURI_SCHEME; + + //move reference point up to input buffer + uricopy = ++uri; + } + else + //relative uri with relative path reference + m_scheme = wxEmptyString; + } +// else + //relative uri with _possible_ relative path reference + + return uricopy; +} + +const wxChar* wxURI::ParseAuthority(const wxChar* uri) +{ + // authority = [ userinfo "@" ] host [ ":" port ] + if (*uri == wxT('/') && *(uri+1) == wxT('/')) + { + //skip past the two slashes + uri += 2; + + // ############# DEVIATION FROM RFC ######################### + // Don't parse the server component for file URIs + if(m_scheme != wxT("file")) + { + //normal way + uri = ParseUserInfo(uri); + uri = ParseServer(uri); + return ParsePort(uri); + } + } + + return uri; +} + +const wxChar* wxURI::ParseUserInfo(const wxChar* uri) +{ + wxASSERT(uri != NULL); + + //copy of the uri - used for figuring out + //length of each component + const wxChar* uricopy = uri; + + // userinfo = *( unreserved / pct-encoded / sub-delims / ":" ) + while(*uri && *uri != wxT('@') && *uri != wxT('/') && *uri != wxT('#') && *uri != wxT('?')) + { + if(IsUnreserved(*uri) || + IsSubDelim(*uri) || *uri == wxT(':')) + m_userinfo += *uri++; + else if (IsEscape(uri)) + { + m_userinfo += *uri++; + m_userinfo += *uri++; + m_userinfo += *uri++; + } + else + Escape(m_userinfo, *uri++); + } + + if(*uri == wxT('@')) + { + //valid userinfo + m_fields |= wxURI_USERINFO; + + uricopy = ++uri; + } + else + m_userinfo = wxEmptyString; + + return uricopy; +} + +const wxChar* wxURI::ParseServer(const wxChar* uri) +{ + wxASSERT(uri != NULL); + + //copy of the uri - used for figuring out + //length of each component + const wxChar* uricopy = uri; + + // host = IP-literal / IPv4address / reg-name + // IP-literal = "[" ( IPv6address / IPvFuture ) "]" + if (*uri == wxT('[')) + { + ++uri; //some compilers don't support *&ing a ++* + if (ParseIPv6address(uri) && *uri == wxT(']')) + { + ++uri; + m_hostType = wxURI_IPV6ADDRESS; + + wxStringBufferLength theBuffer(m_server, uri - uricopy); + wxTmemcpy(theBuffer, uricopy, uri-uricopy); + theBuffer.SetLength(uri-uricopy); + } + else + { + uri = uricopy; + + ++uri; //some compilers don't support *&ing a ++* + if (ParseIPvFuture(uri) && *uri == wxT(']')) + { + ++uri; + m_hostType = wxURI_IPVFUTURE; + + wxStringBufferLength theBuffer(m_server, uri - uricopy); + wxTmemcpy(theBuffer, uricopy, uri-uricopy); + theBuffer.SetLength(uri-uricopy); + } + else + uri = uricopy; + } + } + else + { + if (ParseIPv4address(uri)) + { + m_hostType = wxURI_IPV4ADDRESS; + + wxStringBufferLength theBuffer(m_server, uri - uricopy); + wxTmemcpy(theBuffer, uricopy, uri-uricopy); + theBuffer.SetLength(uri-uricopy); + } + else + uri = uricopy; + } + + if(m_hostType == wxURI_REGNAME) + { + uri = uricopy; + // reg-name = *( unreserved / pct-encoded / sub-delims ) + while(*uri && *uri != wxT('/') && *uri != wxT(':') && *uri != wxT('#') && *uri != wxT('?')) + { + if(IsUnreserved(*uri) || IsSubDelim(*uri)) + m_server += *uri++; + else if (IsEscape(uri)) + { + m_server += *uri++; + m_server += *uri++; + m_server += *uri++; + } + else + Escape(m_server, *uri++); + } + } + + //mark the server as valid + m_fields |= wxURI_SERVER; + + return uri; +} + + +const wxChar* wxURI::ParsePort(const wxChar* uri) +{ + wxASSERT(uri != NULL); + + // port = *DIGIT + if(*uri == wxT(':')) + { + ++uri; + while(IsDigit(*uri)) + { + m_port += *uri++; + } + + //mark the port as valid + m_fields |= wxURI_PORT; + } + + return uri; +} + +const wxChar* wxURI::ParsePath(const wxChar* uri, bool bReference, bool bNormalize) +{ + wxASSERT(uri != NULL); + + //copy of the uri - used for figuring out + //length of each component + const wxChar* uricopy = uri; + + /// hier-part = "//" authority path-abempty + /// / path-absolute + /// / path-rootless + /// / path-empty + /// + /// relative-part = "//" authority path-abempty + /// / path-absolute + /// / path-noscheme + /// / path-empty + /// + /// path-abempty = *( "/" segment ) + /// path-absolute = "/" [ segment-nz *( "/" segment ) ] + /// path-noscheme = segment-nz-nc *( "/" segment ) + /// path-rootless = segment-nz *( "/" segment ) + /// path-empty = 0 + /// + /// segment = *pchar + /// segment-nz = 1*pchar + /// segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" ) + /// ; non-zero-length segment without any colon ":" + /// + /// pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + if (*uri == wxT('/')) + { + m_path += *uri++; + + while(*uri && *uri != wxT('#') && *uri != wxT('?')) + { + if( IsUnreserved(*uri) || IsSubDelim(*uri) || + *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/')) + m_path += *uri++; + else if (IsEscape(uri)) + { + m_path += *uri++; + m_path += *uri++; + m_path += *uri++; + } + else + Escape(m_path, *uri++); + } + + if (bNormalize) + { + wxStringBufferLength theBuffer(m_path, m_path.length() + 1); +#if wxUSE_STL + wxTmemcpy(theBuffer, m_path.c_str(), m_path.length()+1); +#endif + Normalize(theBuffer, true); + theBuffer.SetLength(wxStrlen(theBuffer)); + } + //mark the path as valid + m_fields |= wxURI_PATH; + } + else if(*uri) //Relative path + { + if (bReference) + { + //no colon allowed + while(*uri && *uri != wxT('#') && *uri != wxT('?')) + { + if(IsUnreserved(*uri) || IsSubDelim(*uri) || + *uri == wxT('@') || *uri == wxT('/')) + m_path += *uri++; + else if (IsEscape(uri)) + { + m_path += *uri++; + m_path += *uri++; + m_path += *uri++; + } + else + Escape(m_path, *uri++); + } + } + else + { + while(*uri && *uri != wxT('#') && *uri != wxT('?')) + { + if(IsUnreserved(*uri) || IsSubDelim(*uri) || + *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/')) + m_path += *uri++; + else if (IsEscape(uri)) + { + m_path += *uri++; + m_path += *uri++; + m_path += *uri++; + } + else + Escape(m_path, *uri++); + } + } + + if (uri != uricopy) + { + if (bNormalize) + { + wxStringBufferLength theBuffer(m_path, m_path.length() + 1); +#if wxUSE_STL + wxTmemcpy(theBuffer, m_path.c_str(), m_path.length()+1); +#endif + Normalize(theBuffer); + theBuffer.SetLength(wxStrlen(theBuffer)); + } + + //mark the path as valid + m_fields |= wxURI_PATH; + } + } + + return uri; +} + + +const wxChar* wxURI::ParseQuery(const wxChar* uri) +{ + wxASSERT(uri != NULL); + + // query = *( pchar / "/" / "?" ) + if (*uri == wxT('?')) + { + ++uri; + while(*uri && *uri != wxT('#')) + { + if (IsUnreserved(*uri) || IsSubDelim(*uri) || + *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/') || *uri == wxT('?')) + m_query += *uri++; + else if (IsEscape(uri)) + { + m_query += *uri++; + m_query += *uri++; + m_query += *uri++; + } + else + Escape(m_query, *uri++); + } + + //mark the server as valid + m_fields |= wxURI_QUERY; + } + + return uri; +} + + +const wxChar* wxURI::ParseFragment(const wxChar* uri) +{ + wxASSERT(uri != NULL); + + // fragment = *( pchar / "/" / "?" ) + if (*uri == wxT('#')) + { + ++uri; + while(*uri) + { + if (IsUnreserved(*uri) || IsSubDelim(*uri) || + *uri == wxT(':') || *uri == wxT('@') || *uri == wxT('/') || *uri == wxT('?')) + m_fragment += *uri++; + else if (IsEscape(uri)) + { + m_fragment += *uri++; + m_fragment += *uri++; + m_fragment += *uri++; + } + else + Escape(m_fragment, *uri++); + } + + //mark the server as valid + m_fields |= wxURI_FRAGMENT; + } + + return uri; +} + +// --------------------------------------------------------------------------- +// Resolve +// +// Builds missing components of this uri from a base uri +// +// A version of the algorithm outlined in the RFC is used here +// (it is shown in comments) +// +// Note that an empty URI inherits all components +// --------------------------------------------------------------------------- + +void wxURI::Resolve(const wxURI& base, int flags) +{ + wxASSERT_MSG(!base.IsReference(), + wxT("wxURI to inherit from must not be a reference!")); + + // If we arn't being strict, enable the older (pre-RFC2396) + // loophole that allows this uri to inherit other + // properties from the base uri - even if the scheme + // is defined + if ( !(flags & wxURI_STRICT) && + HasScheme() && base.HasScheme() && + m_scheme == base.m_scheme ) + { + m_fields -= wxURI_SCHEME; + } + + + // Do nothing if this is an absolute wxURI + // if defined(R.scheme) then + // T.scheme = R.scheme; + // T.authority = R.authority; + // T.path = remove_dot_segments(R.path); + // T.query = R.query; + if (HasScheme()) + { + return; + } + + //No scheme - inherit + m_scheme = base.m_scheme; + m_fields |= wxURI_SCHEME; + + // All we need to do for relative URIs with an + // authority component is just inherit the scheme + // if defined(R.authority) then + // T.authority = R.authority; + // T.path = remove_dot_segments(R.path); + // T.query = R.query; + if (HasServer()) + { + return; + } + + //No authority - inherit + if (base.HasUserInfo()) + { + m_userinfo = base.m_userinfo; + m_fields |= wxURI_USERINFO; + } + + m_server = base.m_server; + m_hostType = base.m_hostType; + m_fields |= wxURI_SERVER; + + if (base.HasPort()) + { + m_port = base.m_port; + m_fields |= wxURI_PORT; + } + + + // Simple path inheritance from base + if (!HasPath()) + { + // T.path = Base.path; + m_path = base.m_path; + m_fields |= wxURI_PATH; + + + // if defined(R.query) then + // T.query = R.query; + // else + // T.query = Base.query; + // endif; + if (!HasQuery()) + { + m_query = base.m_query; + m_fields |= wxURI_QUERY; + } + } + else + { + // if (R.path starts-with "/") then + // T.path = remove_dot_segments(R.path); + // else + // T.path = merge(Base.path, R.path); + // T.path = remove_dot_segments(T.path); + // endif; + // T.query = R.query; + if (m_path.empty() || m_path[0u] != wxT('/')) + { + //Merge paths + const wxChar* op = m_path.c_str(); + const wxChar* bp = base.m_path.c_str() + base.m_path.Length(); + + //not a ending directory? move up + if (base.m_path[0] && *(bp-1) != wxT('/')) + UpTree(base.m_path, bp); + + //normalize directories + while(*op == wxT('.') && *(op+1) == wxT('.') && + (*(op+2) == '\0' || *(op+2) == wxT('/')) ) + { + UpTree(base.m_path, bp); + + if (*(op+2) == '\0') + op += 2; + else + op += 3; + } + + m_path = base.m_path.substr(0, bp - base.m_path.c_str()) + + m_path.substr((op - m_path.c_str()), m_path.Length()); + } + } + + //T.fragment = R.fragment; +} + +// --------------------------------------------------------------------------- +// UpTree +// +// Moves a URI path up a directory +// --------------------------------------------------------------------------- + +//static +void wxURI::UpTree(const wxChar* uristart, const wxChar*& uri) +{ + if (uri != uristart && *(uri-1) == wxT('/')) + { + uri -= 2; + } + + for(;uri != uristart; --uri) + { + if (*uri == wxT('/')) + { + ++uri; + break; + } + } + + //!!!TODO:HACK!!!// + if (uri == uristart && *uri == wxT('/')) + ++uri; + //!!!// +} + +// --------------------------------------------------------------------------- +// Normalize +// +// Normalizes directories in-place +// +// I.E. ./ and . are ignored +// +// ../ and .. are removed if a directory is before it, along +// with that directory (leading .. and ../ are kept) +// --------------------------------------------------------------------------- + +//static +void wxURI::Normalize(wxChar* s, bool bIgnoreLeads) +{ + wxChar* cp = s; + wxChar* bp = s; + + if(s[0] == wxT('/')) + ++bp; + + while(*cp) + { + if (*cp == wxT('.') && (*(cp+1) == wxT('/') || *(cp+1) == '\0') + && (bp == cp || *(cp-1) == wxT('/'))) + { + //. _or_ ./ - ignore + if (*(cp+1) == '\0') + cp += 1; + else + cp += 2; + } + else if (*cp == wxT('.') && *(cp+1) == wxT('.') && + (*(cp+2) == wxT('/') || *(cp+2) == '\0') + && (bp == cp || *(cp-1) == wxT('/'))) + { + //.. _or_ ../ - go up the tree + if (s != bp) + { + UpTree((const wxChar*)bp, (const wxChar*&)s); + + if (*(cp+2) == '\0') + cp += 2; + else + cp += 3; + } + else if (!bIgnoreLeads) + + { + *bp++ = *cp++; + *bp++ = *cp++; + if (*cp) + *bp++ = *cp++; + + s = bp; + } + else + { + if (*(cp+2) == '\0') + cp += 2; + else + cp += 3; + } + } + else + *s++ = *cp++; + } + + *s = '\0'; +} + +// --------------------------------------------------------------------------- +// ParseH16 +// +// Parses 1 to 4 hex values. Returns true if the first character of the input +// string is a valid hex character. It is the caller's responsability to move +// the input string back to its original position on failure. +// --------------------------------------------------------------------------- + +bool wxURI::ParseH16(const wxChar*& uri) +{ + // h16 = 1*4HEXDIG + if(!IsHex(*++uri)) + return false; + + if(IsHex(*++uri) && IsHex(*++uri) && IsHex(*++uri)) + ++uri; + + return true; +} + +// --------------------------------------------------------------------------- +// ParseIPXXX +// +// Parses a certain version of an IP address and moves the input string past +// it. Returns true if the input string contains the proper version of an ip +// address. It is the caller's responsability to move the input string back +// to its original position on failure. +// --------------------------------------------------------------------------- + +bool wxURI::ParseIPv4address(const wxChar*& uri) +{ + //IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet + // + //dec-octet = DIGIT ; 0-9 + // / %x31-39 DIGIT ; 10-99 + // / "1" 2DIGIT ; 100-199 + // / "2" %x30-34 DIGIT ; 200-249 + // / "25" %x30-35 ; 250-255 + size_t iIPv4 = 0; + if (IsDigit(*uri)) + { + ++iIPv4; + + + //each ip part must be between 0-255 (dupe of version in for loop) + if( IsDigit(*++uri) && IsDigit(*++uri) && + //100 or less (note !) + !( (*(uri-2) < wxT('2')) || + //240 or less + (*(uri-2) == wxT('2') && + (*(uri-1) < wxT('5') || (*(uri-1) == wxT('5') && *uri <= wxT('5'))) + ) + ) + ) + { + return false; + } + + if(IsDigit(*uri))++uri; + + //compilers should unroll this loop + for(; iIPv4 < 4; ++iIPv4) + { + if (*uri != wxT('.') || !IsDigit(*++uri)) + break; + + //each ip part must be between 0-255 + if( IsDigit(*++uri) && IsDigit(*++uri) && + //100 or less (note !) + !( (*(uri-2) < wxT('2')) || + //240 or less + (*(uri-2) == wxT('2') && + (*(uri-1) < wxT('5') || (*(uri-1) == wxT('5') && *uri <= wxT('5'))) + ) + ) + ) + { + return false; + } + if(IsDigit(*uri))++uri; + } + } + return iIPv4 == 4; +} + +bool wxURI::ParseIPv6address(const wxChar*& uri) +{ + // IPv6address = 6( h16 ":" ) ls32 + // / "::" 5( h16 ":" ) ls32 + // / [ h16 ] "::" 4( h16 ":" ) ls32 + // / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 + // / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 + // / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 + // / [ *4( h16 ":" ) h16 ] "::" ls32 + // / [ *5( h16 ":" ) h16 ] "::" h16 + // / [ *6( h16 ":" ) h16 ] "::" + + size_t numPrefix = 0, + maxPostfix; + + bool bEndHex = false; + + for( ; numPrefix < 6; ++numPrefix) + { + if(!ParseH16(uri)) + { + --uri; + bEndHex = true; + break; + } + + if(*uri != wxT(':')) + { + break; + } + } + + if(!bEndHex && !ParseH16(uri)) + { + --uri; + + if (numPrefix) + return false; + + if (*uri == wxT(':')) + { + if (*++uri != wxT(':')) + return false; + + maxPostfix = 5; + } + else + maxPostfix = 6; + } + else + { + if (*uri != wxT(':') || *(uri+1) != wxT(':')) + { + if (numPrefix != 6) + return false; + + while (*--uri != wxT(':')) {} + ++uri; + + const wxChar* uristart = uri; + //parse ls32 + // ls32 = ( h16 ":" h16 ) / IPv4address + if (ParseH16(uri) && *uri == wxT(':') && ParseH16(uri)) + return true; + + uri = uristart; + + if (ParseIPv4address(uri)) + return true; + else + return false; + } + else + { + uri += 2; + + if (numPrefix > 3) + maxPostfix = 0; + else + maxPostfix = 4 - numPrefix; + } + } + + bool bAllowAltEnding = maxPostfix == 0; + + for(; maxPostfix != 0; --maxPostfix) + { + if(!ParseH16(uri) || *uri != wxT(':')) + return false; + } + + if(numPrefix <= 4) + { + const wxChar* uristart = uri; + //parse ls32 + // ls32 = ( h16 ":" h16 ) / IPv4address + if (ParseH16(uri) && *uri == wxT(':') && ParseH16(uri)) + return true; + + uri = uristart; + + if (ParseIPv4address(uri)) + return true; + + uri = uristart; + + if (!bAllowAltEnding) + return false; + } + + if(numPrefix <= 5 && ParseH16(uri)) + return true; + + return true; +} + +bool wxURI::ParseIPvFuture(const wxChar*& uri) +{ + // IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" ) + if (*++uri != wxT('v') || !IsHex(*++uri)) + return false; + + while (IsHex(*++uri)) {} + + if (*uri != wxT('.') || !(IsUnreserved(*++uri) || IsSubDelim(*uri) || *uri == wxT(':'))) + return false; + + while(IsUnreserved(*++uri) || IsSubDelim(*uri) || *uri == wxT(':')) {} + + return true; +} + + +// --------------------------------------------------------------------------- +// CharToHex +// +// Converts a character into a numeric hexidecimal value, or 0 if the +// passed in character is not a valid hex character +// --------------------------------------------------------------------------- + +//static +wxChar wxURI::CharToHex(const wxChar& c) +{ + if ((c >= wxT('A')) && (c <= wxT('Z'))) return wxChar(c - wxT('A') + 0x0A); + if ((c >= wxT('a')) && (c <= wxT('z'))) return wxChar(c - wxT('a') + 0x0a); + if ((c >= wxT('0')) && (c <= wxT('9'))) return wxChar(c - wxT('0') + 0x00); + + return 0; +} + +// --------------------------------------------------------------------------- +// IsXXX +// +// Returns true if the passed in character meets the criteria of the method +// --------------------------------------------------------------------------- + +//! unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" +bool wxURI::IsUnreserved (const wxChar& c) +{ return IsAlpha(c) || IsDigit(c) || + c == wxT('-') || + c == wxT('.') || + c == wxT('_') || + c == wxT('~') //tilde + ; +} + +bool wxURI::IsReserved (const wxChar& c) +{ + return IsGenDelim(c) || IsSubDelim(c); +} + +//! gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@" +bool wxURI::IsGenDelim (const wxChar& c) +{ + return c == wxT(':') || + c == wxT('/') || + c == wxT('?') || + c == wxT('#') || + c == wxT('[') || + c == wxT(']') || + c == wxT('@'); +} + +//! sub-delims = "!" / "$" / "&" / "'" / "(" / ")" +//! / "*" / "+" / "," / ";" / "=" +bool wxURI::IsSubDelim (const wxChar& c) +{ + return c == wxT('!') || + c == wxT('$') || + c == wxT('&') || + c == wxT('\'') || + c == wxT('(') || + c == wxT(')') || + c == wxT('*') || + c == wxT('+') || + c == wxT(',') || + c == wxT(';') || + c == wxT('=') + ; +} + +bool wxURI::IsHex(const wxChar& c) +{ return IsDigit(c) || (c >= wxT('a') && c <= wxT('f')) || (c >= wxT('A') && c <= wxT('F')); } + +bool wxURI::IsAlpha(const wxChar& c) +{ return (c >= wxT('a') && c <= wxT('z')) || (c >= wxT('A') && c <= wxT('Z')); } + +bool wxURI::IsDigit(const wxChar& c) +{ return c >= wxT('0') && c <= wxT('9'); } + + +//end of uri.cpp + + + diff --git a/Source/3rd Party/wx/src/common/utilscmn.cpp b/Source/3rd Party/wx/src/common/utilscmn.cpp index e1683bf96..e2835b7d7 100644 --- a/Source/3rd Party/wx/src/common/utilscmn.cpp +++ b/Source/3rd Party/wx/src/common/utilscmn.cpp @@ -1,1417 +1,1417 @@ -// Name: src/common/utilscmn.cpp -// Purpose: Miscellaneous utility functions and classes -// Author: Julian Smart -// Modified by: -// Created: 29/01/98 -// RCS-ID: $Id: utilscmn.cpp 66917 2011-02-16 21:51:31Z JS $ -// Copyright: (c) 1998 Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/app.h" - #include "wx/string.h" - #include "wx/utils.h" - #include "wx/intl.h" - #include "wx/log.h" - - #if wxUSE_GUI - #include "wx/window.h" - #include "wx/frame.h" - #include "wx/menu.h" - #include "wx/msgdlg.h" - #include "wx/textdlg.h" - #include "wx/textctrl.h" // for wxTE_PASSWORD - #if wxUSE_ACCEL - #include "wx/menuitem.h" - #include "wx/accel.h" - #endif // wxUSE_ACCEL - #endif // wxUSE_GUI -#endif // WX_PRECOMP - -#include "wx/apptrait.h" - -#include "wx/process.h" -#include "wx/txtstrm.h" -#include "wx/uri.h" -#include "wx/mimetype.h" -#include "wx/config.h" - -#if defined(__WXWINCE__) && wxUSE_DATETIME -#include "wx/datetime.h" -#endif - -#include -#include -#include -#include - -#if !wxONLY_WATCOM_EARLIER_THAN(1,4) - #if !(defined(_MSC_VER) && (_MSC_VER > 800)) - #include - #endif -#endif - -#if wxUSE_GUI - #include "wx/colordlg.h" - #include "wx/fontdlg.h" - #include "wx/notebook.h" - #include "wx/statusbr.h" -#endif // wxUSE_GUI - -#ifndef __WXWINCE__ -#include -#else -#include "wx/msw/wince/time.h" -#endif - -#ifdef __WXMAC__ -#include "wx/mac/private.h" -#ifndef __DARWIN__ -#include "InternetConfig.h" -#endif -#endif - -#if !defined(__MWERKS__) && !defined(__WXWINCE__) - #include - #include -#endif - -#if defined(__WXMSW__) - #include "wx/msw/private.h" - #include "wx/msw/registry.h" - #include // needed for SHELLEXECUTEINFO -#endif - -#if wxUSE_BASE - -// ---------------------------------------------------------------------------- -// common data -// ---------------------------------------------------------------------------- - -// ============================================================================ -// implementation -// ============================================================================ - -#if WXWIN_COMPATIBILITY_2_4 - -wxChar * -copystring (const wxChar *s) -{ - if (s == NULL) s = wxEmptyString; - size_t len = wxStrlen (s) + 1; - - wxChar *news = new wxChar[len]; - memcpy (news, s, len * sizeof(wxChar)); // Should be the fastest - - return news; -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -// ---------------------------------------------------------------------------- -// String <-> Number conversions (deprecated) -// ---------------------------------------------------------------------------- - -#if WXWIN_COMPATIBILITY_2_4 - -WXDLLIMPEXP_DATA_BASE(const wxChar *) wxFloatToStringStr = wxT("%.2f"); -WXDLLIMPEXP_DATA_BASE(const wxChar *) wxDoubleToStringStr = wxT("%.2f"); - -void -StringToFloat (const wxChar *s, float *number) -{ - if (s && *s && number) - *number = (float) wxStrtod (s, (wxChar **) NULL); -} - -void -StringToDouble (const wxChar *s, double *number) -{ - if (s && *s && number) - *number = wxStrtod (s, (wxChar **) NULL); -} - -wxChar * -FloatToString (float number, const wxChar *fmt) -{ - static wxChar buf[256]; - - wxSprintf (buf, fmt, number); - return buf; -} - -wxChar * -DoubleToString (double number, const wxChar *fmt) -{ - static wxChar buf[256]; - - wxSprintf (buf, fmt, number); - return buf; -} - -void -StringToInt (const wxChar *s, int *number) -{ - if (s && *s && number) - *number = (int) wxStrtol (s, (wxChar **) NULL, 10); -} - -void -StringToLong (const wxChar *s, long *number) -{ - if (s && *s && number) - *number = wxStrtol (s, (wxChar **) NULL, 10); -} - -wxChar * -IntToString (int number) -{ - static wxChar buf[20]; - - wxSprintf (buf, wxT("%d"), number); - return buf; -} - -wxChar * -LongToString (long number) -{ - static wxChar buf[20]; - - wxSprintf (buf, wxT("%ld"), number); - return buf; -} - -#endif // WXWIN_COMPATIBILITY_2_4 - -// Array used in DecToHex conversion routine. -static wxChar hexArray[] = wxT("0123456789ABCDEF"); - -// Convert 2-digit hex number to decimal -int wxHexToDec(const wxString& buf) -{ - int firstDigit, secondDigit; - - if (buf.GetChar(0) >= wxT('A')) - firstDigit = buf.GetChar(0) - wxT('A') + 10; - else - firstDigit = buf.GetChar(0) - wxT('0'); - - if (buf.GetChar(1) >= wxT('A')) - secondDigit = buf.GetChar(1) - wxT('A') + 10; - else - secondDigit = buf.GetChar(1) - wxT('0'); - - return (firstDigit & 0xF) * 16 + (secondDigit & 0xF ); -} - -// Convert decimal integer to 2-character hex string -void wxDecToHex(int dec, wxChar *buf) -{ - int firstDigit = (int)(dec/16.0); - int secondDigit = (int)(dec - (firstDigit*16.0)); - buf[0] = hexArray[firstDigit]; - buf[1] = hexArray[secondDigit]; - buf[2] = 0; -} - -// Convert decimal integer to 2-character hex string -wxString wxDecToHex(int dec) -{ - wxChar buf[3]; - wxDecToHex(dec, buf); - return wxString(buf); -} - -// ---------------------------------------------------------------------------- -// misc functions -// ---------------------------------------------------------------------------- - -// Return the current date/time -wxString wxNow() -{ -#ifdef __WXWINCE__ -#if wxUSE_DATETIME - wxDateTime now = wxDateTime::Now(); - return now.Format(); -#else - return wxEmptyString; -#endif -#else - time_t now = time((time_t *) NULL); - char *date = ctime(&now); - date[24] = '\0'; - return wxString::FromAscii(date); -#endif -} - -void wxUsleep(unsigned long milliseconds) -{ - wxMilliSleep(milliseconds); -} - -const wxChar *wxGetInstallPrefix() -{ - wxString prefix; - - if ( wxGetEnv(wxT("WXPREFIX"), &prefix) ) - return prefix.c_str(); - -#ifdef wxINSTALL_PREFIX - return wxT(wxINSTALL_PREFIX); -#else - return wxEmptyString; -#endif -} - -wxString wxGetDataDir() -{ - wxString dir = wxGetInstallPrefix(); - dir << wxFILE_SEP_PATH << wxT("share") << wxFILE_SEP_PATH << wxT("wx"); - return dir; -} - -bool wxIsPlatformLittleEndian() -{ - // Are we little or big endian? This method is from Harbison & Steele. - union - { - long l; - char c[sizeof(long)]; - } u; - u.l = 1; - - return u.c[0] == 1; -} - - -/* - * Class to make it easier to specify platform-dependent values - */ - -wxArrayInt* wxPlatform::sm_customPlatforms = NULL; - -void wxPlatform::Copy(const wxPlatform& platform) -{ - m_longValue = platform.m_longValue; - m_doubleValue = platform.m_doubleValue; - m_stringValue = platform.m_stringValue; -} - -wxPlatform wxPlatform::If(int platform, long value) -{ - if (Is(platform)) - return wxPlatform(value); - else - return wxPlatform(); -} - -wxPlatform wxPlatform::IfNot(int platform, long value) -{ - if (!Is(platform)) - return wxPlatform(value); - else - return wxPlatform(); -} - -wxPlatform& wxPlatform::ElseIf(int platform, long value) -{ - if (Is(platform)) - m_longValue = value; - return *this; -} - -wxPlatform& wxPlatform::ElseIfNot(int platform, long value) -{ - if (!Is(platform)) - m_longValue = value; - return *this; -} - -wxPlatform wxPlatform::If(int platform, double value) -{ - if (Is(platform)) - return wxPlatform(value); - else - return wxPlatform(); -} - -wxPlatform wxPlatform::IfNot(int platform, double value) -{ - if (!Is(platform)) - return wxPlatform(value); - else - return wxPlatform(); -} - -wxPlatform& wxPlatform::ElseIf(int platform, double value) -{ - if (Is(platform)) - m_doubleValue = value; - return *this; -} - -wxPlatform& wxPlatform::ElseIfNot(int platform, double value) -{ - if (!Is(platform)) - m_doubleValue = value; - return *this; -} - -wxPlatform wxPlatform::If(int platform, const wxString& value) -{ - if (Is(platform)) - return wxPlatform(value); - else - return wxPlatform(); -} - -wxPlatform wxPlatform::IfNot(int platform, const wxString& value) -{ - if (!Is(platform)) - return wxPlatform(value); - else - return wxPlatform(); -} - -wxPlatform& wxPlatform::ElseIf(int platform, const wxString& value) -{ - if (Is(platform)) - m_stringValue = value; - return *this; -} - -wxPlatform& wxPlatform::ElseIfNot(int platform, const wxString& value) -{ - if (!Is(platform)) - m_stringValue = value; - return *this; -} - -wxPlatform& wxPlatform::Else(long value) -{ - m_longValue = value; - return *this; -} - -wxPlatform& wxPlatform::Else(double value) -{ - m_doubleValue = value; - return *this; -} - -wxPlatform& wxPlatform::Else(const wxString& value) -{ - m_stringValue = value; - return *this; -} - -void wxPlatform::AddPlatform(int platform) -{ - if (!sm_customPlatforms) - sm_customPlatforms = new wxArrayInt; - sm_customPlatforms->Add(platform); -} - -void wxPlatform::ClearPlatforms() -{ - delete sm_customPlatforms; - sm_customPlatforms = NULL; -} - -/// Function for testing current platform - -bool wxPlatform::Is(int platform) -{ -#ifdef __WXMSW__ - if (platform == wxOS_WINDOWS) - return true; -#endif -#ifdef __WXWINCE__ - if (platform == wxOS_WINDOWS_CE) - return true; -#endif - -#if 0 - -// FIXME: wxWinPocketPC and wxWinSmartPhone are unknown symbols - -#if defined(__WXWINCE__) && defined(__POCKETPC__) - if (platform == wxWinPocketPC) - return true; -#endif -#if defined(__WXWINCE__) && defined(__SMARTPHONE__) - if (platform == wxWinSmartPhone) - return true; -#endif - -#endif - -#ifdef __WXGTK__ - if (platform == wxPORT_GTK) - return true; -#endif -#ifdef __WXMAC__ - if (platform == wxPORT_MAC) - return true; -#endif -#ifdef __WXX11__ - if (platform == wxPORT_X11) - return true; -#endif -#ifdef __UNIX__ - if (platform == wxOS_UNIX) - return true; -#endif -#ifdef __WXMGL__ - if (platform == wxPORT_MGL) - return true; -#endif -#ifdef __OS2__ - if (platform == wxOS_OS2) - return true; -#endif -#ifdef __WXPM__ - if (platform == wxPORT_PM) - return true; -#endif -#ifdef __WXCOCOA__ - if (platform == wxPORT_MAC) - return true; -#endif - - if (sm_customPlatforms && sm_customPlatforms->Index(platform) != wxNOT_FOUND) - return true; - - return false; -} - -// ---------------------------------------------------------------------------- -// network and user id functions -// ---------------------------------------------------------------------------- - -// Get Full RFC822 style email address -bool wxGetEmailAddress(wxChar *address, int maxSize) -{ - wxString email = wxGetEmailAddress(); - if ( !email ) - return false; - - wxStrncpy(address, email, maxSize - 1); - address[maxSize - 1] = wxT('\0'); - - return true; -} - -wxString wxGetEmailAddress() -{ - wxString email; - - wxString host = wxGetFullHostName(); - if ( !host.empty() ) - { - wxString user = wxGetUserId(); - if ( !user.empty() ) - { - email << user << wxT('@') << host; - } - } - - return email; -} - -wxString wxGetUserId() -{ - static const int maxLoginLen = 256; // FIXME arbitrary number - - wxString buf; - bool ok = wxGetUserId(wxStringBuffer(buf, maxLoginLen), maxLoginLen); - - if ( !ok ) - buf.Empty(); - - return buf; -} - -wxString wxGetUserName() -{ - static const int maxUserNameLen = 1024; // FIXME arbitrary number - - wxString buf; - bool ok = wxGetUserName(wxStringBuffer(buf, maxUserNameLen), maxUserNameLen); - - if ( !ok ) - buf.Empty(); - - return buf; -} - -wxString wxGetHostName() -{ - static const size_t hostnameSize = 257; - - wxString buf; - bool ok = wxGetHostName(wxStringBuffer(buf, hostnameSize), hostnameSize); - - if ( !ok ) - buf.Empty(); - - return buf; -} - -wxString wxGetFullHostName() -{ - static const size_t hostnameSize = 257; - - wxString buf; - bool ok = wxGetFullHostName(wxStringBuffer(buf, hostnameSize), hostnameSize); - - if ( !ok ) - buf.Empty(); - - return buf; -} - -wxString wxGetHomeDir() -{ - wxString home; - wxGetHomeDir(&home); - - return home; -} - -#if 0 - -wxString wxGetCurrentDir() -{ - wxString dir; - size_t len = 1024; - bool ok; - do - { - ok = getcwd(dir.GetWriteBuf(len + 1), len) != NULL; - dir.UngetWriteBuf(); - - if ( !ok ) - { - if ( errno != ERANGE ) - { - wxLogSysError(_T("Failed to get current directory")); - - return wxEmptyString; - } - else - { - // buffer was too small, retry with a larger one - len *= 2; - } - } - //else: ok - } while ( !ok ); - - return dir; -} - -#endif // 0 - -// ---------------------------------------------------------------------------- -// wxExecute -// ---------------------------------------------------------------------------- - -// wxDoExecuteWithCapture() helper: reads an entire stream into one array -// -// returns true if ok, false if error -#if wxUSE_STREAMS -static bool ReadAll(wxInputStream *is, wxArrayString& output) -{ - wxCHECK_MSG( is, false, _T("NULL stream in wxExecute()?") ); - - // the stream could be already at EOF or in wxSTREAM_BROKEN_PIPE state - is->Reset(); - - wxTextInputStream tis(*is); - - for ( ;; ) - { - wxString line = tis.ReadLine(); - - // check for EOF before other errors as it's not really an error - if ( is->Eof() ) - { - // add the last, possibly incomplete, line - if ( !line.empty() ) - output.Add(line); - break; - } - - // any other error is fatal - if ( !*is ) - return false; - - output.Add(line); - } - - return true; -} -#endif // wxUSE_STREAMS - -// this is a private function because it hasn't a clean interface: the first -// array is passed by reference, the second by pointer - instead we have 2 -// public versions of wxExecute() below -static long wxDoExecuteWithCapture(const wxString& command, - wxArrayString& output, - wxArrayString* error, - int flags) -{ - // create a wxProcess which will capture the output - wxProcess *process = new wxProcess; - process->Redirect(); - - long rc = wxExecute(command, wxEXEC_SYNC | flags, process); - -#if wxUSE_STREAMS - if ( rc != -1 ) - { - if ( !ReadAll(process->GetInputStream(), output) ) - rc = -1; - - if ( error ) - { - if ( !ReadAll(process->GetErrorStream(), *error) ) - rc = -1; - } - - } -#else - wxUnusedVar(output); - wxUnusedVar(error); -#endif // wxUSE_STREAMS/!wxUSE_STREAMS - - delete process; - - return rc; -} - -long wxExecute(const wxString& command, wxArrayString& output, int flags) -{ - return wxDoExecuteWithCapture(command, output, NULL, flags); -} - -long wxExecute(const wxString& command, - wxArrayString& output, - wxArrayString& error, - int flags) -{ - return wxDoExecuteWithCapture(command, output, &error, flags); -} - -// ---------------------------------------------------------------------------- -// Launch default browser -// ---------------------------------------------------------------------------- - -#include "wx/private/browserhack28.h" - -static bool wxLaunchDefaultBrowserBaseImpl(const wxString& url, int flags); - -// Use wxLaunchDefaultBrowserBaseImpl by default -static wxLaunchDefaultBrowserImpl_t s_launchBrowserImpl = &wxLaunchDefaultBrowserBaseImpl; - -// Function the GUI library can call to provide a better implementation -WXDLLIMPEXP_BASE void wxSetLaunchDefaultBrowserImpl(wxLaunchDefaultBrowserImpl_t newImpl) -{ - s_launchBrowserImpl = newImpl!=NULL ? newImpl : &wxLaunchDefaultBrowserBaseImpl; -} - -static bool wxLaunchDefaultBrowserBaseImpl(const wxString& url, int flags) -{ - wxUnusedVar(flags); - -#if defined(__WXMSW__) - -#if wxUSE_IPC - if ( flags & wxBROWSER_NEW_WINDOW ) - { - // ShellExecuteEx() opens the URL in an existing window by default so - // we can't use it if we need a new window - wxURI uri(url); - wxRegKey key(wxRegKey::HKCR, uri.GetScheme() + _T("\\shell\\open")); - if ( !key.Exists() ) - { - // try default browser, it must be registered at least for http URLs - key.SetName(wxRegKey::HKCR, _T("http\\shell\\open")); - } - - if ( key.Exists() ) - { - wxRegKey keyDDE(key, wxT("DDEExec")); - if ( keyDDE.Exists() ) - { - // we only know the syntax of WWW_OpenURL DDE request for IE, - // optimistically assume that all other browsers are compatible - // with it - static const wxString TOPIC_OPEN_URL = wxT("WWW_OpenURL"); - wxString ddeCmd; - wxRegKey keyTopic(keyDDE, wxT("topic")); - bool ok = keyTopic.Exists() && (keyTopic.QueryDefaultValue() = TOPIC_OPEN_URL); - if ( ok ) - { - ddeCmd = keyDDE.QueryDefaultValue(); - ok = !ddeCmd.empty(); - } - - if ( ok ) - { - // for WWW_OpenURL, the index of the window to open the URL - // in is -1 (meaning "current") by default, replace it with - // 0 which means "new" (see KB article 160957) - ok = ddeCmd.Replace(wxT("-1"), wxT("0"), - false /* only first occurence */) == 1; - } - - if ( ok ) - { - // and also replace the parameters: the topic should - // contain a placeholder for the URL - ok = ddeCmd.Replace(wxT("%1"), url, false) == 1; - } - - if ( ok ) - { - // try to send it the DDE request now but ignore the errors - wxLogNull noLog; - - const wxString ddeServer = wxRegKey(keyDDE, wxT("application")).QueryDefaultValue(); - if ( wxExecuteDDE(ddeServer, TOPIC_OPEN_URL, ddeCmd) ) - return true; - - // this is not necessarily an error: maybe browser is - // simply not running, but no matter, in any case we're - // going to launch it using ShellExecuteEx() below now and - // we shouldn't try to open a new window if we open a new - // browser anyhow - } - } - } - } -#endif // wxUSE_IPC - - WinStruct sei; - sei.lpFile = url.c_str(); - sei.lpVerb = _T("open"); - sei.nShow = SW_SHOWNORMAL; - sei.fMask = SEE_MASK_FLAG_NO_UI; // we give error message ourselves - - BOOL nExecResult = ::ShellExecuteEx(&sei); - - //From MSDN for wince - //hInstApp member is only valid if the function fails, in which case it - //receives one of the following error values, which are less than or - //equal to 32. - const int nResult = (int) sei.hInstApp; - - // Firefox returns file not found for some reason, so make an exception - // for it - if ( nResult > 32 || nResult == SE_ERR_FNF || nExecResult == TRUE ) - { -#ifdef __WXDEBUG__ - // Log something if SE_ERR_FNF happens - if ( nResult == SE_ERR_FNF || nExecResult == FALSE ) - wxLogDebug(wxT("SE_ERR_FNF from ShellExecute -- maybe FireFox?")); -#endif // __WXDEBUG__ - return true; - } -#elif defined(__WXMAC__) - OSStatus err; - ICInstance inst; - long int startSel; - long int endSel; - - err = ICStart(&inst, 'STKA'); // put your app creator code here - if (err == noErr) - { -#if !TARGET_CARBON - err = ICFindConfigFile(inst, 0, NULL); -#endif - if (err == noErr) - { - ConstStr255Param hint = 0; - startSel = 0; - endSel = url.length(); - err = ICLaunchURL(inst, hint, url.fn_str(), endSel, &startSel, &endSel); - if (err != noErr) - wxLogDebug(wxT("ICLaunchURL error %d"), (int) err); - } - ICStop(inst); - return true; - } - else - { - wxLogDebug(wxT("ICStart error %d"), (int) err); - return false; - } -#else - // (non-Mac, non-MSW) - -#ifdef __UNIX__ - - // Our best best is to use xdg-open from freedesktop.org cross-desktop - // compatibility suite xdg-utils - // (see http://portland.freedesktop.org/wiki/) -- this is installed on - // most modern distributions and may be tweaked by them to handle - // distribution specifics. Only if that fails, try to find the right - // browser ourselves. - wxString path, xdg_open; - if ( wxGetEnv(_T("PATH"), &path) && - wxFindFileInPath(&xdg_open, path, _T("xdg-open")) ) - { - if ( wxExecute(xdg_open + _T(" ") + url) ) - return true; - } - - wxString desktop = wxTheApp->GetTraits()->GetDesktopEnvironment(); - - // GNOME and KDE desktops have some applications which should be always installed - // together with their main parts, which give us the - if (desktop == wxT("GNOME")) - { - wxArrayString errors; - wxArrayString output; - - // gconf will tell us the path of the application to use as browser - long res = wxExecute( wxT("gconftool-2 --get /desktop/gnome/applications/browser/exec"), - output, errors, wxEXEC_NODISABLE ); - if (res >= 0 && errors.GetCount() == 0) - { - wxString cmd = output[0]; - cmd << _T(' ') << url; - if (wxExecute(cmd)) - return true; - } - } - else if (desktop == wxT("KDE")) - { - // kfmclient directly opens the given URL - if (wxExecute(wxT("kfmclient openURL ") + url)) - return true; - } -#endif - - bool ok = false; - wxString cmd; - -#if wxUSE_MIMETYPE - wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(_T("html")); - if ( ft ) - { - wxString mt; - ft->GetMimeType(&mt); - - ok = ft->GetOpenCommand(&cmd, wxFileType::MessageParameters(url)); - delete ft; - } -#endif // wxUSE_MIMETYPE - - if ( !ok || cmd.empty() ) - { - // fallback to checking for the BROWSER environment variable - cmd = wxGetenv(wxT("BROWSER")); - if ( !cmd.empty() ) - cmd << _T(' ') << url; - } - - ok = ( !cmd.empty() && wxExecute(cmd) ); - if (ok) - return ok; - - // no file type for HTML extension - wxLogError(_T("No default application configured for HTML files.")); - -#endif // !wxUSE_MIMETYPE && !__WXMSW__ - return false; -} - -bool wxLaunchDefaultBrowser(const wxString& urlOrig, int flags) -{ - // set the scheme of url to http if it does not have one - // RR: This doesn't work if the url is just a local path - wxString url(urlOrig); - wxURI uri(url); - if ( !uri.HasScheme() ) - { - if (wxFileExists(urlOrig)) - url.Prepend( wxT("file://") ); - else - url.Prepend(wxT("http://")); - } - - if(s_launchBrowserImpl(url, flags)) - return true; - - wxLogSysError(_T("Failed to open URL \"%s\" in default browser."), - url.c_str()); - - return false; -} - -// ---------------------------------------------------------------------------- -// wxApp::Yield() wrappers for backwards compatibility -// ---------------------------------------------------------------------------- - -bool wxYield() -{ - return wxTheApp && wxTheApp->Yield(); -} - -bool wxYieldIfNeeded() -{ - return wxTheApp && wxTheApp->Yield(true); -} - -#endif // wxUSE_BASE - -// ============================================================================ -// GUI-only functions from now on -// ============================================================================ - -#if wxUSE_GUI - -// Id generation -static long wxCurrentId = 100; - -long wxNewId() -{ - // skip the part of IDs space that contains hard-coded values: - if (wxCurrentId == wxID_LOWEST) - wxCurrentId = wxID_HIGHEST + 1; - - return wxCurrentId++; -} - -long -wxGetCurrentId(void) { return wxCurrentId; } - -void -wxRegisterId (long id) -{ - if (id >= wxCurrentId) - wxCurrentId = id + 1; -} - -// ---------------------------------------------------------------------------- -// Menu accelerators related functions -// ---------------------------------------------------------------------------- - -wxChar *wxStripMenuCodes(const wxChar *in, wxChar *out) -{ -#if wxUSE_MENUS - wxString s = wxMenuItem::GetLabelFromText(in); -#else - wxString str(in); - wxString s = wxStripMenuCodes(str); -#endif // wxUSE_MENUS - if ( out ) - { - // go smash their buffer if it's not big enough - I love char * params - memcpy(out, s.c_str(), s.length() * sizeof(wxChar)); - } - else - { - // MYcopystring - for easier search... - out = new wxChar[s.length() + 1]; - wxStrcpy(out, s.c_str()); - } - - return out; -} - -wxString wxStripMenuCodes(const wxString& in, int flags) -{ - wxASSERT_MSG( flags, _T("this is useless to call without any flags") ); - - wxString out; - - size_t len = in.length(); - out.reserve(len); - - for ( size_t n = 0; n < len; n++ ) - { - wxChar ch = in[n]; - if ( (flags & wxStrip_Mnemonics) && ch == _T('&') ) - { - // skip it, it is used to introduce the accel char (or to quote - // itself in which case it should still be skipped): note that it - // can't be the last character of the string - if ( ++n == len ) - { - wxLogDebug(_T("Invalid menu string '%s'"), in.c_str()); - } - else - { - // use the next char instead - ch = in[n]; - } - } - else if ( (flags & wxStrip_Accel) && ch == _T('\t') ) - { - // everything after TAB is accel string, exit the loop - break; - } - - out += ch; - } - - return out; -} - -// ---------------------------------------------------------------------------- -// Window search functions -// ---------------------------------------------------------------------------- - -/* - * If parent is non-NULL, look through children for a label or title - * matching the specified string. If NULL, look through all top-level windows. - * - */ - -wxWindow * -wxFindWindowByLabel (const wxString& title, wxWindow * parent) -{ - return wxWindow::FindWindowByLabel( title, parent ); -} - - -/* - * If parent is non-NULL, look through children for a name - * matching the specified string. If NULL, look through all top-level windows. - * - */ - -wxWindow * -wxFindWindowByName (const wxString& name, wxWindow * parent) -{ - return wxWindow::FindWindowByName( name, parent ); -} - -// Returns menu item id or wxNOT_FOUND if none. -int -wxFindMenuItemId (wxFrame * frame, const wxString& menuString, const wxString& itemString) -{ -#if wxUSE_MENUS - wxMenuBar *menuBar = frame->GetMenuBar (); - if ( menuBar ) - return menuBar->FindMenuItem (menuString, itemString); -#endif // wxUSE_MENUS - - return wxNOT_FOUND; -} - -// Try to find the deepest child that contains 'pt'. -// We go backwards, to try to allow for controls that are spacially -// within other controls, but are still siblings (e.g. buttons within -// static boxes). Static boxes are likely to be created _before_ controls -// that sit inside them. -wxWindow* wxFindWindowAtPoint(wxWindow* win, const wxPoint& pt) -{ - if (!win->IsShown()) - return NULL; - - // Hack for wxNotebook case: at least in wxGTK, all pages - // claim to be shown, so we must only deal with the selected one. -#if wxUSE_NOTEBOOK - if (win->IsKindOf(CLASSINFO(wxNotebook))) - { - wxNotebook* nb = (wxNotebook*) win; - int sel = nb->GetSelection(); - if (sel >= 0) - { - wxWindow* child = nb->GetPage(sel); - wxWindow* foundWin = wxFindWindowAtPoint(child, pt); - if (foundWin) - return foundWin; - } - } -#endif - - wxWindowList::compatibility_iterator node = win->GetChildren().GetLast(); - while (node) - { - wxWindow* child = node->GetData(); - wxWindow* foundWin = wxFindWindowAtPoint(child, pt); - if (foundWin) - return foundWin; - node = node->GetPrevious(); - } - - wxPoint pos = win->GetPosition(); - wxSize sz = win->GetSize(); - if ( !win->IsTopLevel() && win->GetParent() ) - { - pos = win->GetParent()->ClientToScreen(pos); - } - - wxRect rect(pos, sz); - if (rect.Contains(pt)) - return win; - - return NULL; -} - -wxWindow* wxGenericFindWindowAtPoint(const wxPoint& pt) -{ - // Go backwards through the list since windows - // on top are likely to have been appended most - // recently. - wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetLast(); - while (node) - { - wxWindow* win = node->GetData(); - wxWindow* found = wxFindWindowAtPoint(win, pt); - if (found) - return found; - node = node->GetPrevious(); - } - return NULL; -} - -// ---------------------------------------------------------------------------- -// GUI helpers -// ---------------------------------------------------------------------------- - -/* - * N.B. these convenience functions must be separate from msgdlgg.cpp, textdlgg.cpp - * since otherwise the generic code may be pulled in unnecessarily. - */ - -#if wxUSE_MSGDLG - -int wxMessageBox(const wxString& message, const wxString& caption, long style, - wxWindow *parent, int WXUNUSED(x), int WXUNUSED(y) ) -{ - long decorated_style = style; - - if ( ( style & ( wxICON_EXCLAMATION | wxICON_HAND | wxICON_INFORMATION | wxICON_QUESTION ) ) == 0 ) - { - decorated_style |= ( style & wxYES ) ? wxICON_QUESTION : wxICON_INFORMATION ; - } - - wxMessageDialog dialog(parent, message, caption, decorated_style); - - int ans = dialog.ShowModal(); - switch ( ans ) - { - case wxID_OK: - return wxOK; - case wxID_YES: - return wxYES; - case wxID_NO: - return wxNO; - case wxID_CANCEL: - return wxCANCEL; - } - - wxFAIL_MSG( _T("unexpected return code from wxMessageDialog") ); - - return wxCANCEL; -} - -#endif // wxUSE_MSGDLG - -#if wxUSE_TEXTDLG - -wxString wxGetTextFromUser(const wxString& message, const wxString& caption, - const wxString& defaultValue, wxWindow *parent, - wxCoord x, wxCoord y, bool centre ) -{ - wxString str; - long style = wxTextEntryDialogStyle; - - if (centre) - style |= wxCENTRE; - else - style &= ~wxCENTRE; - - wxTextEntryDialog dialog(parent, message, caption, defaultValue, style, wxPoint(x, y)); - - if (dialog.ShowModal() == wxID_OK) - { - str = dialog.GetValue(); - } - - return str; -} - -wxString wxGetPasswordFromUser(const wxString& message, - const wxString& caption, - const wxString& defaultValue, - wxWindow *parent, - wxCoord x, wxCoord y, bool centre ) -{ - wxString str; - long style = wxTextEntryDialogStyle; - - if (centre) - style |= wxCENTRE; - else - style &= ~wxCENTRE; - - wxPasswordEntryDialog dialog(parent, message, caption, defaultValue, - style, wxPoint(x, y)); - if ( dialog.ShowModal() == wxID_OK ) - { - str = dialog.GetValue(); - } - - return str; -} - -#endif // wxUSE_TEXTDLG - -#if wxUSE_COLOURDLG - -wxColour wxGetColourFromUser(wxWindow *parent, const wxColour& colInit, const wxString& caption) -{ - static wxColourData data; - data.SetChooseFull(true); - if ( colInit.Ok() ) - { - data.SetColour((wxColour &)colInit); // const_cast - } - - wxColour colRet; - wxColourDialog dialog(parent, &data); - if (!caption.empty()) - dialog.SetTitle(caption); - if ( dialog.ShowModal() == wxID_OK ) - { - colRet = dialog.GetColourData().GetColour(); - } - //else: leave it invalid - - return colRet; -} - -#endif // wxUSE_COLOURDLG - -#if wxUSE_FONTDLG - -wxFont wxGetFontFromUser(wxWindow *parent, const wxFont& fontInit, const wxString& caption) -{ - wxFontData data; - if ( fontInit.Ok() ) - { - data.SetInitialFont(fontInit); - } - - wxFont fontRet; - wxFontDialog dialog(parent, data); - if (!caption.empty()) - dialog.SetTitle(caption); - if ( dialog.ShowModal() == wxID_OK ) - { - fontRet = dialog.GetFontData().GetChosenFont(); - } - //else: leave it invalid - - return fontRet; -} - -#endif // wxUSE_FONTDLG - -// ---------------------------------------------------------------------------- -// wxSafeYield and supporting functions -// ---------------------------------------------------------------------------- - -void wxEnableTopLevelWindows(bool enable) -{ - wxWindowList::compatibility_iterator node; - for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() ) - node->GetData()->Enable(enable); -} - -wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip) -{ - // remember the top level windows which were already disabled, so that we - // don't reenable them later - m_winDisabled = NULL; - - wxWindowList::compatibility_iterator node; - for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() ) - { - wxWindow *winTop = node->GetData(); - if ( winTop == winToSkip ) - continue; - - // we don't need to disable the hidden or already disabled windows - if ( winTop->IsEnabled() && winTop->IsShown() ) - { - winTop->Disable(); - } - else - { - if ( !m_winDisabled ) - { - m_winDisabled = new wxWindowList; - } - - m_winDisabled->Append(winTop); - } - } -} - -wxWindowDisabler::~wxWindowDisabler() -{ - wxWindowList::compatibility_iterator node; - for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() ) - { - wxWindow *winTop = node->GetData(); - if ( !m_winDisabled || !m_winDisabled->Find(winTop) ) - { - winTop->Enable(); - } - //else: had been already disabled, don't reenable - } - - delete m_winDisabled; -} - -// Yield to other apps/messages and disable user input to all windows except -// the given one -bool wxSafeYield(wxWindow *win, bool onlyIfNeeded) -{ - wxWindowDisabler wd(win); - - bool rc; - if (onlyIfNeeded) - rc = wxYieldIfNeeded(); - else - rc = wxYield(); - - return rc; -} - -// Don't synthesize KeyUp events holding down a key and producing KeyDown -// events with autorepeat. On by default and always on in wxMSW. wxGTK version -// in utilsgtk.cpp. -#ifndef __WXGTK__ -bool wxSetDetectableAutoRepeat( bool WXUNUSED(flag) ) -{ - return true; // detectable auto-repeat is the only mode MSW supports -} -#endif // !wxGTK - -#endif // wxUSE_GUI +// Name: src/common/utilscmn.cpp +// Purpose: Miscellaneous utility functions and classes +// Author: Julian Smart +// Modified by: +// Created: 29/01/98 +// RCS-ID: $Id: utilscmn.cpp 66917 2011-02-16 21:51:31Z JS $ +// Copyright: (c) 1998 Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/app.h" + #include "wx/string.h" + #include "wx/utils.h" + #include "wx/intl.h" + #include "wx/log.h" + + #if wxUSE_GUI + #include "wx/window.h" + #include "wx/frame.h" + #include "wx/menu.h" + #include "wx/msgdlg.h" + #include "wx/textdlg.h" + #include "wx/textctrl.h" // for wxTE_PASSWORD + #if wxUSE_ACCEL + #include "wx/menuitem.h" + #include "wx/accel.h" + #endif // wxUSE_ACCEL + #endif // wxUSE_GUI +#endif // WX_PRECOMP + +#include "wx/apptrait.h" + +#include "wx/process.h" +#include "wx/txtstrm.h" +#include "wx/uri.h" +#include "wx/mimetype.h" +#include "wx/config.h" + +#if defined(__WXWINCE__) && wxUSE_DATETIME +#include "wx/datetime.h" +#endif + +#include +#include +#include +#include + +#if !wxONLY_WATCOM_EARLIER_THAN(1,4) + #if !(defined(_MSC_VER) && (_MSC_VER > 800)) + #include + #endif +#endif + +#if wxUSE_GUI + #include "wx/colordlg.h" + #include "wx/fontdlg.h" + #include "wx/notebook.h" + #include "wx/statusbr.h" +#endif // wxUSE_GUI + +#ifndef __WXWINCE__ +#include +#else +#include "wx/msw/wince/time.h" +#endif + +#ifdef __WXMAC__ +#include "wx/mac/private.h" +#ifndef __DARWIN__ +#include "InternetConfig.h" +#endif +#endif + +#if !defined(__MWERKS__) && !defined(__WXWINCE__) + #include + #include +#endif + +#if defined(__WXMSW__) + #include "wx/msw/private.h" + #include "wx/msw/registry.h" + #include // needed for SHELLEXECUTEINFO +#endif + +#if wxUSE_BASE + +// ---------------------------------------------------------------------------- +// common data +// ---------------------------------------------------------------------------- + +// ============================================================================ +// implementation +// ============================================================================ + +#if WXWIN_COMPATIBILITY_2_4 + +wxChar * +copystring (const wxChar *s) +{ + if (s == NULL) s = wxEmptyString; + size_t len = wxStrlen (s) + 1; + + wxChar *news = new wxChar[len]; + memcpy (news, s, len * sizeof(wxChar)); // Should be the fastest + + return news; +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +// ---------------------------------------------------------------------------- +// String <-> Number conversions (deprecated) +// ---------------------------------------------------------------------------- + +#if WXWIN_COMPATIBILITY_2_4 + +WXDLLIMPEXP_DATA_BASE(const wxChar *) wxFloatToStringStr = wxT("%.2f"); +WXDLLIMPEXP_DATA_BASE(const wxChar *) wxDoubleToStringStr = wxT("%.2f"); + +void +StringToFloat (const wxChar *s, float *number) +{ + if (s && *s && number) + *number = (float) wxStrtod (s, (wxChar **) NULL); +} + +void +StringToDouble (const wxChar *s, double *number) +{ + if (s && *s && number) + *number = wxStrtod (s, (wxChar **) NULL); +} + +wxChar * +FloatToString (float number, const wxChar *fmt) +{ + static wxChar buf[256]; + + wxSprintf (buf, fmt, number); + return buf; +} + +wxChar * +DoubleToString (double number, const wxChar *fmt) +{ + static wxChar buf[256]; + + wxSprintf (buf, fmt, number); + return buf; +} + +void +StringToInt (const wxChar *s, int *number) +{ + if (s && *s && number) + *number = (int) wxStrtol (s, (wxChar **) NULL, 10); +} + +void +StringToLong (const wxChar *s, long *number) +{ + if (s && *s && number) + *number = wxStrtol (s, (wxChar **) NULL, 10); +} + +wxChar * +IntToString (int number) +{ + static wxChar buf[20]; + + wxSprintf (buf, wxT("%d"), number); + return buf; +} + +wxChar * +LongToString (long number) +{ + static wxChar buf[20]; + + wxSprintf (buf, wxT("%ld"), number); + return buf; +} + +#endif // WXWIN_COMPATIBILITY_2_4 + +// Array used in DecToHex conversion routine. +static wxChar hexArray[] = wxT("0123456789ABCDEF"); + +// Convert 2-digit hex number to decimal +int wxHexToDec(const wxString& buf) +{ + int firstDigit, secondDigit; + + if (buf.GetChar(0) >= wxT('A')) + firstDigit = buf.GetChar(0) - wxT('A') + 10; + else + firstDigit = buf.GetChar(0) - wxT('0'); + + if (buf.GetChar(1) >= wxT('A')) + secondDigit = buf.GetChar(1) - wxT('A') + 10; + else + secondDigit = buf.GetChar(1) - wxT('0'); + + return (firstDigit & 0xF) * 16 + (secondDigit & 0xF ); +} + +// Convert decimal integer to 2-character hex string +void wxDecToHex(int dec, wxChar *buf) +{ + int firstDigit = (int)(dec/16.0); + int secondDigit = (int)(dec - (firstDigit*16.0)); + buf[0] = hexArray[firstDigit]; + buf[1] = hexArray[secondDigit]; + buf[2] = 0; +} + +// Convert decimal integer to 2-character hex string +wxString wxDecToHex(int dec) +{ + wxChar buf[3]; + wxDecToHex(dec, buf); + return wxString(buf); +} + +// ---------------------------------------------------------------------------- +// misc functions +// ---------------------------------------------------------------------------- + +// Return the current date/time +wxString wxNow() +{ +#ifdef __WXWINCE__ +#if wxUSE_DATETIME + wxDateTime now = wxDateTime::Now(); + return now.Format(); +#else + return wxEmptyString; +#endif +#else + time_t now = time((time_t *) NULL); + char *date = ctime(&now); + date[24] = '\0'; + return wxString::FromAscii(date); +#endif +} + +void wxUsleep(unsigned long milliseconds) +{ + wxMilliSleep(milliseconds); +} + +const wxChar *wxGetInstallPrefix() +{ + wxString prefix; + + if ( wxGetEnv(wxT("WXPREFIX"), &prefix) ) + return prefix.c_str(); + +#ifdef wxINSTALL_PREFIX + return wxT(wxINSTALL_PREFIX); +#else + return wxEmptyString; +#endif +} + +wxString wxGetDataDir() +{ + wxString dir = wxGetInstallPrefix(); + dir << wxFILE_SEP_PATH << wxT("share") << wxFILE_SEP_PATH << wxT("wx"); + return dir; +} + +bool wxIsPlatformLittleEndian() +{ + // Are we little or big endian? This method is from Harbison & Steele. + union + { + long l; + char c[sizeof(long)]; + } u; + u.l = 1; + + return u.c[0] == 1; +} + + +/* + * Class to make it easier to specify platform-dependent values + */ + +wxArrayInt* wxPlatform::sm_customPlatforms = NULL; + +void wxPlatform::Copy(const wxPlatform& platform) +{ + m_longValue = platform.m_longValue; + m_doubleValue = platform.m_doubleValue; + m_stringValue = platform.m_stringValue; +} + +wxPlatform wxPlatform::If(int platform, long value) +{ + if (Is(platform)) + return wxPlatform(value); + else + return wxPlatform(); +} + +wxPlatform wxPlatform::IfNot(int platform, long value) +{ + if (!Is(platform)) + return wxPlatform(value); + else + return wxPlatform(); +} + +wxPlatform& wxPlatform::ElseIf(int platform, long value) +{ + if (Is(platform)) + m_longValue = value; + return *this; +} + +wxPlatform& wxPlatform::ElseIfNot(int platform, long value) +{ + if (!Is(platform)) + m_longValue = value; + return *this; +} + +wxPlatform wxPlatform::If(int platform, double value) +{ + if (Is(platform)) + return wxPlatform(value); + else + return wxPlatform(); +} + +wxPlatform wxPlatform::IfNot(int platform, double value) +{ + if (!Is(platform)) + return wxPlatform(value); + else + return wxPlatform(); +} + +wxPlatform& wxPlatform::ElseIf(int platform, double value) +{ + if (Is(platform)) + m_doubleValue = value; + return *this; +} + +wxPlatform& wxPlatform::ElseIfNot(int platform, double value) +{ + if (!Is(platform)) + m_doubleValue = value; + return *this; +} + +wxPlatform wxPlatform::If(int platform, const wxString& value) +{ + if (Is(platform)) + return wxPlatform(value); + else + return wxPlatform(); +} + +wxPlatform wxPlatform::IfNot(int platform, const wxString& value) +{ + if (!Is(platform)) + return wxPlatform(value); + else + return wxPlatform(); +} + +wxPlatform& wxPlatform::ElseIf(int platform, const wxString& value) +{ + if (Is(platform)) + m_stringValue = value; + return *this; +} + +wxPlatform& wxPlatform::ElseIfNot(int platform, const wxString& value) +{ + if (!Is(platform)) + m_stringValue = value; + return *this; +} + +wxPlatform& wxPlatform::Else(long value) +{ + m_longValue = value; + return *this; +} + +wxPlatform& wxPlatform::Else(double value) +{ + m_doubleValue = value; + return *this; +} + +wxPlatform& wxPlatform::Else(const wxString& value) +{ + m_stringValue = value; + return *this; +} + +void wxPlatform::AddPlatform(int platform) +{ + if (!sm_customPlatforms) + sm_customPlatforms = new wxArrayInt; + sm_customPlatforms->Add(platform); +} + +void wxPlatform::ClearPlatforms() +{ + delete sm_customPlatforms; + sm_customPlatforms = NULL; +} + +/// Function for testing current platform + +bool wxPlatform::Is(int platform) +{ +#ifdef __WXMSW__ + if (platform == wxOS_WINDOWS) + return true; +#endif +#ifdef __WXWINCE__ + if (platform == wxOS_WINDOWS_CE) + return true; +#endif + +#if 0 + +// FIXME: wxWinPocketPC and wxWinSmartPhone are unknown symbols + +#if defined(__WXWINCE__) && defined(__POCKETPC__) + if (platform == wxWinPocketPC) + return true; +#endif +#if defined(__WXWINCE__) && defined(__SMARTPHONE__) + if (platform == wxWinSmartPhone) + return true; +#endif + +#endif + +#ifdef __WXGTK__ + if (platform == wxPORT_GTK) + return true; +#endif +#ifdef __WXMAC__ + if (platform == wxPORT_MAC) + return true; +#endif +#ifdef __WXX11__ + if (platform == wxPORT_X11) + return true; +#endif +#ifdef __UNIX__ + if (platform == wxOS_UNIX) + return true; +#endif +#ifdef __WXMGL__ + if (platform == wxPORT_MGL) + return true; +#endif +#ifdef __OS2__ + if (platform == wxOS_OS2) + return true; +#endif +#ifdef __WXPM__ + if (platform == wxPORT_PM) + return true; +#endif +#ifdef __WXCOCOA__ + if (platform == wxPORT_MAC) + return true; +#endif + + if (sm_customPlatforms && sm_customPlatforms->Index(platform) != wxNOT_FOUND) + return true; + + return false; +} + +// ---------------------------------------------------------------------------- +// network and user id functions +// ---------------------------------------------------------------------------- + +// Get Full RFC822 style email address +bool wxGetEmailAddress(wxChar *address, int maxSize) +{ + wxString email = wxGetEmailAddress(); + if ( !email ) + return false; + + wxStrncpy(address, email, maxSize - 1); + address[maxSize - 1] = wxT('\0'); + + return true; +} + +wxString wxGetEmailAddress() +{ + wxString email; + + wxString host = wxGetFullHostName(); + if ( !host.empty() ) + { + wxString user = wxGetUserId(); + if ( !user.empty() ) + { + email << user << wxT('@') << host; + } + } + + return email; +} + +wxString wxGetUserId() +{ + static const int maxLoginLen = 256; // FIXME arbitrary number + + wxString buf; + bool ok = wxGetUserId(wxStringBuffer(buf, maxLoginLen), maxLoginLen); + + if ( !ok ) + buf.Empty(); + + return buf; +} + +wxString wxGetUserName() +{ + static const int maxUserNameLen = 1024; // FIXME arbitrary number + + wxString buf; + bool ok = wxGetUserName(wxStringBuffer(buf, maxUserNameLen), maxUserNameLen); + + if ( !ok ) + buf.Empty(); + + return buf; +} + +wxString wxGetHostName() +{ + static const size_t hostnameSize = 257; + + wxString buf; + bool ok = wxGetHostName(wxStringBuffer(buf, hostnameSize), hostnameSize); + + if ( !ok ) + buf.Empty(); + + return buf; +} + +wxString wxGetFullHostName() +{ + static const size_t hostnameSize = 257; + + wxString buf; + bool ok = wxGetFullHostName(wxStringBuffer(buf, hostnameSize), hostnameSize); + + if ( !ok ) + buf.Empty(); + + return buf; +} + +wxString wxGetHomeDir() +{ + wxString home; + wxGetHomeDir(&home); + + return home; +} + +#if 0 + +wxString wxGetCurrentDir() +{ + wxString dir; + size_t len = 1024; + bool ok; + do + { + ok = getcwd(dir.GetWriteBuf(len + 1), len) != NULL; + dir.UngetWriteBuf(); + + if ( !ok ) + { + if ( errno != ERANGE ) + { + wxLogSysError(_T("Failed to get current directory")); + + return wxEmptyString; + } + else + { + // buffer was too small, retry with a larger one + len *= 2; + } + } + //else: ok + } while ( !ok ); + + return dir; +} + +#endif // 0 + +// ---------------------------------------------------------------------------- +// wxExecute +// ---------------------------------------------------------------------------- + +// wxDoExecuteWithCapture() helper: reads an entire stream into one array +// +// returns true if ok, false if error +#if wxUSE_STREAMS +static bool ReadAll(wxInputStream *is, wxArrayString& output) +{ + wxCHECK_MSG( is, false, _T("NULL stream in wxExecute()?") ); + + // the stream could be already at EOF or in wxSTREAM_BROKEN_PIPE state + is->Reset(); + + wxTextInputStream tis(*is); + + for ( ;; ) + { + wxString line = tis.ReadLine(); + + // check for EOF before other errors as it's not really an error + if ( is->Eof() ) + { + // add the last, possibly incomplete, line + if ( !line.empty() ) + output.Add(line); + break; + } + + // any other error is fatal + if ( !*is ) + return false; + + output.Add(line); + } + + return true; +} +#endif // wxUSE_STREAMS + +// this is a private function because it hasn't a clean interface: the first +// array is passed by reference, the second by pointer - instead we have 2 +// public versions of wxExecute() below +static long wxDoExecuteWithCapture(const wxString& command, + wxArrayString& output, + wxArrayString* error, + int flags) +{ + // create a wxProcess which will capture the output + wxProcess *process = new wxProcess; + process->Redirect(); + + long rc = wxExecute(command, wxEXEC_SYNC | flags, process); + +#if wxUSE_STREAMS + if ( rc != -1 ) + { + if ( !ReadAll(process->GetInputStream(), output) ) + rc = -1; + + if ( error ) + { + if ( !ReadAll(process->GetErrorStream(), *error) ) + rc = -1; + } + + } +#else + wxUnusedVar(output); + wxUnusedVar(error); +#endif // wxUSE_STREAMS/!wxUSE_STREAMS + + delete process; + + return rc; +} + +long wxExecute(const wxString& command, wxArrayString& output, int flags) +{ + return wxDoExecuteWithCapture(command, output, NULL, flags); +} + +long wxExecute(const wxString& command, + wxArrayString& output, + wxArrayString& error, + int flags) +{ + return wxDoExecuteWithCapture(command, output, &error, flags); +} + +// ---------------------------------------------------------------------------- +// Launch default browser +// ---------------------------------------------------------------------------- + +#include "wx/private/browserhack28.h" + +static bool wxLaunchDefaultBrowserBaseImpl(const wxString& url, int flags); + +// Use wxLaunchDefaultBrowserBaseImpl by default +static wxLaunchDefaultBrowserImpl_t s_launchBrowserImpl = &wxLaunchDefaultBrowserBaseImpl; + +// Function the GUI library can call to provide a better implementation +WXDLLIMPEXP_BASE void wxSetLaunchDefaultBrowserImpl(wxLaunchDefaultBrowserImpl_t newImpl) +{ + s_launchBrowserImpl = newImpl!=NULL ? newImpl : &wxLaunchDefaultBrowserBaseImpl; +} + +static bool wxLaunchDefaultBrowserBaseImpl(const wxString& url, int flags) +{ + wxUnusedVar(flags); + +#if defined(__WXMSW__) + +#if wxUSE_IPC + if ( flags & wxBROWSER_NEW_WINDOW ) + { + // ShellExecuteEx() opens the URL in an existing window by default so + // we can't use it if we need a new window + wxURI uri(url); + wxRegKey key(wxRegKey::HKCR, uri.GetScheme() + _T("\\shell\\open")); + if ( !key.Exists() ) + { + // try default browser, it must be registered at least for http URLs + key.SetName(wxRegKey::HKCR, _T("http\\shell\\open")); + } + + if ( key.Exists() ) + { + wxRegKey keyDDE(key, wxT("DDEExec")); + if ( keyDDE.Exists() ) + { + // we only know the syntax of WWW_OpenURL DDE request for IE, + // optimistically assume that all other browsers are compatible + // with it + static const wxString TOPIC_OPEN_URL = wxT("WWW_OpenURL"); + wxString ddeCmd; + wxRegKey keyTopic(keyDDE, wxT("topic")); + bool ok = keyTopic.Exists() && (keyTopic.QueryDefaultValue() = TOPIC_OPEN_URL); + if ( ok ) + { + ddeCmd = keyDDE.QueryDefaultValue(); + ok = !ddeCmd.empty(); + } + + if ( ok ) + { + // for WWW_OpenURL, the index of the window to open the URL + // in is -1 (meaning "current") by default, replace it with + // 0 which means "new" (see KB article 160957) + ok = ddeCmd.Replace(wxT("-1"), wxT("0"), + false /* only first occurence */) == 1; + } + + if ( ok ) + { + // and also replace the parameters: the topic should + // contain a placeholder for the URL + ok = ddeCmd.Replace(wxT("%1"), url, false) == 1; + } + + if ( ok ) + { + // try to send it the DDE request now but ignore the errors + wxLogNull noLog; + + const wxString ddeServer = wxRegKey(keyDDE, wxT("application")).QueryDefaultValue(); + if ( wxExecuteDDE(ddeServer, TOPIC_OPEN_URL, ddeCmd) ) + return true; + + // this is not necessarily an error: maybe browser is + // simply not running, but no matter, in any case we're + // going to launch it using ShellExecuteEx() below now and + // we shouldn't try to open a new window if we open a new + // browser anyhow + } + } + } + } +#endif // wxUSE_IPC + + WinStruct sei; + sei.lpFile = url.c_str(); + sei.lpVerb = _T("open"); + sei.nShow = SW_SHOWNORMAL; + sei.fMask = SEE_MASK_FLAG_NO_UI; // we give error message ourselves + + BOOL nExecResult = ::ShellExecuteEx(&sei); + + //From MSDN for wince + //hInstApp member is only valid if the function fails, in which case it + //receives one of the following error values, which are less than or + //equal to 32. + const int nResult = (int) sei.hInstApp; + + // Firefox returns file not found for some reason, so make an exception + // for it + if ( nResult > 32 || nResult == SE_ERR_FNF || nExecResult == TRUE ) + { +#ifdef __WXDEBUG__ + // Log something if SE_ERR_FNF happens + if ( nResult == SE_ERR_FNF || nExecResult == FALSE ) + wxLogDebug(wxT("SE_ERR_FNF from ShellExecute -- maybe FireFox?")); +#endif // __WXDEBUG__ + return true; + } +#elif defined(__WXMAC__) + OSStatus err; + ICInstance inst; + long int startSel; + long int endSel; + + err = ICStart(&inst, 'STKA'); // put your app creator code here + if (err == noErr) + { +#if !TARGET_CARBON + err = ICFindConfigFile(inst, 0, NULL); +#endif + if (err == noErr) + { + ConstStr255Param hint = 0; + startSel = 0; + endSel = url.length(); + err = ICLaunchURL(inst, hint, url.fn_str(), endSel, &startSel, &endSel); + if (err != noErr) + wxLogDebug(wxT("ICLaunchURL error %d"), (int) err); + } + ICStop(inst); + return true; + } + else + { + wxLogDebug(wxT("ICStart error %d"), (int) err); + return false; + } +#else + // (non-Mac, non-MSW) + +#ifdef __UNIX__ + + // Our best best is to use xdg-open from freedesktop.org cross-desktop + // compatibility suite xdg-utils + // (see http://portland.freedesktop.org/wiki/) -- this is installed on + // most modern distributions and may be tweaked by them to handle + // distribution specifics. Only if that fails, try to find the right + // browser ourselves. + wxString path, xdg_open; + if ( wxGetEnv(_T("PATH"), &path) && + wxFindFileInPath(&xdg_open, path, _T("xdg-open")) ) + { + if ( wxExecute(xdg_open + _T(" ") + url) ) + return true; + } + + wxString desktop = wxTheApp->GetTraits()->GetDesktopEnvironment(); + + // GNOME and KDE desktops have some applications which should be always installed + // together with their main parts, which give us the + if (desktop == wxT("GNOME")) + { + wxArrayString errors; + wxArrayString output; + + // gconf will tell us the path of the application to use as browser + long res = wxExecute( wxT("gconftool-2 --get /desktop/gnome/applications/browser/exec"), + output, errors, wxEXEC_NODISABLE ); + if (res >= 0 && errors.GetCount() == 0) + { + wxString cmd = output[0]; + cmd << _T(' ') << url; + if (wxExecute(cmd)) + return true; + } + } + else if (desktop == wxT("KDE")) + { + // kfmclient directly opens the given URL + if (wxExecute(wxT("kfmclient openURL ") + url)) + return true; + } +#endif + + bool ok = false; + wxString cmd; + +#if wxUSE_MIMETYPE + wxFileType *ft = wxTheMimeTypesManager->GetFileTypeFromExtension(_T("html")); + if ( ft ) + { + wxString mt; + ft->GetMimeType(&mt); + + ok = ft->GetOpenCommand(&cmd, wxFileType::MessageParameters(url)); + delete ft; + } +#endif // wxUSE_MIMETYPE + + if ( !ok || cmd.empty() ) + { + // fallback to checking for the BROWSER environment variable + cmd = wxGetenv(wxT("BROWSER")); + if ( !cmd.empty() ) + cmd << _T(' ') << url; + } + + ok = ( !cmd.empty() && wxExecute(cmd) ); + if (ok) + return ok; + + // no file type for HTML extension + wxLogError(_T("No default application configured for HTML files.")); + +#endif // !wxUSE_MIMETYPE && !__WXMSW__ + return false; +} + +bool wxLaunchDefaultBrowser(const wxString& urlOrig, int flags) +{ + // set the scheme of url to http if it does not have one + // RR: This doesn't work if the url is just a local path + wxString url(urlOrig); + wxURI uri(url); + if ( !uri.HasScheme() ) + { + if (wxFileExists(urlOrig)) + url.Prepend( wxT("file://") ); + else + url.Prepend(wxT("http://")); + } + + if(s_launchBrowserImpl(url, flags)) + return true; + + wxLogSysError(_T("Failed to open URL \"%s\" in default browser."), + url.c_str()); + + return false; +} + +// ---------------------------------------------------------------------------- +// wxApp::Yield() wrappers for backwards compatibility +// ---------------------------------------------------------------------------- + +bool wxYield() +{ + return wxTheApp && wxTheApp->Yield(); +} + +bool wxYieldIfNeeded() +{ + return wxTheApp && wxTheApp->Yield(true); +} + +#endif // wxUSE_BASE + +// ============================================================================ +// GUI-only functions from now on +// ============================================================================ + +#if wxUSE_GUI + +// Id generation +static long wxCurrentId = 100; + +long wxNewId() +{ + // skip the part of IDs space that contains hard-coded values: + if (wxCurrentId == wxID_LOWEST) + wxCurrentId = wxID_HIGHEST + 1; + + return wxCurrentId++; +} + +long +wxGetCurrentId(void) { return wxCurrentId; } + +void +wxRegisterId (long id) +{ + if (id >= wxCurrentId) + wxCurrentId = id + 1; +} + +// ---------------------------------------------------------------------------- +// Menu accelerators related functions +// ---------------------------------------------------------------------------- + +wxChar *wxStripMenuCodes(const wxChar *in, wxChar *out) +{ +#if wxUSE_MENUS + wxString s = wxMenuItem::GetLabelFromText(in); +#else + wxString str(in); + wxString s = wxStripMenuCodes(str); +#endif // wxUSE_MENUS + if ( out ) + { + // go smash their buffer if it's not big enough - I love char * params + memcpy(out, s.c_str(), s.length() * sizeof(wxChar)); + } + else + { + // MYcopystring - for easier search... + out = new wxChar[s.length() + 1]; + wxStrcpy(out, s.c_str()); + } + + return out; +} + +wxString wxStripMenuCodes(const wxString& in, int flags) +{ + wxASSERT_MSG( flags, _T("this is useless to call without any flags") ); + + wxString out; + + size_t len = in.length(); + out.reserve(len); + + for ( size_t n = 0; n < len; n++ ) + { + wxChar ch = in[n]; + if ( (flags & wxStrip_Mnemonics) && ch == _T('&') ) + { + // skip it, it is used to introduce the accel char (or to quote + // itself in which case it should still be skipped): note that it + // can't be the last character of the string + if ( ++n == len ) + { + wxLogDebug(_T("Invalid menu string '%s'"), in.c_str()); + } + else + { + // use the next char instead + ch = in[n]; + } + } + else if ( (flags & wxStrip_Accel) && ch == _T('\t') ) + { + // everything after TAB is accel string, exit the loop + break; + } + + out += ch; + } + + return out; +} + +// ---------------------------------------------------------------------------- +// Window search functions +// ---------------------------------------------------------------------------- + +/* + * If parent is non-NULL, look through children for a label or title + * matching the specified string. If NULL, look through all top-level windows. + * + */ + +wxWindow * +wxFindWindowByLabel (const wxString& title, wxWindow * parent) +{ + return wxWindow::FindWindowByLabel( title, parent ); +} + + +/* + * If parent is non-NULL, look through children for a name + * matching the specified string. If NULL, look through all top-level windows. + * + */ + +wxWindow * +wxFindWindowByName (const wxString& name, wxWindow * parent) +{ + return wxWindow::FindWindowByName( name, parent ); +} + +// Returns menu item id or wxNOT_FOUND if none. +int +wxFindMenuItemId (wxFrame * frame, const wxString& menuString, const wxString& itemString) +{ +#if wxUSE_MENUS + wxMenuBar *menuBar = frame->GetMenuBar (); + if ( menuBar ) + return menuBar->FindMenuItem (menuString, itemString); +#endif // wxUSE_MENUS + + return wxNOT_FOUND; +} + +// Try to find the deepest child that contains 'pt'. +// We go backwards, to try to allow for controls that are spacially +// within other controls, but are still siblings (e.g. buttons within +// static boxes). Static boxes are likely to be created _before_ controls +// that sit inside them. +wxWindow* wxFindWindowAtPoint(wxWindow* win, const wxPoint& pt) +{ + if (!win->IsShown()) + return NULL; + + // Hack for wxNotebook case: at least in wxGTK, all pages + // claim to be shown, so we must only deal with the selected one. +#if wxUSE_NOTEBOOK + if (win->IsKindOf(CLASSINFO(wxNotebook))) + { + wxNotebook* nb = (wxNotebook*) win; + int sel = nb->GetSelection(); + if (sel >= 0) + { + wxWindow* child = nb->GetPage(sel); + wxWindow* foundWin = wxFindWindowAtPoint(child, pt); + if (foundWin) + return foundWin; + } + } +#endif + + wxWindowList::compatibility_iterator node = win->GetChildren().GetLast(); + while (node) + { + wxWindow* child = node->GetData(); + wxWindow* foundWin = wxFindWindowAtPoint(child, pt); + if (foundWin) + return foundWin; + node = node->GetPrevious(); + } + + wxPoint pos = win->GetPosition(); + wxSize sz = win->GetSize(); + if ( !win->IsTopLevel() && win->GetParent() ) + { + pos = win->GetParent()->ClientToScreen(pos); + } + + wxRect rect(pos, sz); + if (rect.Contains(pt)) + return win; + + return NULL; +} + +wxWindow* wxGenericFindWindowAtPoint(const wxPoint& pt) +{ + // Go backwards through the list since windows + // on top are likely to have been appended most + // recently. + wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetLast(); + while (node) + { + wxWindow* win = node->GetData(); + wxWindow* found = wxFindWindowAtPoint(win, pt); + if (found) + return found; + node = node->GetPrevious(); + } + return NULL; +} + +// ---------------------------------------------------------------------------- +// GUI helpers +// ---------------------------------------------------------------------------- + +/* + * N.B. these convenience functions must be separate from msgdlgg.cpp, textdlgg.cpp + * since otherwise the generic code may be pulled in unnecessarily. + */ + +#if wxUSE_MSGDLG + +int wxMessageBox(const wxString& message, const wxString& caption, long style, + wxWindow *parent, int WXUNUSED(x), int WXUNUSED(y) ) +{ + long decorated_style = style; + + if ( ( style & ( wxICON_EXCLAMATION | wxICON_HAND | wxICON_INFORMATION | wxICON_QUESTION ) ) == 0 ) + { + decorated_style |= ( style & wxYES ) ? wxICON_QUESTION : wxICON_INFORMATION ; + } + + wxMessageDialog dialog(parent, message, caption, decorated_style); + + int ans = dialog.ShowModal(); + switch ( ans ) + { + case wxID_OK: + return wxOK; + case wxID_YES: + return wxYES; + case wxID_NO: + return wxNO; + case wxID_CANCEL: + return wxCANCEL; + } + + wxFAIL_MSG( _T("unexpected return code from wxMessageDialog") ); + + return wxCANCEL; +} + +#endif // wxUSE_MSGDLG + +#if wxUSE_TEXTDLG + +wxString wxGetTextFromUser(const wxString& message, const wxString& caption, + const wxString& defaultValue, wxWindow *parent, + wxCoord x, wxCoord y, bool centre ) +{ + wxString str; + long style = wxTextEntryDialogStyle; + + if (centre) + style |= wxCENTRE; + else + style &= ~wxCENTRE; + + wxTextEntryDialog dialog(parent, message, caption, defaultValue, style, wxPoint(x, y)); + + if (dialog.ShowModal() == wxID_OK) + { + str = dialog.GetValue(); + } + + return str; +} + +wxString wxGetPasswordFromUser(const wxString& message, + const wxString& caption, + const wxString& defaultValue, + wxWindow *parent, + wxCoord x, wxCoord y, bool centre ) +{ + wxString str; + long style = wxTextEntryDialogStyle; + + if (centre) + style |= wxCENTRE; + else + style &= ~wxCENTRE; + + wxPasswordEntryDialog dialog(parent, message, caption, defaultValue, + style, wxPoint(x, y)); + if ( dialog.ShowModal() == wxID_OK ) + { + str = dialog.GetValue(); + } + + return str; +} + +#endif // wxUSE_TEXTDLG + +#if wxUSE_COLOURDLG + +wxColour wxGetColourFromUser(wxWindow *parent, const wxColour& colInit, const wxString& caption) +{ + static wxColourData data; + data.SetChooseFull(true); + if ( colInit.Ok() ) + { + data.SetColour((wxColour &)colInit); // const_cast + } + + wxColour colRet; + wxColourDialog dialog(parent, &data); + if (!caption.empty()) + dialog.SetTitle(caption); + if ( dialog.ShowModal() == wxID_OK ) + { + colRet = dialog.GetColourData().GetColour(); + } + //else: leave it invalid + + return colRet; +} + +#endif // wxUSE_COLOURDLG + +#if wxUSE_FONTDLG + +wxFont wxGetFontFromUser(wxWindow *parent, const wxFont& fontInit, const wxString& caption) +{ + wxFontData data; + if ( fontInit.Ok() ) + { + data.SetInitialFont(fontInit); + } + + wxFont fontRet; + wxFontDialog dialog(parent, data); + if (!caption.empty()) + dialog.SetTitle(caption); + if ( dialog.ShowModal() == wxID_OK ) + { + fontRet = dialog.GetFontData().GetChosenFont(); + } + //else: leave it invalid + + return fontRet; +} + +#endif // wxUSE_FONTDLG + +// ---------------------------------------------------------------------------- +// wxSafeYield and supporting functions +// ---------------------------------------------------------------------------- + +void wxEnableTopLevelWindows(bool enable) +{ + wxWindowList::compatibility_iterator node; + for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() ) + node->GetData()->Enable(enable); +} + +wxWindowDisabler::wxWindowDisabler(wxWindow *winToSkip) +{ + // remember the top level windows which were already disabled, so that we + // don't reenable them later + m_winDisabled = NULL; + + wxWindowList::compatibility_iterator node; + for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() ) + { + wxWindow *winTop = node->GetData(); + if ( winTop == winToSkip ) + continue; + + // we don't need to disable the hidden or already disabled windows + if ( winTop->IsEnabled() && winTop->IsShown() ) + { + winTop->Disable(); + } + else + { + if ( !m_winDisabled ) + { + m_winDisabled = new wxWindowList; + } + + m_winDisabled->Append(winTop); + } + } +} + +wxWindowDisabler::~wxWindowDisabler() +{ + wxWindowList::compatibility_iterator node; + for ( node = wxTopLevelWindows.GetFirst(); node; node = node->GetNext() ) + { + wxWindow *winTop = node->GetData(); + if ( !m_winDisabled || !m_winDisabled->Find(winTop) ) + { + winTop->Enable(); + } + //else: had been already disabled, don't reenable + } + + delete m_winDisabled; +} + +// Yield to other apps/messages and disable user input to all windows except +// the given one +bool wxSafeYield(wxWindow *win, bool onlyIfNeeded) +{ + wxWindowDisabler wd(win); + + bool rc; + if (onlyIfNeeded) + rc = wxYieldIfNeeded(); + else + rc = wxYield(); + + return rc; +} + +// Don't synthesize KeyUp events holding down a key and producing KeyDown +// events with autorepeat. On by default and always on in wxMSW. wxGTK version +// in utilsgtk.cpp. +#ifndef __WXGTK__ +bool wxSetDetectableAutoRepeat( bool WXUNUSED(flag) ) +{ + return true; // detectable auto-repeat is the only mode MSW supports +} +#endif // !wxGTK + +#endif // wxUSE_GUI diff --git a/Source/3rd Party/wx/src/common/valgen.cpp b/Source/3rd Party/wx/src/common/valgen.cpp index 9b206483a..b010537ce 100644 --- a/Source/3rd Party/wx/src/common/valgen.cpp +++ b/Source/3rd Party/wx/src/common/valgen.cpp @@ -1,591 +1,591 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/valgen.cpp -// Purpose: wxGenericValidator class -// Author: Kevin Smith -// Modified by: -// Created: Jan 22 1999 -// RCS-ID: $Id: valgen.cpp 39463 2006-05-29 21:26:35Z ABX $ -// Copyright: (c) 1999 Kevin Smith -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_VALIDATORS - -#ifndef WX_PRECOMP - #include "wx/dynarray.h" - #include "wx/utils.h" - #include "wx/intl.h" - #include "wx/choice.h" - #include "wx/combobox.h" - #include "wx/radiobox.h" - #include "wx/radiobut.h" - #include "wx/checkbox.h" - #include "wx/scrolbar.h" - #include "wx/gauge.h" - #include "wx/stattext.h" - #include "wx/textctrl.h" - #include "wx/button.h" - #include "wx/listbox.h" - #include "wx/slider.h" - #include "wx/checklst.h" -#endif - -#include "wx/spinctrl.h" - -#if wxUSE_SPINBTN - #include "wx/spinbutt.h" -#endif -#if wxUSE_TOGGLEBTN - #include "wx/tglbtn.h" -#endif - -#include "wx/valgen.h" - -IMPLEMENT_CLASS(wxGenericValidator, wxValidator) - -wxGenericValidator::wxGenericValidator(bool *val) -{ - Initialize(); - m_pBool = val; -} - -wxGenericValidator::wxGenericValidator(int *val) -{ - Initialize(); - m_pInt = val; -} - -wxGenericValidator::wxGenericValidator(wxString *val) -{ - Initialize(); - m_pString = val; -} - -wxGenericValidator::wxGenericValidator(wxArrayInt *val) -{ - Initialize(); - m_pArrayInt = val; -} - -wxGenericValidator::wxGenericValidator(const wxGenericValidator& val) - : wxValidator() -{ - Copy(val); -} - -bool wxGenericValidator::Copy(const wxGenericValidator& val) -{ - wxValidator::Copy(val); - - m_pBool = val.m_pBool; - m_pInt = val.m_pInt; - m_pString = val.m_pString; - m_pArrayInt = val.m_pArrayInt; - - return true; -} - -// Called to transfer data to the window -bool wxGenericValidator::TransferToWindow(void) -{ - if ( !m_validatorWindow ) - return false; - - // bool controls -#if wxUSE_CHECKBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckBox)) ) - { - wxCheckBox* pControl = (wxCheckBox*) m_validatorWindow; - if (m_pBool) - { - pControl->SetValue(*m_pBool); - return true; - } - } else -#endif -#if wxUSE_RADIOBTN - if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioButton)) ) - { - wxRadioButton* pControl = (wxRadioButton*) m_validatorWindow; - if (m_pBool) - { - pControl->SetValue(*m_pBool) ; - return true; - } - } else -#endif -#if wxUSE_TOGGLEBTN - if (m_validatorWindow->IsKindOf(CLASSINFO(wxToggleButton)) ) - { - wxToggleButton * pControl = (wxToggleButton *) m_validatorWindow; - if (m_pBool) - { - pControl->SetValue(*m_pBool); - return true; - } - } else -#endif - - // int controls -#if wxUSE_GAUGE - if (m_validatorWindow->IsKindOf(CLASSINFO(wxGauge)) ) - { - wxGauge* pControl = (wxGauge*) m_validatorWindow; - if (m_pInt) - { - pControl->SetValue(*m_pInt); - return true; - } - } else -#endif -#if wxUSE_RADIOBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioBox)) ) - { - wxRadioBox* pControl = (wxRadioBox*) m_validatorWindow; - if (m_pInt) - { - pControl->SetSelection(*m_pInt) ; - return true; - } - } else -#endif -#if wxUSE_SCROLLBAR - if (m_validatorWindow->IsKindOf(CLASSINFO(wxScrollBar)) ) - { - wxScrollBar* pControl = (wxScrollBar*) m_validatorWindow; - if (m_pInt) - { - pControl->SetThumbPosition(*m_pInt) ; - return true; - } - } else -#endif -#if wxUSE_SPINCTRL && !defined(__WXMOTIF__) - if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinCtrl)) ) - { - wxSpinCtrl* pControl = (wxSpinCtrl*) m_validatorWindow; - if (m_pInt) - { - pControl->SetValue(*m_pInt); - return true; - } - } else -#endif -#if wxUSE_SPINBTN - if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinButton)) ) - { - wxSpinButton* pControl = (wxSpinButton*) m_validatorWindow; - if (m_pInt) - { - pControl->SetValue(*m_pInt) ; - return true; - } - } else -#endif -#if wxUSE_SLIDER - if (m_validatorWindow->IsKindOf(CLASSINFO(wxSlider)) ) - { - wxSlider* pControl = (wxSlider*) m_validatorWindow; - if (m_pInt) - { - pControl->SetValue(*m_pInt) ; - return true; - } - } else -#endif - - // string controls -#if wxUSE_BUTTON - if (m_validatorWindow->IsKindOf(CLASSINFO(wxButton)) ) - { - wxButton* pControl = (wxButton*) m_validatorWindow; - if (m_pString) - { - pControl->SetLabel(*m_pString) ; - return true; - } - } else -#endif -#if wxUSE_COMBOBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxComboBox)) ) - { - wxComboBox* pControl = (wxComboBox*) m_validatorWindow; - if (m_pInt) - { - pControl->SetSelection(*m_pInt) ; - return true; - } - else if (m_pString) - { - if (pControl->FindString(* m_pString) != wxNOT_FOUND) - { - pControl->SetStringSelection(* m_pString); - } - if ((m_validatorWindow->GetWindowStyle() & wxCB_READONLY) == 0) - { - pControl->SetValue(* m_pString); - } - return true; - } - } else -#endif -#if wxUSE_CHOICE - if (m_validatorWindow->IsKindOf(CLASSINFO(wxChoice)) ) - { - wxChoice* pControl = (wxChoice*) m_validatorWindow; - if (m_pInt) - { - pControl->SetSelection(*m_pInt) ; - return true; - } - else if (m_pString) - { - if (pControl->FindString(* m_pString) != wxNOT_FOUND) - { - pControl->SetStringSelection(* m_pString); - } - return true; - } - } else -#endif -#if wxUSE_STATTEXT - if (m_validatorWindow->IsKindOf(CLASSINFO(wxStaticText)) ) - { - wxStaticText* pControl = (wxStaticText*) m_validatorWindow; - if (m_pString) - { - pControl->SetLabel(*m_pString) ; - return true; - } - } else -#endif -#if wxUSE_TEXTCTRL - if (m_validatorWindow->IsKindOf(CLASSINFO(wxTextCtrl)) ) - { - wxTextCtrl* pControl = (wxTextCtrl*) m_validatorWindow; - if (m_pString) - { - pControl->SetValue(*m_pString) ; - return true; - } - else if (m_pInt) - { - wxString str; - str.Printf(wxT("%d"), *m_pInt); - pControl->SetValue(str); - return true; - } - } else -#endif - - // array controls -#if wxUSE_CHECKLISTBOX - // NOTE: wxCheckListBox is a wxListBox, so wxCheckListBox MUST come first: - if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckListBox)) ) - { - wxCheckListBox* pControl = (wxCheckListBox*) m_validatorWindow; - if (m_pArrayInt) - { - // clear all selections - size_t i, - count = pControl->GetCount(); - for ( i = 0 ; i < count; i++ ) - pControl->Check(i, false); - - // select each item in our array - count = m_pArrayInt->GetCount(); - for ( i = 0 ; i < count; i++ ) - pControl->Check(m_pArrayInt->Item(i)); - - return true; - } - else - return false; - } else -#endif -#if wxUSE_LISTBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxListBox)) ) - { - wxListBox* pControl = (wxListBox*) m_validatorWindow; - if (m_pArrayInt) - { - // clear all selections - size_t i, - count = pControl->GetCount(); - for ( i = 0 ; i < count; i++ ) - pControl->Deselect(i); - - // select each item in our array - count = m_pArrayInt->GetCount(); - for ( i = 0 ; i < count; i++ ) - pControl->SetSelection(m_pArrayInt->Item(i)); - - return true; - } - } else -#endif - ; // to match the last 'else' above - - // unrecognized control, or bad pointer - return false; -} - -// Called to transfer data from the window -bool wxGenericValidator::TransferFromWindow(void) -{ - if ( !m_validatorWindow ) - return false; - - // BOOL CONTROLS ************************************** -#if wxUSE_CHECKBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckBox)) ) - { - wxCheckBox* pControl = (wxCheckBox*) m_validatorWindow; - if (m_pBool) - { - *m_pBool = pControl->GetValue() ; - return true; - } - } else -#endif -#if wxUSE_RADIOBTN - if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioButton)) ) - { - wxRadioButton* pControl = (wxRadioButton*) m_validatorWindow; - if (m_pBool) - { - *m_pBool = pControl->GetValue() ; - return true; - } - } else -#endif -#if wxUSE_TOGGLEBTN - if (m_validatorWindow->IsKindOf(CLASSINFO(wxToggleButton)) ) - { - wxToggleButton *pControl = (wxToggleButton *) m_validatorWindow; - if (m_pBool) - { - *m_pBool = pControl->GetValue() ; - return true; - } - } else -#endif - - // INT CONTROLS *************************************** -#if wxUSE_GAUGE - if (m_validatorWindow->IsKindOf(CLASSINFO(wxGauge)) ) - { - wxGauge* pControl = (wxGauge*) m_validatorWindow; - if (m_pInt) - { - *m_pInt = pControl->GetValue() ; - return true; - } - } else -#endif -#if wxUSE_RADIOBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioBox)) ) - { - wxRadioBox* pControl = (wxRadioBox*) m_validatorWindow; - if (m_pInt) - { - *m_pInt = pControl->GetSelection() ; - return true; - } - } else -#endif -#if wxUSE_SCROLLBAR - if (m_validatorWindow->IsKindOf(CLASSINFO(wxScrollBar)) ) - { - wxScrollBar* pControl = (wxScrollBar*) m_validatorWindow; - if (m_pInt) - { - *m_pInt = pControl->GetThumbPosition() ; - return true; - } - } else -#endif -#if wxUSE_SPINCTRL && !defined(__WXMOTIF__) - if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinCtrl)) ) - { - wxSpinCtrl* pControl = (wxSpinCtrl*) m_validatorWindow; - if (m_pInt) - { - *m_pInt=pControl->GetValue(); - return true; - } - } else -#endif -#if wxUSE_SPINBTN - if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinButton)) ) - { - wxSpinButton* pControl = (wxSpinButton*) m_validatorWindow; - if (m_pInt) - { - *m_pInt = pControl->GetValue() ; - return true; - } - } else -#endif -#if wxUSE_SLIDER - if (m_validatorWindow->IsKindOf(CLASSINFO(wxSlider)) ) - { - wxSlider* pControl = (wxSlider*) m_validatorWindow; - if (m_pInt) - { - *m_pInt = pControl->GetValue() ; - return true; - } - } else -#endif - - // STRING CONTROLS ************************************ -#if wxUSE_BUTTON - if (m_validatorWindow->IsKindOf(CLASSINFO(wxButton)) ) - { - wxButton* pControl = (wxButton*) m_validatorWindow; - if (m_pString) - { - *m_pString = pControl->GetLabel() ; - return true; - } - } else -#endif -#if wxUSE_COMBOBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxComboBox)) ) - { - wxComboBox* pControl = (wxComboBox*) m_validatorWindow; - if (m_pInt) - { - *m_pInt = pControl->GetSelection() ; - return true; - } - else if (m_pString) - { - if (m_validatorWindow->GetWindowStyle() & wxCB_READONLY) - *m_pString = pControl->GetStringSelection(); - else - *m_pString = pControl->GetValue(); - return true; - } - } else -#endif -#if wxUSE_CHOICE - if (m_validatorWindow->IsKindOf(CLASSINFO(wxChoice)) ) - { - wxChoice* pControl = (wxChoice*) m_validatorWindow; - if (m_pInt) - { - *m_pInt = pControl->GetSelection() ; - return true; - } - else if (m_pString) - { - *m_pString = pControl->GetStringSelection(); - return true; - } - } else -#endif -#if wxUSE_STATTEXT - if (m_validatorWindow->IsKindOf(CLASSINFO(wxStaticText)) ) - { - wxStaticText* pControl = (wxStaticText*) m_validatorWindow; - if (m_pString) - { - *m_pString = pControl->GetLabel() ; - return true; - } - } else -#endif -#if wxUSE_TEXTCTRL - if (m_validatorWindow->IsKindOf(CLASSINFO(wxTextCtrl)) ) - { - wxTextCtrl* pControl = (wxTextCtrl*) m_validatorWindow; - if (m_pString) - { - *m_pString = pControl->GetValue() ; - return true; - } - else if (m_pInt) - { - *m_pInt = wxAtoi(pControl->GetValue()); - return true; - } - } else -#endif - - // ARRAY CONTROLS ************************************* -#if wxUSE_CHECKLISTBOX - // NOTE: wxCheckListBox isa wxListBox, so wxCheckListBox MUST come first: - if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckListBox)) ) - { - wxCheckListBox* pControl = (wxCheckListBox*) m_validatorWindow; - if (m_pArrayInt) - { - // clear our array - m_pArrayInt->Clear(); - - // add each selected item to our array - size_t i, - count = pControl->GetCount(); - for ( i = 0; i < count; i++ ) - { - if (pControl->IsChecked(i)) - m_pArrayInt->Add(i); - } - - return true; - } - else - return false; - } else -#endif -#if wxUSE_LISTBOX - if (m_validatorWindow->IsKindOf(CLASSINFO(wxListBox)) ) - { - wxListBox* pControl = (wxListBox*) m_validatorWindow; - if (m_pArrayInt) - { - // clear our array - m_pArrayInt->Clear(); - - // add each selected item to our array - size_t i, - count = pControl->GetCount(); - for ( i = 0; i < count; i++ ) - { - if (pControl->IsSelected(i)) - m_pArrayInt->Add(i); - } - - return true; - } - } else -#endif - - // unrecognized control, or bad pointer - return false; - - return false; -} - -/* - Called by constructors to initialize ALL data members -*/ -void wxGenericValidator::Initialize() -{ - m_pBool = 0; - m_pInt = 0; - m_pString = 0; - m_pArrayInt = 0; -} - -#endif - // wxUSE_VALIDATORS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/valgen.cpp +// Purpose: wxGenericValidator class +// Author: Kevin Smith +// Modified by: +// Created: Jan 22 1999 +// RCS-ID: $Id: valgen.cpp 39463 2006-05-29 21:26:35Z ABX $ +// Copyright: (c) 1999 Kevin Smith +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_VALIDATORS + +#ifndef WX_PRECOMP + #include "wx/dynarray.h" + #include "wx/utils.h" + #include "wx/intl.h" + #include "wx/choice.h" + #include "wx/combobox.h" + #include "wx/radiobox.h" + #include "wx/radiobut.h" + #include "wx/checkbox.h" + #include "wx/scrolbar.h" + #include "wx/gauge.h" + #include "wx/stattext.h" + #include "wx/textctrl.h" + #include "wx/button.h" + #include "wx/listbox.h" + #include "wx/slider.h" + #include "wx/checklst.h" +#endif + +#include "wx/spinctrl.h" + +#if wxUSE_SPINBTN + #include "wx/spinbutt.h" +#endif +#if wxUSE_TOGGLEBTN + #include "wx/tglbtn.h" +#endif + +#include "wx/valgen.h" + +IMPLEMENT_CLASS(wxGenericValidator, wxValidator) + +wxGenericValidator::wxGenericValidator(bool *val) +{ + Initialize(); + m_pBool = val; +} + +wxGenericValidator::wxGenericValidator(int *val) +{ + Initialize(); + m_pInt = val; +} + +wxGenericValidator::wxGenericValidator(wxString *val) +{ + Initialize(); + m_pString = val; +} + +wxGenericValidator::wxGenericValidator(wxArrayInt *val) +{ + Initialize(); + m_pArrayInt = val; +} + +wxGenericValidator::wxGenericValidator(const wxGenericValidator& val) + : wxValidator() +{ + Copy(val); +} + +bool wxGenericValidator::Copy(const wxGenericValidator& val) +{ + wxValidator::Copy(val); + + m_pBool = val.m_pBool; + m_pInt = val.m_pInt; + m_pString = val.m_pString; + m_pArrayInt = val.m_pArrayInt; + + return true; +} + +// Called to transfer data to the window +bool wxGenericValidator::TransferToWindow(void) +{ + if ( !m_validatorWindow ) + return false; + + // bool controls +#if wxUSE_CHECKBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckBox)) ) + { + wxCheckBox* pControl = (wxCheckBox*) m_validatorWindow; + if (m_pBool) + { + pControl->SetValue(*m_pBool); + return true; + } + } else +#endif +#if wxUSE_RADIOBTN + if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioButton)) ) + { + wxRadioButton* pControl = (wxRadioButton*) m_validatorWindow; + if (m_pBool) + { + pControl->SetValue(*m_pBool) ; + return true; + } + } else +#endif +#if wxUSE_TOGGLEBTN + if (m_validatorWindow->IsKindOf(CLASSINFO(wxToggleButton)) ) + { + wxToggleButton * pControl = (wxToggleButton *) m_validatorWindow; + if (m_pBool) + { + pControl->SetValue(*m_pBool); + return true; + } + } else +#endif + + // int controls +#if wxUSE_GAUGE + if (m_validatorWindow->IsKindOf(CLASSINFO(wxGauge)) ) + { + wxGauge* pControl = (wxGauge*) m_validatorWindow; + if (m_pInt) + { + pControl->SetValue(*m_pInt); + return true; + } + } else +#endif +#if wxUSE_RADIOBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioBox)) ) + { + wxRadioBox* pControl = (wxRadioBox*) m_validatorWindow; + if (m_pInt) + { + pControl->SetSelection(*m_pInt) ; + return true; + } + } else +#endif +#if wxUSE_SCROLLBAR + if (m_validatorWindow->IsKindOf(CLASSINFO(wxScrollBar)) ) + { + wxScrollBar* pControl = (wxScrollBar*) m_validatorWindow; + if (m_pInt) + { + pControl->SetThumbPosition(*m_pInt) ; + return true; + } + } else +#endif +#if wxUSE_SPINCTRL && !defined(__WXMOTIF__) + if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinCtrl)) ) + { + wxSpinCtrl* pControl = (wxSpinCtrl*) m_validatorWindow; + if (m_pInt) + { + pControl->SetValue(*m_pInt); + return true; + } + } else +#endif +#if wxUSE_SPINBTN + if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinButton)) ) + { + wxSpinButton* pControl = (wxSpinButton*) m_validatorWindow; + if (m_pInt) + { + pControl->SetValue(*m_pInt) ; + return true; + } + } else +#endif +#if wxUSE_SLIDER + if (m_validatorWindow->IsKindOf(CLASSINFO(wxSlider)) ) + { + wxSlider* pControl = (wxSlider*) m_validatorWindow; + if (m_pInt) + { + pControl->SetValue(*m_pInt) ; + return true; + } + } else +#endif + + // string controls +#if wxUSE_BUTTON + if (m_validatorWindow->IsKindOf(CLASSINFO(wxButton)) ) + { + wxButton* pControl = (wxButton*) m_validatorWindow; + if (m_pString) + { + pControl->SetLabel(*m_pString) ; + return true; + } + } else +#endif +#if wxUSE_COMBOBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxComboBox)) ) + { + wxComboBox* pControl = (wxComboBox*) m_validatorWindow; + if (m_pInt) + { + pControl->SetSelection(*m_pInt) ; + return true; + } + else if (m_pString) + { + if (pControl->FindString(* m_pString) != wxNOT_FOUND) + { + pControl->SetStringSelection(* m_pString); + } + if ((m_validatorWindow->GetWindowStyle() & wxCB_READONLY) == 0) + { + pControl->SetValue(* m_pString); + } + return true; + } + } else +#endif +#if wxUSE_CHOICE + if (m_validatorWindow->IsKindOf(CLASSINFO(wxChoice)) ) + { + wxChoice* pControl = (wxChoice*) m_validatorWindow; + if (m_pInt) + { + pControl->SetSelection(*m_pInt) ; + return true; + } + else if (m_pString) + { + if (pControl->FindString(* m_pString) != wxNOT_FOUND) + { + pControl->SetStringSelection(* m_pString); + } + return true; + } + } else +#endif +#if wxUSE_STATTEXT + if (m_validatorWindow->IsKindOf(CLASSINFO(wxStaticText)) ) + { + wxStaticText* pControl = (wxStaticText*) m_validatorWindow; + if (m_pString) + { + pControl->SetLabel(*m_pString) ; + return true; + } + } else +#endif +#if wxUSE_TEXTCTRL + if (m_validatorWindow->IsKindOf(CLASSINFO(wxTextCtrl)) ) + { + wxTextCtrl* pControl = (wxTextCtrl*) m_validatorWindow; + if (m_pString) + { + pControl->SetValue(*m_pString) ; + return true; + } + else if (m_pInt) + { + wxString str; + str.Printf(wxT("%d"), *m_pInt); + pControl->SetValue(str); + return true; + } + } else +#endif + + // array controls +#if wxUSE_CHECKLISTBOX + // NOTE: wxCheckListBox is a wxListBox, so wxCheckListBox MUST come first: + if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckListBox)) ) + { + wxCheckListBox* pControl = (wxCheckListBox*) m_validatorWindow; + if (m_pArrayInt) + { + // clear all selections + size_t i, + count = pControl->GetCount(); + for ( i = 0 ; i < count; i++ ) + pControl->Check(i, false); + + // select each item in our array + count = m_pArrayInt->GetCount(); + for ( i = 0 ; i < count; i++ ) + pControl->Check(m_pArrayInt->Item(i)); + + return true; + } + else + return false; + } else +#endif +#if wxUSE_LISTBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxListBox)) ) + { + wxListBox* pControl = (wxListBox*) m_validatorWindow; + if (m_pArrayInt) + { + // clear all selections + size_t i, + count = pControl->GetCount(); + for ( i = 0 ; i < count; i++ ) + pControl->Deselect(i); + + // select each item in our array + count = m_pArrayInt->GetCount(); + for ( i = 0 ; i < count; i++ ) + pControl->SetSelection(m_pArrayInt->Item(i)); + + return true; + } + } else +#endif + ; // to match the last 'else' above + + // unrecognized control, or bad pointer + return false; +} + +// Called to transfer data from the window +bool wxGenericValidator::TransferFromWindow(void) +{ + if ( !m_validatorWindow ) + return false; + + // BOOL CONTROLS ************************************** +#if wxUSE_CHECKBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckBox)) ) + { + wxCheckBox* pControl = (wxCheckBox*) m_validatorWindow; + if (m_pBool) + { + *m_pBool = pControl->GetValue() ; + return true; + } + } else +#endif +#if wxUSE_RADIOBTN + if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioButton)) ) + { + wxRadioButton* pControl = (wxRadioButton*) m_validatorWindow; + if (m_pBool) + { + *m_pBool = pControl->GetValue() ; + return true; + } + } else +#endif +#if wxUSE_TOGGLEBTN + if (m_validatorWindow->IsKindOf(CLASSINFO(wxToggleButton)) ) + { + wxToggleButton *pControl = (wxToggleButton *) m_validatorWindow; + if (m_pBool) + { + *m_pBool = pControl->GetValue() ; + return true; + } + } else +#endif + + // INT CONTROLS *************************************** +#if wxUSE_GAUGE + if (m_validatorWindow->IsKindOf(CLASSINFO(wxGauge)) ) + { + wxGauge* pControl = (wxGauge*) m_validatorWindow; + if (m_pInt) + { + *m_pInt = pControl->GetValue() ; + return true; + } + } else +#endif +#if wxUSE_RADIOBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxRadioBox)) ) + { + wxRadioBox* pControl = (wxRadioBox*) m_validatorWindow; + if (m_pInt) + { + *m_pInt = pControl->GetSelection() ; + return true; + } + } else +#endif +#if wxUSE_SCROLLBAR + if (m_validatorWindow->IsKindOf(CLASSINFO(wxScrollBar)) ) + { + wxScrollBar* pControl = (wxScrollBar*) m_validatorWindow; + if (m_pInt) + { + *m_pInt = pControl->GetThumbPosition() ; + return true; + } + } else +#endif +#if wxUSE_SPINCTRL && !defined(__WXMOTIF__) + if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinCtrl)) ) + { + wxSpinCtrl* pControl = (wxSpinCtrl*) m_validatorWindow; + if (m_pInt) + { + *m_pInt=pControl->GetValue(); + return true; + } + } else +#endif +#if wxUSE_SPINBTN + if (m_validatorWindow->IsKindOf(CLASSINFO(wxSpinButton)) ) + { + wxSpinButton* pControl = (wxSpinButton*) m_validatorWindow; + if (m_pInt) + { + *m_pInt = pControl->GetValue() ; + return true; + } + } else +#endif +#if wxUSE_SLIDER + if (m_validatorWindow->IsKindOf(CLASSINFO(wxSlider)) ) + { + wxSlider* pControl = (wxSlider*) m_validatorWindow; + if (m_pInt) + { + *m_pInt = pControl->GetValue() ; + return true; + } + } else +#endif + + // STRING CONTROLS ************************************ +#if wxUSE_BUTTON + if (m_validatorWindow->IsKindOf(CLASSINFO(wxButton)) ) + { + wxButton* pControl = (wxButton*) m_validatorWindow; + if (m_pString) + { + *m_pString = pControl->GetLabel() ; + return true; + } + } else +#endif +#if wxUSE_COMBOBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxComboBox)) ) + { + wxComboBox* pControl = (wxComboBox*) m_validatorWindow; + if (m_pInt) + { + *m_pInt = pControl->GetSelection() ; + return true; + } + else if (m_pString) + { + if (m_validatorWindow->GetWindowStyle() & wxCB_READONLY) + *m_pString = pControl->GetStringSelection(); + else + *m_pString = pControl->GetValue(); + return true; + } + } else +#endif +#if wxUSE_CHOICE + if (m_validatorWindow->IsKindOf(CLASSINFO(wxChoice)) ) + { + wxChoice* pControl = (wxChoice*) m_validatorWindow; + if (m_pInt) + { + *m_pInt = pControl->GetSelection() ; + return true; + } + else if (m_pString) + { + *m_pString = pControl->GetStringSelection(); + return true; + } + } else +#endif +#if wxUSE_STATTEXT + if (m_validatorWindow->IsKindOf(CLASSINFO(wxStaticText)) ) + { + wxStaticText* pControl = (wxStaticText*) m_validatorWindow; + if (m_pString) + { + *m_pString = pControl->GetLabel() ; + return true; + } + } else +#endif +#if wxUSE_TEXTCTRL + if (m_validatorWindow->IsKindOf(CLASSINFO(wxTextCtrl)) ) + { + wxTextCtrl* pControl = (wxTextCtrl*) m_validatorWindow; + if (m_pString) + { + *m_pString = pControl->GetValue() ; + return true; + } + else if (m_pInt) + { + *m_pInt = wxAtoi(pControl->GetValue()); + return true; + } + } else +#endif + + // ARRAY CONTROLS ************************************* +#if wxUSE_CHECKLISTBOX + // NOTE: wxCheckListBox isa wxListBox, so wxCheckListBox MUST come first: + if (m_validatorWindow->IsKindOf(CLASSINFO(wxCheckListBox)) ) + { + wxCheckListBox* pControl = (wxCheckListBox*) m_validatorWindow; + if (m_pArrayInt) + { + // clear our array + m_pArrayInt->Clear(); + + // add each selected item to our array + size_t i, + count = pControl->GetCount(); + for ( i = 0; i < count; i++ ) + { + if (pControl->IsChecked(i)) + m_pArrayInt->Add(i); + } + + return true; + } + else + return false; + } else +#endif +#if wxUSE_LISTBOX + if (m_validatorWindow->IsKindOf(CLASSINFO(wxListBox)) ) + { + wxListBox* pControl = (wxListBox*) m_validatorWindow; + if (m_pArrayInt) + { + // clear our array + m_pArrayInt->Clear(); + + // add each selected item to our array + size_t i, + count = pControl->GetCount(); + for ( i = 0; i < count; i++ ) + { + if (pControl->IsSelected(i)) + m_pArrayInt->Add(i); + } + + return true; + } + } else +#endif + + // unrecognized control, or bad pointer + return false; + + return false; +} + +/* + Called by constructors to initialize ALL data members +*/ +void wxGenericValidator::Initialize() +{ + m_pBool = 0; + m_pInt = 0; + m_pString = 0; + m_pArrayInt = 0; +} + +#endif + // wxUSE_VALIDATORS diff --git a/Source/3rd Party/wx/src/common/validate.cpp b/Source/3rd Party/wx/src/common/validate.cpp index d4ba5e61a..e01711bae 100644 --- a/Source/3rd Party/wx/src/common/validate.cpp +++ b/Source/3rd Party/wx/src/common/validate.cpp @@ -1,45 +1,45 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/validate.cpp -// Purpose: wxValidator -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: validate.cpp 39656 2006-06-09 21:21:53Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_VALIDATORS - -#include "wx/validate.h" - -#ifndef WX_PRECOMP - #include "wx/window.h" -#endif - -const wxValidator wxDefaultValidator; - -IMPLEMENT_DYNAMIC_CLASS(wxValidator, wxEvtHandler) - -// VZ: personally, I think true would be more appropriate - these bells are -// _annoying_ -bool wxValidator::ms_isSilent = false; - -wxValidator::wxValidator() -{ - m_validatorWindow = (wxWindow *) NULL; -} - -wxValidator::~wxValidator() -{ -} - -#endif - // wxUSE_VALIDATORS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/validate.cpp +// Purpose: wxValidator +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: validate.cpp 39656 2006-06-09 21:21:53Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_VALIDATORS + +#include "wx/validate.h" + +#ifndef WX_PRECOMP + #include "wx/window.h" +#endif + +const wxValidator wxDefaultValidator; + +IMPLEMENT_DYNAMIC_CLASS(wxValidator, wxEvtHandler) + +// VZ: personally, I think true would be more appropriate - these bells are +// _annoying_ +bool wxValidator::ms_isSilent = false; + +wxValidator::wxValidator() +{ + m_validatorWindow = (wxWindow *) NULL; +} + +wxValidator::~wxValidator() +{ +} + +#endif + // wxUSE_VALIDATORS diff --git a/Source/3rd Party/wx/src/common/valtext.cpp b/Source/3rd Party/wx/src/common/valtext.cpp index e9eba332a..6f3d8b560 100644 --- a/Source/3rd Party/wx/src/common/valtext.cpp +++ b/Source/3rd Party/wx/src/common/valtext.cpp @@ -1,344 +1,344 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/valtext.cpp -// Purpose: wxTextValidator -// Author: Julian Smart -// Modified by: -// Created: 04/01/98 -// RCS-ID: $Id: valtext.cpp 39656 2006-06-09 21:21:53Z ABX $ -// Copyright: (c) Julian Smart -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_VALIDATORS && wxUSE_TEXTCTRL - -#include "wx/valtext.h" - -#ifndef WX_PRECOMP - #include - #include "wx/textctrl.h" - #include "wx/utils.h" - #include "wx/msgdlg.h" - #include "wx/intl.h" -#endif - -#include -#include -#include - -#ifdef __SALFORDC__ - #include -#endif - -IMPLEMENT_DYNAMIC_CLASS(wxTextValidator, wxValidator) - -BEGIN_EVENT_TABLE(wxTextValidator, wxValidator) - EVT_CHAR(wxTextValidator::OnChar) -END_EVENT_TABLE() - -static bool wxIsNumeric(const wxString& val); - -wxTextValidator::wxTextValidator(long style, wxString *val) -{ - m_validatorStyle = style; - m_stringValue = val; -/* - m_refData = new wxVTextRefData; - - M_VTEXTDATA->m_validatorStyle = style; - M_VTEXTDATA->m_stringValue = val; -*/ -} - -wxTextValidator::wxTextValidator(const wxTextValidator& val) - : wxValidator() -{ - Copy(val); -} - -bool wxTextValidator::Copy(const wxTextValidator& val) -{ - wxValidator::Copy(val); - - m_validatorStyle = val.m_validatorStyle; - m_stringValue = val.m_stringValue; - - m_includes = val.m_includes; - m_excludes = val.m_excludes; - - return true; -} - -static bool wxIsAlpha(const wxString& val) -{ - int i; - for ( i = 0; i < (int)val.length(); i++) - { - if (!wxIsalpha(val[i])) - return false; - } - return true; -} - -static bool wxIsAlphaNumeric(const wxString& val) -{ - int i; - for ( i = 0; i < (int)val.length(); i++) - { - if (!wxIsalnum(val[i])) - return false; - } - return true; -} - -// Called when the value in the window must be validated. -// This function can pop up an error message. -bool wxTextValidator::Validate(wxWindow *parent) -{ - if( !CheckValidator() ) - return false; - - wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow; - - // If window is disabled, simply return - if ( !control->IsEnabled() ) - return true; - - wxString val(control->GetValue()); - - bool ok = true; - - // NB: this format string should contian exactly one '%s' - wxString errormsg; - - bool includes = (m_validatorStyle & wxFILTER_INCLUDE_LIST) != 0; - if ( includes || (m_validatorStyle & wxFILTER_EXCLUDE_LIST) ) - { - // if includes, it's only ok to have the members of the list, - // otherwise it's only ok to have non-members - ok = includes == (m_includes.Index(val) != wxNOT_FOUND); - if ( !ok ) - { - errormsg = _("'%s' is invalid"); - } - } - else if ( (m_validatorStyle & wxFILTER_ASCII) && !val.IsAscii() ) - { - ok = false; - - errormsg = _("'%s' should only contain ASCII characters."); - } - else if ( (m_validatorStyle & wxFILTER_ALPHA) && !wxIsAlpha(val) ) - { - ok = false; - - errormsg = _("'%s' should only contain alphabetic characters."); - } - else if ( (m_validatorStyle & wxFILTER_ALPHANUMERIC) && !wxIsAlphaNumeric(val)) - { - ok = false; - - errormsg = _("'%s' should only contain alphabetic or numeric characters."); - } - else if ( (m_validatorStyle & wxFILTER_NUMERIC) && !wxIsNumeric(val)) - { - ok = false; - - errormsg = _("'%s' should be numeric."); - } - else if ( (m_validatorStyle & wxFILTER_INCLUDE_CHAR_LIST) && !IsInCharIncludes(val)) - { - //it's only ok to have the members of the list - errormsg = _("'%s' is invalid"); - ok = false; - } - else if ( (m_validatorStyle & wxFILTER_EXCLUDE_CHAR_LIST) && !IsNotInCharExcludes(val)) - { - // it's only ok to have non-members of the list - errormsg = _("'%s' is invalid"); - ok = false; - } - - if ( !ok ) - { - wxASSERT_MSG( !errormsg.empty(), _T("you forgot to set errormsg") ); - - m_validatorWindow->SetFocus(); - - wxString buf; - buf.Printf(errormsg, val.c_str()); - - wxMessageBox(buf, _("Validation conflict"), - wxOK | wxICON_EXCLAMATION, parent); - } - - return ok; -} - -// Called to transfer data to the window -bool wxTextValidator::TransferToWindow(void) -{ - if( !CheckValidator() ) - return false; - - if ( m_stringValue ) - { - wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow; - control->SetValue(* m_stringValue); - } - - return true; -} - -// Called to transfer data to the window -bool wxTextValidator::TransferFromWindow(void) -{ - if( !CheckValidator() ) - return false; - - if ( m_stringValue ) - { - wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow; - *m_stringValue = control->GetValue(); - } - - return true; -} - -#if WXWIN_COMPATIBILITY_2_4 - -inline void wxCopyStringListToArrayString(wxArrayString& to, const wxStringList& from) -{ - to.Clear(); - - for ( wxStringList::compatibility_iterator pNode = from.GetFirst(); - pNode; - pNode = pNode->GetNext() ) - { - to.Add(pNode->GetData()); - } -} - -inline void wxCopyArrayStringToStringList(wxStringList& to, const wxArrayString& from) -{ - to.Clear(); - - for(size_t i = 0; i < from.GetCount(); ++i) - to.Add(from[i]); -} - -wxStringList& wxTextValidator::GetIncludeList() -{ - wxCopyArrayStringToStringList(m_includeList, m_includes); - return m_includeList; -} - -wxStringList& wxTextValidator::GetExcludeList() -{ - wxCopyArrayStringToStringList(m_excludeList, m_excludes); - return m_excludeList; -} - -void wxTextValidator::SetIncludeList(const wxStringList& list) -{ - wxCopyStringListToArrayString(m_includes, list); -} - -void wxTextValidator::SetExcludeList(const wxStringList& list) -{ - wxCopyStringListToArrayString(m_excludes, list); -} - -bool wxTextValidator::IsInCharIncludeList(const wxString& val) -{ - return IsInCharIncludes(val); -} - -bool wxTextValidator::IsNotInCharExcludeList(const wxString& val) -{ - return IsNotInCharExcludes(val); -} - -#endif //compat 2.4 - - -bool wxTextValidator::IsInCharIncludes(const wxString& val) -{ - size_t i; - for ( i = 0; i < val.length(); i++) - { - if (m_includes.Index((wxString) val[i]) == wxNOT_FOUND) - return false; - } - return true; -} - -bool wxTextValidator::IsNotInCharExcludes(const wxString& val) -{ - size_t i; - for ( i = 0; i < val.length(); i++) - { - if (m_excludes.Index((wxString) val[i]) != wxNOT_FOUND) - return false; - } - return true; -} - -void wxTextValidator::OnChar(wxKeyEvent& event) -{ -/* - if ( !M_VTEXTDATA ) - return; -*/ - - if ( m_validatorWindow ) - { - int keyCode = event.GetKeyCode(); - - // we don't filter special keys and Delete - if ( - !(keyCode < WXK_SPACE || keyCode == WXK_DELETE || keyCode > WXK_START) && - ( - ((m_validatorStyle & wxFILTER_INCLUDE_CHAR_LIST) && !IsInCharIncludes(wxString((wxChar) keyCode, 1))) || - ((m_validatorStyle & wxFILTER_EXCLUDE_CHAR_LIST) && !IsNotInCharExcludes(wxString((wxChar) keyCode, 1))) || - ((m_validatorStyle & wxFILTER_ASCII) && !isascii(keyCode)) || - ((m_validatorStyle & wxFILTER_ALPHA) && !wxIsalpha(keyCode)) || - ((m_validatorStyle & wxFILTER_ALPHANUMERIC) && !wxIsalnum(keyCode)) || - ((m_validatorStyle & wxFILTER_NUMERIC) && !wxIsdigit(keyCode) - && keyCode != wxT('.') && keyCode != wxT(',') && keyCode != wxT('-') && keyCode != wxT('+') && keyCode != wxT('e') && keyCode != wxT('E')) - ) - ) - { - if ( !wxValidator::IsSilent() ) - wxBell(); - - // eat message - return; - } - } - - event.Skip(); -} - -static bool wxIsNumeric(const wxString& val) -{ - int i; - for ( i = 0; i < (int)val.length(); i++) - { - // Allow for "," (French) as well as "." -- in future we should - // use wxSystemSettings or other to do better localisation - if ((!wxIsdigit(val[i])) && (val[i] != wxT('.')) && (val[i] != wxT(',')) && (val[i] != wxT('e')) && (val[i] != wxT('E')) && (val[i] != wxT('+')) && (val[i] != wxT('-'))) - return false; - } - return true; -} - - -#endif - // wxUSE_VALIDATORS && wxUSE_TEXTCTRL +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/valtext.cpp +// Purpose: wxTextValidator +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: valtext.cpp 39656 2006-06-09 21:21:53Z ABX $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_VALIDATORS && wxUSE_TEXTCTRL + +#include "wx/valtext.h" + +#ifndef WX_PRECOMP + #include + #include "wx/textctrl.h" + #include "wx/utils.h" + #include "wx/msgdlg.h" + #include "wx/intl.h" +#endif + +#include +#include +#include + +#ifdef __SALFORDC__ + #include +#endif + +IMPLEMENT_DYNAMIC_CLASS(wxTextValidator, wxValidator) + +BEGIN_EVENT_TABLE(wxTextValidator, wxValidator) + EVT_CHAR(wxTextValidator::OnChar) +END_EVENT_TABLE() + +static bool wxIsNumeric(const wxString& val); + +wxTextValidator::wxTextValidator(long style, wxString *val) +{ + m_validatorStyle = style; + m_stringValue = val; +/* + m_refData = new wxVTextRefData; + + M_VTEXTDATA->m_validatorStyle = style; + M_VTEXTDATA->m_stringValue = val; +*/ +} + +wxTextValidator::wxTextValidator(const wxTextValidator& val) + : wxValidator() +{ + Copy(val); +} + +bool wxTextValidator::Copy(const wxTextValidator& val) +{ + wxValidator::Copy(val); + + m_validatorStyle = val.m_validatorStyle; + m_stringValue = val.m_stringValue; + + m_includes = val.m_includes; + m_excludes = val.m_excludes; + + return true; +} + +static bool wxIsAlpha(const wxString& val) +{ + int i; + for ( i = 0; i < (int)val.length(); i++) + { + if (!wxIsalpha(val[i])) + return false; + } + return true; +} + +static bool wxIsAlphaNumeric(const wxString& val) +{ + int i; + for ( i = 0; i < (int)val.length(); i++) + { + if (!wxIsalnum(val[i])) + return false; + } + return true; +} + +// Called when the value in the window must be validated. +// This function can pop up an error message. +bool wxTextValidator::Validate(wxWindow *parent) +{ + if( !CheckValidator() ) + return false; + + wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow; + + // If window is disabled, simply return + if ( !control->IsEnabled() ) + return true; + + wxString val(control->GetValue()); + + bool ok = true; + + // NB: this format string should contian exactly one '%s' + wxString errormsg; + + bool includes = (m_validatorStyle & wxFILTER_INCLUDE_LIST) != 0; + if ( includes || (m_validatorStyle & wxFILTER_EXCLUDE_LIST) ) + { + // if includes, it's only ok to have the members of the list, + // otherwise it's only ok to have non-members + ok = includes == (m_includes.Index(val) != wxNOT_FOUND); + if ( !ok ) + { + errormsg = _("'%s' is invalid"); + } + } + else if ( (m_validatorStyle & wxFILTER_ASCII) && !val.IsAscii() ) + { + ok = false; + + errormsg = _("'%s' should only contain ASCII characters."); + } + else if ( (m_validatorStyle & wxFILTER_ALPHA) && !wxIsAlpha(val) ) + { + ok = false; + + errormsg = _("'%s' should only contain alphabetic characters."); + } + else if ( (m_validatorStyle & wxFILTER_ALPHANUMERIC) && !wxIsAlphaNumeric(val)) + { + ok = false; + + errormsg = _("'%s' should only contain alphabetic or numeric characters."); + } + else if ( (m_validatorStyle & wxFILTER_NUMERIC) && !wxIsNumeric(val)) + { + ok = false; + + errormsg = _("'%s' should be numeric."); + } + else if ( (m_validatorStyle & wxFILTER_INCLUDE_CHAR_LIST) && !IsInCharIncludes(val)) + { + //it's only ok to have the members of the list + errormsg = _("'%s' is invalid"); + ok = false; + } + else if ( (m_validatorStyle & wxFILTER_EXCLUDE_CHAR_LIST) && !IsNotInCharExcludes(val)) + { + // it's only ok to have non-members of the list + errormsg = _("'%s' is invalid"); + ok = false; + } + + if ( !ok ) + { + wxASSERT_MSG( !errormsg.empty(), _T("you forgot to set errormsg") ); + + m_validatorWindow->SetFocus(); + + wxString buf; + buf.Printf(errormsg, val.c_str()); + + wxMessageBox(buf, _("Validation conflict"), + wxOK | wxICON_EXCLAMATION, parent); + } + + return ok; +} + +// Called to transfer data to the window +bool wxTextValidator::TransferToWindow(void) +{ + if( !CheckValidator() ) + return false; + + if ( m_stringValue ) + { + wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow; + control->SetValue(* m_stringValue); + } + + return true; +} + +// Called to transfer data to the window +bool wxTextValidator::TransferFromWindow(void) +{ + if( !CheckValidator() ) + return false; + + if ( m_stringValue ) + { + wxTextCtrl *control = (wxTextCtrl *) m_validatorWindow; + *m_stringValue = control->GetValue(); + } + + return true; +} + +#if WXWIN_COMPATIBILITY_2_4 + +inline void wxCopyStringListToArrayString(wxArrayString& to, const wxStringList& from) +{ + to.Clear(); + + for ( wxStringList::compatibility_iterator pNode = from.GetFirst(); + pNode; + pNode = pNode->GetNext() ) + { + to.Add(pNode->GetData()); + } +} + +inline void wxCopyArrayStringToStringList(wxStringList& to, const wxArrayString& from) +{ + to.Clear(); + + for(size_t i = 0; i < from.GetCount(); ++i) + to.Add(from[i]); +} + +wxStringList& wxTextValidator::GetIncludeList() +{ + wxCopyArrayStringToStringList(m_includeList, m_includes); + return m_includeList; +} + +wxStringList& wxTextValidator::GetExcludeList() +{ + wxCopyArrayStringToStringList(m_excludeList, m_excludes); + return m_excludeList; +} + +void wxTextValidator::SetIncludeList(const wxStringList& list) +{ + wxCopyStringListToArrayString(m_includes, list); +} + +void wxTextValidator::SetExcludeList(const wxStringList& list) +{ + wxCopyStringListToArrayString(m_excludes, list); +} + +bool wxTextValidator::IsInCharIncludeList(const wxString& val) +{ + return IsInCharIncludes(val); +} + +bool wxTextValidator::IsNotInCharExcludeList(const wxString& val) +{ + return IsNotInCharExcludes(val); +} + +#endif //compat 2.4 + + +bool wxTextValidator::IsInCharIncludes(const wxString& val) +{ + size_t i; + for ( i = 0; i < val.length(); i++) + { + if (m_includes.Index((wxString) val[i]) == wxNOT_FOUND) + return false; + } + return true; +} + +bool wxTextValidator::IsNotInCharExcludes(const wxString& val) +{ + size_t i; + for ( i = 0; i < val.length(); i++) + { + if (m_excludes.Index((wxString) val[i]) != wxNOT_FOUND) + return false; + } + return true; +} + +void wxTextValidator::OnChar(wxKeyEvent& event) +{ +/* + if ( !M_VTEXTDATA ) + return; +*/ + + if ( m_validatorWindow ) + { + int keyCode = event.GetKeyCode(); + + // we don't filter special keys and Delete + if ( + !(keyCode < WXK_SPACE || keyCode == WXK_DELETE || keyCode > WXK_START) && + ( + ((m_validatorStyle & wxFILTER_INCLUDE_CHAR_LIST) && !IsInCharIncludes(wxString((wxChar) keyCode, 1))) || + ((m_validatorStyle & wxFILTER_EXCLUDE_CHAR_LIST) && !IsNotInCharExcludes(wxString((wxChar) keyCode, 1))) || + ((m_validatorStyle & wxFILTER_ASCII) && !isascii(keyCode)) || + ((m_validatorStyle & wxFILTER_ALPHA) && !wxIsalpha(keyCode)) || + ((m_validatorStyle & wxFILTER_ALPHANUMERIC) && !wxIsalnum(keyCode)) || + ((m_validatorStyle & wxFILTER_NUMERIC) && !wxIsdigit(keyCode) + && keyCode != wxT('.') && keyCode != wxT(',') && keyCode != wxT('-') && keyCode != wxT('+') && keyCode != wxT('e') && keyCode != wxT('E')) + ) + ) + { + if ( !wxValidator::IsSilent() ) + wxBell(); + + // eat message + return; + } + } + + event.Skip(); +} + +static bool wxIsNumeric(const wxString& val) +{ + int i; + for ( i = 0; i < (int)val.length(); i++) + { + // Allow for "," (French) as well as "." -- in future we should + // use wxSystemSettings or other to do better localisation + if ((!wxIsdigit(val[i])) && (val[i] != wxT('.')) && (val[i] != wxT(',')) && (val[i] != wxT('e')) && (val[i] != wxT('E')) && (val[i] != wxT('+')) && (val[i] != wxT('-'))) + return false; + } + return true; +} + + +#endif + // wxUSE_VALIDATORS && wxUSE_TEXTCTRL diff --git a/Source/3rd Party/wx/src/common/variant.cpp b/Source/3rd Party/wx/src/common/variant.cpp index a1af4b2d7..eb653c0ff 100644 --- a/Source/3rd Party/wx/src/common/variant.cpp +++ b/Source/3rd Party/wx/src/common/variant.cpp @@ -1,2040 +1,2040 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/variant.cpp -// Purpose: wxVariant class, container for any type -// Author: Julian Smart -// Modified by: -// Created: 10/09/98 -// RCS-ID: $Id: variant.cpp 58054 2009-01-12 17:27:53Z JMS $ -// Copyright: (c) -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx/wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#include "wx/variant.h" - -#if wxUSE_VARIANT - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/math.h" - #if wxUSE_STREAMS - #include "wx/stream.h" - #endif -#endif - -#if wxUSE_STD_IOSTREAM - #if wxUSE_IOSTREAMH - #include - #else - #include - #endif -#endif - -#if defined(__MWERKS__) && __MSL__ >= 0x6000 -namespace std {} -using namespace std ; -#endif - -#if wxUSE_STREAMS - #include "wx/txtstrm.h" -#endif - -#include "wx/string.h" -#include "wx/tokenzr.h" - -IMPLEMENT_ABSTRACT_CLASS(wxVariantData, wxObject) - -wxVariant WXDLLIMPEXP_BASE wxNullVariant; - - -/* - * wxVariant - */ - -IMPLEMENT_DYNAMIC_CLASS(wxVariant, wxObject) - -wxVariant::wxVariant() -{ - m_data = (wxVariantData*) NULL; -} - -bool wxVariant::IsNull() const -{ - return (m_data == (wxVariantData*) NULL); -} - -void wxVariant::MakeNull() -{ - UnRef(); -} - -void wxVariant::Clear() -{ - m_name = wxEmptyString; -} - -wxVariant::wxVariant(const wxVariant& variant) - : wxObject() -{ - m_data = (wxVariantData*) NULL; - - if (!variant.IsNull()) - Ref(variant); - - m_name = variant.m_name; -} - -wxVariant::wxVariant(wxVariantData* data, const wxString& name) // User-defined data -{ - m_data = data; - m_name = name; -} - -wxVariant::~wxVariant() -{ - UnRef(); -} - -// Assignment -void wxVariant::operator= (const wxVariant& variant) -{ - Ref(variant); - m_name = variant.m_name; -} - -// myVariant = new wxStringVariantData("hello") -void wxVariant::operator= (wxVariantData* variantData) -{ - UnRef(); - m_data = variantData; -} - -bool wxVariant::operator== (const wxVariant& variant) const -{ - if (IsNull() || variant.IsNull()) - return (IsNull() == variant.IsNull()); - - return (GetData()->Eq(* variant.GetData())); -} - -bool wxVariant::operator!= (const wxVariant& variant) const -{ - return (!(*this == variant)); -} - - -wxString wxVariant::MakeString() const -{ - if (!IsNull()) - { - wxString str; - if (GetData()->Write(str)) - return str; - } - return wxEmptyString; -} - -void wxVariant::SetData(wxVariantData* data) -{ - UnRef(); - m_data = data; -} - -void wxVariant::Ref(const wxVariant& clone) -{ - // nothing to be done - if (m_data == clone.m_data) - return; - - // delete reference to old data - UnRef(); - - // reference new data - if ( clone.m_data ) - { - m_data = clone.m_data; - m_data->m_count++; - } -} - - -void wxVariant::UnRef() -{ - if ( m_data ) - { - wxASSERT_MSG( m_data->m_count > 0, _T("invalid ref data count") ); - - m_data->DecRef(); - m_data = NULL; - } -} - - -// Returns a string representing the type of the variant, -// e.g. "string", "bool", "list", "double", "long" -wxString wxVariant::GetType() const -{ - if (IsNull()) - return wxString(wxT("null")); - else - return GetData()->GetType(); -} - - -bool wxVariant::IsType(const wxString& type) const -{ - return (GetType() == type); -} - -bool wxVariant::IsValueKindOf(const wxClassInfo* type) const -{ - wxClassInfo* info=GetData()->GetValueClassInfo(); - return info ? info->IsKindOf(type) : false ; -} - - -// ----------------------------------------------------------------- -// wxVariantDataLong -// ----------------------------------------------------------------- - -class WXDLLIMPEXP_BASE wxVariantDataLong: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataLong) -public: - wxVariantDataLong() { m_value = 0; } - wxVariantDataLong(long value) { m_value = value; } - - inline long GetValue() const { return m_value; } - inline void SetValue(long value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; - - virtual bool Read(wxString& str); - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); - virtual bool Write(wxSTD ostream& str) const; -#endif -#if wxUSE_STREAMS - virtual bool Read(wxInputStream& str); - virtual bool Write(wxOutputStream &str) const; -#endif // wxUSE_STREAMS - - virtual wxString GetType() const { return wxT("long"); } - -protected: - long m_value; -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataLong, wxVariantData) - -bool wxVariantDataLong::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("long")), wxT("wxVariantDataLong::Eq: argument mismatch") ); - - wxVariantDataLong& otherData = (wxVariantDataLong&) data; - - return (otherData.m_value == m_value); -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataLong::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDataLong::Write(wxString& str) const -{ - str.Printf(wxT("%ld"), m_value); - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataLong::Read(wxSTD istream& str) -{ - str >> m_value; - return true; -} -#endif - -#if wxUSE_STREAMS -bool wxVariantDataLong::Write(wxOutputStream& str) const -{ - wxTextOutputStream s(str); - - s.Write32((size_t)m_value); - return true; -} - -bool wxVariantDataLong::Read(wxInputStream& str) -{ - wxTextInputStream s(str); - m_value = s.Read32(); - return true; -} -#endif // wxUSE_STREAMS - -bool wxVariantDataLong::Read(wxString& str) -{ - m_value = wxAtol((const wxChar*) str); - return true; -} - -// wxVariant - -wxVariant::wxVariant(long val, const wxString& name) -{ - m_data = new wxVariantDataLong(val); - m_name = name; -} - -wxVariant::wxVariant(int val, const wxString& name) -{ - m_data = new wxVariantDataLong((long)val); - m_name = name; -} - -wxVariant::wxVariant(short val, const wxString& name) -{ - m_data = new wxVariantDataLong((long)val); - m_name = name; -} - -bool wxVariant::operator== (long value) const -{ - long thisValue; - if (!Convert(&thisValue)) - return false; - else - return (value == thisValue); -} - -bool wxVariant::operator!= (long value) const -{ - return (!((*this) == value)); -} - -void wxVariant::operator= (long value) -{ - if (GetType() == wxT("long") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataLong*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataLong(value); - } -} - -long wxVariant::GetLong() const -{ - long value; - if (Convert(& value)) - return value; - else - { - wxFAIL_MSG(wxT("Could not convert to a long")); - return 0; - } -} - -// ----------------------------------------------------------------- -// wxVariantDoubleData -// ----------------------------------------------------------------- - -class WXDLLIMPEXP_BASE wxVariantDoubleData: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDoubleData) -public: - wxVariantDoubleData() { m_value = 0.0; } - wxVariantDoubleData(double value) { m_value = value; } - - inline double GetValue() const { return m_value; } - inline void SetValue(double value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; - virtual bool Read(wxString& str); -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif -#if wxUSE_STREAMS - virtual bool Read(wxInputStream& str); - virtual bool Write(wxOutputStream &str) const; -#endif // wxUSE_STREAMS - virtual wxString GetType() const { return wxT("double"); } - -protected: - double m_value; -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDoubleData, wxVariantData) - -bool wxVariantDoubleData::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("double")), wxT("wxVariantDoubleData::Eq: argument mismatch") ); - - wxVariantDoubleData& otherData = (wxVariantDoubleData&) data; - - return wxIsSameDouble(otherData.m_value, m_value); -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDoubleData::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDoubleData::Write(wxString& str) const -{ - str.Printf(wxT("%.14g"), m_value); - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDoubleData::Read(wxSTD istream& str) -{ - str >> m_value; - return true; -} -#endif - -#if wxUSE_STREAMS -bool wxVariantDoubleData::Write(wxOutputStream& str) const -{ - wxTextOutputStream s(str); - s.WriteDouble((double)m_value); - return true; -} - -bool wxVariantDoubleData::Read(wxInputStream& str) -{ - wxTextInputStream s(str); - m_value = (float)s.ReadDouble(); - return true; -} -#endif // wxUSE_STREAMS - -bool wxVariantDoubleData::Read(wxString& str) -{ - m_value = wxAtof((const wxChar*) str); - return true; -} - -// wxVariant double code - -wxVariant::wxVariant(double val, const wxString& name) -{ - m_data = new wxVariantDoubleData(val); - m_name = name; -} - -bool wxVariant::operator== (double value) const -{ - double thisValue; - if (!Convert(&thisValue)) - return false; - - return wxIsSameDouble(value, thisValue); -} - -bool wxVariant::operator!= (double value) const -{ - return (!((*this) == value)); -} - -void wxVariant::operator= (double value) -{ - if (GetType() == wxT("double") && - m_data->GetRefCount() == 1) - { - ((wxVariantDoubleData*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDoubleData(value); - } -} - -double wxVariant::GetDouble() const -{ - double value; - if (Convert(& value)) - return value; - else - { - wxFAIL_MSG(wxT("Could not convert to a double number")); - return 0.0; - } -} - -// ----------------------------------------------------------------- -// wxVariantBoolData -// ----------------------------------------------------------------- - -#ifdef HAVE_BOOL - -class WXDLLIMPEXP_BASE wxVariantDataBool: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataBool) -public: - wxVariantDataBool() { m_value = 0; } - wxVariantDataBool(bool value) { m_value = value; } - - inline bool GetValue() const { return m_value; } - inline void SetValue(bool value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; - virtual bool Read(wxString& str); -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif -#if wxUSE_STREAMS - virtual bool Read(wxInputStream& str); - virtual bool Write(wxOutputStream& str) const; -#endif // wxUSE_STREAMS - virtual wxString GetType() const { return wxT("bool"); } - -protected: - bool m_value; -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataBool, wxVariantData) - -bool wxVariantDataBool::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("bool")), wxT("wxVariantDataBool::Eq: argument mismatch") ); - - wxVariantDataBool& otherData = (wxVariantDataBool&) data; - - return (otherData.m_value == m_value); -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataBool::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDataBool::Write(wxString& str) const -{ - str.Printf(wxT("%d"), (int) m_value); - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataBool::Read(wxSTD istream& WXUNUSED(str)) -{ - wxFAIL_MSG(wxT("Unimplemented")); -// str >> (long) m_value; - return false; -} -#endif - -#if wxUSE_STREAMS -bool wxVariantDataBool::Write(wxOutputStream& str) const -{ - wxTextOutputStream s(str); - - s.Write8(m_value); - return true; -} - -bool wxVariantDataBool::Read(wxInputStream& str) -{ - wxTextInputStream s(str); - - m_value = s.Read8() != 0; - return true; -} -#endif // wxUSE_STREAMS - -bool wxVariantDataBool::Read(wxString& str) -{ - m_value = (wxAtol((const wxChar*) str) != 0); - return true; -} - -// wxVariant **** - -wxVariant::wxVariant(bool val, const wxString& name) -{ - m_data = new wxVariantDataBool(val); - m_name = name; -} - -bool wxVariant::operator== (bool value) const -{ - bool thisValue; - if (!Convert(&thisValue)) - return false; - else - return (value == thisValue); -} - -bool wxVariant::operator!= (bool value) const -{ - return (!((*this) == value)); -} - -void wxVariant::operator= (bool value) -{ - if (GetType() == wxT("bool") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataBool*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataBool(value); - } -} - -bool wxVariant::GetBool() const -{ - bool value; - if (Convert(& value)) - return value; - else - { - wxFAIL_MSG(wxT("Could not convert to a bool")); - return 0; - } -} - -#endif // HAVE_BOOL - -// ----------------------------------------------------------------- -// wxVariantDataChar -// ----------------------------------------------------------------- - -class WXDLLIMPEXP_BASE wxVariantDataChar: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataChar) -public: - wxVariantDataChar() { m_value = 0; } - wxVariantDataChar(wxChar value) { m_value = value; } - - inline wxChar GetValue() const { return m_value; } - inline void SetValue(wxChar value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Read(wxString& str); - virtual bool Write(wxString& str) const; -#if wxUSE_STREAMS - virtual bool Read(wxInputStream& str); - virtual bool Write(wxOutputStream& str) const; -#endif // wxUSE_STREAMS - virtual wxString GetType() const { return wxT("char"); } - -protected: - wxChar m_value; -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataChar, wxVariantData) - -bool wxVariantDataChar::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("char")), wxT("wxVariantDataChar::Eq: argument mismatch") ); - - wxVariantDataChar& otherData = (wxVariantDataChar&) data; - - return (otherData.m_value == m_value); -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataChar::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDataChar::Write(wxString& str) const -{ - str.Printf(wxT("%c"), m_value); - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataChar::Read(wxSTD istream& WXUNUSED(str)) -{ - wxFAIL_MSG(wxT("Unimplemented")); - - return false; -} -#endif - -#if wxUSE_STREAMS -bool wxVariantDataChar::Write(wxOutputStream& str) const -{ - wxTextOutputStream s(str); - - s << m_value; - - return true; -} - -bool wxVariantDataChar::Read(wxInputStream& str) -{ - wxTextInputStream s(str); - - s >> m_value; - - return true; -} -#endif // wxUSE_STREAMS - -bool wxVariantDataChar::Read(wxString& str) -{ - m_value = str[size_t(0)]; - return true; -} - -wxVariant::wxVariant(wxChar val, const wxString& name) -{ - m_data = new wxVariantDataChar(val); - m_name = name; -} - -bool wxVariant::operator== (wxChar value) const -{ - wxChar thisValue; - if (!Convert(&thisValue)) - return false; - else - return (value == thisValue); -} - -bool wxVariant::operator!= (wxChar value) const -{ - return (!((*this) == value)); -} - -void wxVariant::operator= (wxChar value) -{ - if (GetType() == wxT("char") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataChar*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataChar(value); - } -} - -wxChar wxVariant::GetChar() const -{ - wxChar value; - if (Convert(& value)) - return value; - else - { - wxFAIL_MSG(wxT("Could not convert to a char")); - return 0; - } -} - -// ---------------------------------------------------------------------------- -// wxVariantDataString -// ---------------------------------------------------------------------------- - -class WXDLLIMPEXP_BASE wxVariantDataString: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataString) -public: - wxVariantDataString() { } - wxVariantDataString(const wxString& value) { m_value = value; } - - inline wxString GetValue() const { return m_value; } - inline void SetValue(const wxString& value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Read(wxString& str); - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& WXUNUSED(str)) { return false; } -#endif -#if wxUSE_STREAMS - virtual bool Read(wxInputStream& str); - virtual bool Write(wxOutputStream& str) const; -#endif // wxUSE_STREAMS - virtual wxString GetType() const { return wxT("string"); } - -protected: - wxString m_value; -}; - -bool wxVariantDataString::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("string")), wxT("wxVariantDataString::Eq: argument mismatch") ); - - wxVariantDataString& otherData = (wxVariantDataString&) data; - - return (otherData.m_value == m_value); -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataString::Write(wxSTD ostream& str) const -{ - str << (const char*) m_value.mb_str(); - return true; -} -#endif - -bool wxVariantDataString::Write(wxString& str) const -{ - str = m_value; - return true; -} - -#if wxUSE_STREAMS -bool wxVariantDataString::Write(wxOutputStream& str) const -{ - // why doesn't wxOutputStream::operator<< take "const wxString&" - wxTextOutputStream s(str); - s.WriteString(m_value); - return true; -} - -bool wxVariantDataString::Read(wxInputStream& str) -{ - wxTextInputStream s(str); - - m_value = s.ReadLine(); - return true; -} -#endif // wxUSE_STREAMS - -bool wxVariantDataString::Read(wxString& str) -{ - m_value = str; - return true; -} - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataString, wxVariantData) - -// wxVariant **** - -wxVariant::wxVariant(const wxString& val, const wxString& name) -{ - m_data = new wxVariantDataString(val); - m_name = name; -} - -wxVariant::wxVariant(const wxChar* val, const wxString& name) -{ - m_data = new wxVariantDataString(wxString(val)); - m_name = name; -} - -bool wxVariant::operator== (const wxString& value) const -{ - wxString thisValue; - if (!Convert(&thisValue)) - return false; - - return value == thisValue; -} - -bool wxVariant::operator!= (const wxString& value) const -{ - return (!((*this) == value)); -} - -void wxVariant::operator= (const wxString& value) -{ - if (GetType() == wxT("string") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataString*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataString(value); - } -} - -void wxVariant::operator= (const wxChar* value) -{ - if (GetType() == wxT("string") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataString*)GetData())->SetValue(wxString(value)); - } - else - { - UnRef(); - m_data = new wxVariantDataString(wxString(value)); - } -} - -wxString wxVariant::GetString() const -{ - wxString value; - if (!Convert(& value)) - { - wxFAIL_MSG(wxT("Could not convert to a string")); - } - - return value; -} - -// ---------------------------------------------------------------------------- -// wxVariantDataWxObjectPtr -// ---------------------------------------------------------------------------- - -class wxVariantDataWxObjectPtr: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataWxObjectPtr) -public: - wxVariantDataWxObjectPtr() { } - wxVariantDataWxObjectPtr(wxObject* value) { m_value = value; } - - inline wxObject* GetValue() const { return m_value; } - inline void SetValue(wxObject* value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif - virtual bool Read(wxString& str); - virtual wxString GetType() const ; - virtual wxVariantData* Clone() { return new wxVariantDataWxObjectPtr; } - - virtual wxClassInfo* GetValueClassInfo() ; -protected: - wxObject* m_value; - - DECLARE_NO_COPY_CLASS(wxVariantDataWxObjectPtr) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataWxObjectPtr, wxVariantData) - -bool wxVariantDataWxObjectPtr::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( wxIsKindOf((&data), wxVariantDataWxObjectPtr), wxT("wxVariantDataWxObjectPtr::Eq: argument mismatch") ); - - wxVariantDataWxObjectPtr& otherData = (wxVariantDataWxObjectPtr&) data; - - return (otherData.m_value == m_value); -} - -wxString wxVariantDataWxObjectPtr::GetType() const -{ - wxString returnVal(wxT("wxObject")); - if (m_value) { - returnVal = m_value->GetClassInfo()->GetClassName(); - } - return returnVal; -} - -wxClassInfo* wxVariantDataWxObjectPtr::GetValueClassInfo() -{ - wxClassInfo* returnVal=NULL; - - if (m_value) returnVal = m_value->GetClassInfo(); - - return returnVal; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataWxObjectPtr::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDataWxObjectPtr::Write(wxString& str) const -{ - str.Printf(wxT("%s(%p)"), GetType().c_str(), wx_static_cast(void*, m_value)); - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataWxObjectPtr::Read(wxSTD istream& WXUNUSED(str)) -{ - // Not implemented - return false; -} -#endif - -bool wxVariantDataWxObjectPtr::Read(wxString& WXUNUSED(str)) -{ - // Not implemented - return false; -} - -// wxVariant - -wxVariant::wxVariant( wxObject* val, const wxString& name) -{ - m_data = new wxVariantDataWxObjectPtr(val); - m_name = name; -} - -bool wxVariant::operator== (wxObject* value) const -{ - return (value == ((wxVariantDataWxObjectPtr*)GetData())->GetValue()); -} - -bool wxVariant::operator!= (wxObject* value) const -{ - return (!((*this) == (wxObject*) value)); -} - -void wxVariant::operator= (wxObject* value) -{ - UnRef(); - m_data = new wxVariantDataWxObjectPtr(value); -} - -wxObject* wxVariant::GetWxObjectPtr() const -{ - wxASSERT(wxIsKindOf(GetData(), wxVariantDataWxObjectPtr)); - return (wxObject*) ((wxVariantDataWxObjectPtr*) m_data)->GetValue(); -} - -// ---------------------------------------------------------------------------- -// wxVariantDataVoidPtr -// ---------------------------------------------------------------------------- - -class wxVariantDataVoidPtr: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataVoidPtr) -public: - wxVariantDataVoidPtr() { } - wxVariantDataVoidPtr(void* value) { m_value = value; } - - inline void* GetValue() const { return m_value; } - inline void SetValue(void* value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif - virtual bool Read(wxString& str); - virtual wxString GetType() const { return wxT("void*"); } - virtual wxVariantData* Clone() { return new wxVariantDataVoidPtr; } - -protected: - void* m_value; - - DECLARE_NO_COPY_CLASS(wxVariantDataVoidPtr) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataVoidPtr, wxVariantData) - -bool wxVariantDataVoidPtr::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("void*")), wxT("wxVariantDataVoidPtr::Eq: argument mismatch") ); - - wxVariantDataVoidPtr& otherData = (wxVariantDataVoidPtr&) data; - - return (otherData.m_value == m_value); -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataVoidPtr::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDataVoidPtr::Write(wxString& str) const -{ - str.Printf(wxT("%p"), m_value); - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataVoidPtr::Read(wxSTD istream& WXUNUSED(str)) -{ - // Not implemented - return false; -} -#endif - -bool wxVariantDataVoidPtr::Read(wxString& WXUNUSED(str)) -{ - // Not implemented - return false; -} - -// wxVariant - -wxVariant::wxVariant( void* val, const wxString& name) -{ - m_data = new wxVariantDataVoidPtr(val); - m_name = name; -} - -bool wxVariant::operator== (void* value) const -{ - return (value == ((wxVariantDataVoidPtr*)GetData())->GetValue()); -} - -bool wxVariant::operator!= (void* value) const -{ - return (!((*this) == (void*) value)); -} - -void wxVariant::operator= (void* value) -{ - if (GetType() == wxT("void*") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataVoidPtr*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataVoidPtr(value); - } -} - -void* wxVariant::GetVoidPtr() const -{ - wxASSERT( (GetType() == wxT("void*")) ); - - return (void*) ((wxVariantDataVoidPtr*) m_data)->GetValue(); -} - -// ---------------------------------------------------------------------------- -// wxVariantDataDateTime -// ---------------------------------------------------------------------------- - -#if wxUSE_DATETIME - -class wxVariantDataDateTime: public wxVariantData -{ - DECLARE_DYNAMIC_CLASS(wxVariantDataDateTime) - -public: - wxVariantDataDateTime() { } - wxVariantDataDateTime(const wxDateTime& value) { m_value = value; } -#if wxUSE_ODBC - wxVariantDataDateTime(const TIME_STRUCT* valptr) - { m_value = wxDateTime(valptr->hour, valptr->minute, valptr->second); } - wxVariantDataDateTime(const DATE_STRUCT* valptr) - { m_value = wxDateTime(valptr->day, (wxDateTime::Month) (valptr->month - 1),valptr->year); } - wxVariantDataDateTime(const TIMESTAMP_STRUCT* valptr) - { m_value = wxDateTime(valptr->day, (wxDateTime::Month) (valptr->month - 1), valptr->year, - valptr->hour, valptr->minute, valptr->second, (wxDateTime::wxDateTime_t)valptr->fraction ); } -#endif //ODBC - - inline wxDateTime GetValue() const { return m_value; } - inline void SetValue(const wxDateTime& value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif - virtual bool Read(wxString& str); - virtual wxString GetType() const { return wxT("datetime"); } - virtual wxVariantData* Clone() { return new wxVariantDataDateTime; } - -protected: - wxDateTime m_value; -}; - - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataDateTime, wxVariantData) - -bool wxVariantDataDateTime::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("datetime")), wxT("wxVariantDataDateTime::Eq: argument mismatch") ); - - wxVariantDataDateTime& otherData = (wxVariantDataDateTime&) data; - - return (otherData.m_value == m_value); -} - - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataDateTime::Write(wxSTD ostream& str) const -{ - wxString value; - Write( value ); - str << value.c_str(); - return true; -} -#endif - - -bool wxVariantDataDateTime::Write(wxString& str) const -{ - if ( m_value.IsValid() ) - str = m_value.Format(); - else - str = wxT("Invalid"); - - return true; -} - - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataDateTime::Read(wxSTD istream& WXUNUSED(str)) -{ - // Not implemented - return false; -} -#endif - - -bool wxVariantDataDateTime::Read(wxString& str) -{ - if ( str == wxT("Invalid") ) - { - m_value = wxInvalidDateTime; - return true; - } - - if(! m_value.ParseDateTime(str)) - return false; - return true; -} - -// wxVariant - -wxVariant::wxVariant(const wxDateTime& val, const wxString& name) // Date -{ - m_data = new wxVariantDataDateTime(val); - m_name = name; -} - -#if wxUSE_ODBC -wxVariant::wxVariant(const TIME_STRUCT* valptr, const wxString& name) // Date -{ - m_data = new wxVariantDataDateTime(valptr); - m_name = name; -} - -wxVariant::wxVariant(const TIMESTAMP_STRUCT* valptr, const wxString& name) // Date -{ - m_data = new wxVariantDataDateTime(valptr); - m_name = name; -} - -wxVariant::wxVariant(const DATE_STRUCT* valptr, const wxString& name) // Date -{ - m_data = new wxVariantDataDateTime(valptr); - m_name = name; -} -#endif // wxUSE_ODBC - -bool wxVariant::operator== (const wxDateTime& value) const -{ - wxDateTime thisValue; - if (!Convert(&thisValue)) - return false; - - return value.IsEqualTo(thisValue); -} - -bool wxVariant::operator!= (const wxDateTime& value) const -{ - return (!((*this) == value)); -} - -void wxVariant::operator= (const wxDateTime& value) -{ - if (GetType() == wxT("datetime") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataDateTime*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataDateTime(value); - } -} - -#if wxUSE_ODBC -void wxVariant::operator= (const DATE_STRUCT* value) -{ - UnRef(); - m_data = new wxVariantDataDateTime(value); -} - -void wxVariant::operator= (const TIME_STRUCT* value) -{ - UnRef(); - m_data = new wxVariantDataDateTime(value); -} - -void wxVariant::operator= (const TIMESTAMP_STRUCT* value) -{ - UnRef(); - m_data = new wxVariantDataDateTime(value); -} - -#endif // wxUSE_ODBC - -wxDateTime wxVariant::GetDateTime() const -{ - wxDateTime value; - if (!Convert(& value)) - { - wxFAIL_MSG(wxT("Could not convert to a datetime")); - } - - return value; -} - -#endif // wxUSE_DATETIME - -// ---------------------------------------------------------------------------- -// wxVariantDataArrayString -// ---------------------------------------------------------------------------- - -class wxVariantDataArrayString: public wxVariantData -{ -public: - wxVariantDataArrayString() { } - wxVariantDataArrayString(const wxArrayString& value) { m_value = value; } - - wxArrayString GetValue() const { return m_value; } - void SetValue(const wxArrayString& value) { m_value = value; } - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif - virtual bool Read(wxString& str); - virtual wxString GetType() const { return wxT("arrstring"); } - virtual wxVariantData* Clone() { return new wxVariantDataArrayString; } - -protected: - wxArrayString m_value; - - DECLARE_DYNAMIC_CLASS(wxVariantDataArrayString) -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataArrayString, wxVariantData) - -bool wxVariantDataArrayString::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( data.GetType() == GetType(), wxT("wxVariantDataArrayString::Eq: argument mismatch") ); - - wxVariantDataArrayString& otherData = (wxVariantDataArrayString&) data; - - return otherData.m_value == m_value; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataArrayString::Write(wxSTD ostream& WXUNUSED(str)) const -{ - // Not implemented - return false; -} -#endif - -bool wxVariantDataArrayString::Write(wxString& str) const -{ - size_t count = m_value.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( n ) - str += _T(';'); - - str += m_value[n]; - } - - return true; -} - - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataArrayString::Read(wxSTD istream& WXUNUSED(str)) -{ - // Not implemented - return false; -} -#endif - - -bool wxVariantDataArrayString::Read(wxString& str) -{ - wxStringTokenizer tk(str, _T(";")); - while ( tk.HasMoreTokens() ) - { - m_value.Add(tk.GetNextToken()); - } - - return true; -} - -// wxVariant - -wxVariant::wxVariant(const wxArrayString& val, const wxString& name) // Strings -{ - m_data = new wxVariantDataArrayString(val); - m_name = name; -} - -bool wxVariant::operator==(const wxArrayString& WXUNUSED(value)) const -{ - wxFAIL_MSG( _T("TODO") ); - - return false; -} - -bool wxVariant::operator!=(const wxArrayString& value) const -{ - return !(*this == value); -} - -void wxVariant::operator=(const wxArrayString& value) -{ - if (GetType() == wxT("arrstring") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataArrayString *)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataArrayString(value); - } -} - -wxArrayString wxVariant::GetArrayString() const -{ - if ( GetType() == wxT("arrstring") ) - return ((wxVariantDataArrayString *)GetData())->GetValue(); - - return wxArrayString(); -} - -// ---------------------------------------------------------------------------- -// wxVariantDataList -// ---------------------------------------------------------------------------- - -class WXDLLIMPEXP_BASE wxVariantDataList: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataList) -public: - wxVariantDataList() {} - wxVariantDataList(const wxList& list); - virtual ~wxVariantDataList(); - - wxList& GetValue() { return m_value; } - void SetValue(const wxList& value) ; - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif - virtual bool Read(wxString& str); - virtual wxString GetType() const { return wxT("list"); } - - void Clear(); - -protected: - wxList m_value; -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataList, wxVariantData) - -wxVariantDataList::wxVariantDataList(const wxList& list) -{ - SetValue(list); -} - -wxVariantDataList::~wxVariantDataList() -{ - Clear(); -} - -void wxVariantDataList::SetValue(const wxList& value) -{ - Clear(); - wxList::compatibility_iterator node = value.GetFirst(); - while (node) - { - wxVariant* var = (wxVariant*) node->GetData(); - m_value.Append(new wxVariant(*var)); - node = node->GetNext(); - } -} - -void wxVariantDataList::Clear() -{ - wxList::compatibility_iterator node = m_value.GetFirst(); - while (node) - { - wxVariant* var = (wxVariant*) node->GetData(); - delete var; - node = node->GetNext(); - } - m_value.Clear(); -} - -bool wxVariantDataList::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("list")), wxT("wxVariantDataList::Eq: argument mismatch") ); - - wxVariantDataList& listData = (wxVariantDataList&) data; - wxList::compatibility_iterator node1 = m_value.GetFirst(); - wxList::compatibility_iterator node2 = listData.GetValue().GetFirst(); - while (node1 && node2) - { - wxVariant* var1 = (wxVariant*) node1->GetData(); - wxVariant* var2 = (wxVariant*) node2->GetData(); - if ((*var1) != (*var2)) - return false; - node1 = node1->GetNext(); - node2 = node2->GetNext(); - } - if (node1 || node2) return false; - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataList::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDataList::Write(wxString& str) const -{ - str = wxEmptyString; - wxList::compatibility_iterator node = m_value.GetFirst(); - while (node) - { - wxVariant* var = (wxVariant*) node->GetData(); - if (node != m_value.GetFirst()) - str += wxT(" "); - wxString str1; - str += var->MakeString(); - node = node->GetNext(); - } - - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataList::Read(wxSTD istream& WXUNUSED(str)) -{ - wxFAIL_MSG(wxT("Unimplemented")); - // TODO - return false; -} -#endif - -bool wxVariantDataList::Read(wxString& WXUNUSED(str)) -{ - wxFAIL_MSG(wxT("Unimplemented")); - // TODO - return false; -} - -// wxVariant - -wxVariant::wxVariant(const wxList& val, const wxString& name) // List of variants -{ - m_data = new wxVariantDataList(val); - m_name = name; -} - -bool wxVariant::operator== (const wxList& value) const -{ - wxASSERT_MSG( (GetType() == wxT("list")), wxT("Invalid type for == operator") ); - - wxVariantDataList other(value); - return (GetData()->Eq(other)); -} - -bool wxVariant::operator!= (const wxList& value) const -{ - return (!((*this) == value)); -} - -void wxVariant::operator= (const wxList& value) -{ - if (GetType() == wxT("list") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataList*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataList(value); - } -} - -wxList& wxVariant::GetList() const -{ - wxASSERT( (GetType() == wxT("list")) ); - - return (wxList&) ((wxVariantDataList*) m_data)->GetValue(); -} - -// Make empty list -void wxVariant::NullList() -{ - SetData(new wxVariantDataList()); -} - -// Append to list -void wxVariant::Append(const wxVariant& value) -{ - wxList& list = GetList(); - - list.Append(new wxVariant(value)); -} - -// Insert at front of list -void wxVariant::Insert(const wxVariant& value) -{ - wxList& list = GetList(); - - list.Insert(new wxVariant(value)); -} - -// Returns true if the variant is a member of the list -bool wxVariant::Member(const wxVariant& value) const -{ - wxList& list = GetList(); - - wxList::compatibility_iterator node = list.GetFirst(); - while (node) - { - wxVariant* other = (wxVariant*) node->GetData(); - if (value == *other) - return true; - node = node->GetNext(); - } - return false; -} - -// Deletes the nth element of the list -bool wxVariant::Delete(size_t item) -{ - wxList& list = GetList(); - - wxASSERT_MSG( (item < list.GetCount()), wxT("Invalid index to Delete") ); - wxList::compatibility_iterator node = list.Item(item); - wxVariant* variant = (wxVariant*) node->GetData(); - delete variant; - list.Erase(node); - return true; -} - -// Clear list -void wxVariant::ClearList() -{ - if (!IsNull() && (GetType() == wxT("list"))) - { - ((wxVariantDataList*) m_data)->Clear(); - } - else - { - if (!GetType().IsSameAs(wxT("list"))) - UnRef(); - - m_data = new wxVariantDataList; - } -} - -#if WXWIN_COMPATIBILITY_2_4 - -// ---------------------------------------------------------------------------- -// wxVariantDataStringList -// ---------------------------------------------------------------------------- - -class WXDLLIMPEXP_BASE wxVariantDataStringList: public wxVariantData -{ -DECLARE_DYNAMIC_CLASS(wxVariantDataStringList) -public: - wxVariantDataStringList() {} - wxVariantDataStringList(const wxStringList& list) { m_value = list; } - - wxStringList& GetValue() const { return (wxStringList&) m_value; } - void SetValue(const wxStringList& value); - - virtual bool Eq(wxVariantData& data) const; -#if wxUSE_STD_IOSTREAM - virtual bool Write(wxSTD ostream& str) const; -#endif - virtual bool Write(wxString& str) const; -#if wxUSE_STD_IOSTREAM - virtual bool Read(wxSTD istream& str); -#endif - virtual bool Read(wxString& str); - virtual wxString GetType() const { return wxT("stringlist"); }; - -protected: - wxStringList m_value; -}; - -IMPLEMENT_DYNAMIC_CLASS(wxVariantDataStringList, wxVariantData) - -void wxVariantDataStringList::SetValue(const wxStringList& value) -{ - m_value = value; -} - -bool wxVariantDataStringList::Eq(wxVariantData& data) const -{ - wxASSERT_MSG( (data.GetType() == wxT("stringlist")), wxT("wxVariantDataStringList::Eq: argument mismatch") ); - - wxVariantDataStringList& listData = (wxVariantDataStringList&) data; - wxStringList::compatibility_iterator node1 = m_value.GetFirst(); - wxStringList::compatibility_iterator node2 = listData.GetValue().GetFirst(); - while (node1 && node2) - { - wxString str1 ( node1->GetData() ); - wxString str2 ( node2->GetData() ); - if (str1 != str2) - return false; - node1 = node1->GetNext(); - node2 = node2->GetNext(); - } - if (node1 || node2) return false; - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataStringList::Write(wxSTD ostream& str) const -{ - wxString s; - Write(s); - str << (const char*) s.mb_str(); - return true; -} -#endif - -bool wxVariantDataStringList::Write(wxString& str) const -{ - str.Empty(); - wxStringList::compatibility_iterator node = m_value.GetFirst(); - while (node) - { - const wxChar* s = node->GetData(); - if (node != m_value.GetFirst()) - str += wxT(" "); - str += s; - node = node->GetNext(); - } - - return true; -} - -#if wxUSE_STD_IOSTREAM -bool wxVariantDataStringList::Read(wxSTD istream& WXUNUSED(str)) -{ - wxFAIL_MSG(wxT("Unimplemented")); - // TODO - return false; -} -#endif - -bool wxVariantDataStringList::Read(wxString& WXUNUSED(str)) -{ - wxFAIL_MSG(wxT("Unimplemented")); - // TODO - return false; -} - -#endif //2.4 compat - -#if WXWIN_COMPATIBILITY_2_4 - -wxVariant::wxVariant(const wxStringList& val, const wxString& name) -{ - m_data = new wxVariantDataStringList(val); - m_name = name; -} - -bool wxVariant::operator== (const wxStringList& value) const -{ - wxASSERT_MSG( (GetType() == wxT("stringlist")), wxT("Invalid type for == operator") ); - - wxVariantDataStringList other(value); - return (GetData()->Eq(other)); -} - -bool wxVariant::operator!= (const wxStringList& value) const -{ - wxASSERT_MSG( (GetType() == wxT("stringlist")), wxT("Invalid type for == operator") ); - - wxVariantDataStringList other(value); - return !(GetData()->Eq(other)); -} - -void wxVariant::operator= (const wxStringList& value) -{ - if (GetType() == wxT("stringlist") && - m_data->GetRefCount() == 1) - { - ((wxVariantDataStringList*)GetData())->SetValue(value); - } - else - { - UnRef(); - m_data = new wxVariantDataStringList(value); - } -} - -// wxVariant - -wxStringList& wxVariant::GetStringList() const -{ - wxASSERT( (GetType() == wxT("stringlist")) ); - - return (wxStringList&) ((wxVariantDataStringList*) m_data)->GetValue(); -} - -#endif - -// Treat a list variant as an array -wxVariant wxVariant::operator[] (size_t idx) const -{ -#if WXWIN_COMPATIBILITY_2_4 - wxASSERT_MSG( (GetType() == wxT("list") || GetType() == wxT("stringlist")), wxT("Invalid type for array operator") ); -#else - wxASSERT_MSG( GetType() == wxT("list"), wxT("Invalid type for array operator") ); -#endif - - if (GetType() == wxT("list")) - { - wxVariantDataList* data = (wxVariantDataList*) m_data; - wxASSERT_MSG( (idx < data->GetValue().GetCount()), wxT("Invalid index for array") ); - return * (wxVariant*) (data->GetValue().Item(idx)->GetData()); - } -#if WXWIN_COMPATIBILITY_2_4 - else if (GetType() == wxT("stringlist")) - { - wxVariantDataStringList* data = (wxVariantDataStringList*) m_data; - wxASSERT_MSG( (idx < data->GetValue().GetCount()), wxT("Invalid index for array") ); - - wxString str( (const wxChar*) (data->GetValue().Item(idx)->GetData()) ); - wxVariant variant( str ); - return variant; - } -#endif - return wxNullVariant; -} - -wxVariant& wxVariant::operator[] (size_t idx) -{ - // We can't return a reference to a variant for a string list, since the string - // is actually stored as a char*, not a variant. - - wxASSERT_MSG( (GetType() == wxT("list")), wxT("Invalid type for array operator") ); - - wxVariantDataList* data = (wxVariantDataList*) m_data; - wxASSERT_MSG( (idx < data->GetValue().GetCount()), wxT("Invalid index for array") ); - - return * (wxVariant*) (data->GetValue().Item(idx)->GetData()); -} - -// Return the number of elements in a list -size_t wxVariant::GetCount() const -{ -#if WXWIN_COMPATIBILITY_2_4 - wxASSERT_MSG( (GetType() == wxT("list") || GetType() == wxT("stringlist")), wxT("Invalid type for GetCount()") ); -#else - wxASSERT_MSG( GetType() == wxT("list"), wxT("Invalid type for GetCount()") ); -#endif - - if (GetType() == wxT("list")) - { - wxVariantDataList* data = (wxVariantDataList*) m_data; - return data->GetValue().GetCount(); - } -#if WXWIN_COMPATIBILITY_2_4 - else if (GetType() == wxT("stringlist")) - { - wxVariantDataStringList* data = (wxVariantDataStringList*) m_data; - return data->GetValue().GetCount(); - } -#endif - return 0; -} - -// ---------------------------------------------------------------------------- -// Type conversion -// ---------------------------------------------------------------------------- - -bool wxVariant::Convert(long* value) const -{ - wxString type(GetType()); - if (type == wxT("double")) - *value = (long) (((wxVariantDoubleData*)GetData())->GetValue()); - else if (type == wxT("long")) - *value = ((wxVariantDataLong*)GetData())->GetValue(); -#ifdef HAVE_BOOL - else if (type == wxT("bool")) - *value = (long) (((wxVariantDataBool*)GetData())->GetValue()); -#endif - else if (type == wxT("string")) - *value = wxAtol((const wxChar*) ((wxVariantDataString*)GetData())->GetValue()); - else - return false; - - return true; -} - -bool wxVariant::Convert(bool* value) const -{ - wxString type(GetType()); - if (type == wxT("double")) - *value = ((int) (((wxVariantDoubleData*)GetData())->GetValue()) != 0); - else if (type == wxT("long")) - *value = (((wxVariantDataLong*)GetData())->GetValue() != 0); -#ifdef HAVE_BOOL - else if (type == wxT("bool")) - *value = ((wxVariantDataBool*)GetData())->GetValue(); -#endif - else if (type == wxT("string")) - { - wxString val(((wxVariantDataString*)GetData())->GetValue()); - val.MakeLower(); - if (val == wxT("true") || val == wxT("yes") || val == wxT('1') ) - *value = true; - else if (val == wxT("false") || val == wxT("no") || val == wxT('0') ) - *value = false; - else - return false; - } - else - return false; - - return true; -} - -bool wxVariant::Convert(double* value) const -{ - wxString type(GetType()); - if (type == wxT("double")) - *value = ((wxVariantDoubleData*)GetData())->GetValue(); - else if (type == wxT("long")) - *value = (double) (((wxVariantDataLong*)GetData())->GetValue()); -#ifdef HAVE_BOOL - else if (type == wxT("bool")) - *value = (double) (((wxVariantDataBool*)GetData())->GetValue()); -#endif - else if (type == wxT("string")) - *value = (double) wxAtof((const wxChar*) ((wxVariantDataString*)GetData())->GetValue()); - else - return false; - - return true; -} - -bool wxVariant::Convert(wxChar* value) const -{ - wxString type(GetType()); - if (type == wxT("char")) - *value = ((wxVariantDataChar*)GetData())->GetValue(); - else if (type == wxT("long")) - *value = (char) (((wxVariantDataLong*)GetData())->GetValue()); -#ifdef HAVE_BOOL - else if (type == wxT("bool")) - *value = (char) (((wxVariantDataBool*)GetData())->GetValue()); -#endif - else - return false; - - return true; -} - -bool wxVariant::Convert(wxString* value) const -{ - *value = MakeString(); - return true; -} - -#if wxUSE_DATETIME -bool wxVariant::Convert(wxDateTime* value) const -{ - wxString type(GetType()); - if (type == wxT("datetime")) - { - *value = ((wxVariantDataDateTime*)GetData())->GetValue(); - return true; - } - // Fallback to string conversion - wxString val; - return Convert(&val) && - (value->ParseDateTime(val) || value->ParseDate(val) || value->ParseTime(val)); -} -#endif // wxUSE_DATETIME - -#endif // wxUSE_VARIANT +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/variant.cpp +// Purpose: wxVariant class, container for any type +// Author: Julian Smart +// Modified by: +// Created: 10/09/98 +// RCS-ID: $Id: variant.cpp 58054 2009-01-12 17:27:53Z JMS $ +// Copyright: (c) +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx/wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/variant.h" + +#if wxUSE_VARIANT + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/math.h" + #if wxUSE_STREAMS + #include "wx/stream.h" + #endif +#endif + +#if wxUSE_STD_IOSTREAM + #if wxUSE_IOSTREAMH + #include + #else + #include + #endif +#endif + +#if defined(__MWERKS__) && __MSL__ >= 0x6000 +namespace std {} +using namespace std ; +#endif + +#if wxUSE_STREAMS + #include "wx/txtstrm.h" +#endif + +#include "wx/string.h" +#include "wx/tokenzr.h" + +IMPLEMENT_ABSTRACT_CLASS(wxVariantData, wxObject) + +wxVariant WXDLLIMPEXP_BASE wxNullVariant; + + +/* + * wxVariant + */ + +IMPLEMENT_DYNAMIC_CLASS(wxVariant, wxObject) + +wxVariant::wxVariant() +{ + m_data = (wxVariantData*) NULL; +} + +bool wxVariant::IsNull() const +{ + return (m_data == (wxVariantData*) NULL); +} + +void wxVariant::MakeNull() +{ + UnRef(); +} + +void wxVariant::Clear() +{ + m_name = wxEmptyString; +} + +wxVariant::wxVariant(const wxVariant& variant) + : wxObject() +{ + m_data = (wxVariantData*) NULL; + + if (!variant.IsNull()) + Ref(variant); + + m_name = variant.m_name; +} + +wxVariant::wxVariant(wxVariantData* data, const wxString& name) // User-defined data +{ + m_data = data; + m_name = name; +} + +wxVariant::~wxVariant() +{ + UnRef(); +} + +// Assignment +void wxVariant::operator= (const wxVariant& variant) +{ + Ref(variant); + m_name = variant.m_name; +} + +// myVariant = new wxStringVariantData("hello") +void wxVariant::operator= (wxVariantData* variantData) +{ + UnRef(); + m_data = variantData; +} + +bool wxVariant::operator== (const wxVariant& variant) const +{ + if (IsNull() || variant.IsNull()) + return (IsNull() == variant.IsNull()); + + return (GetData()->Eq(* variant.GetData())); +} + +bool wxVariant::operator!= (const wxVariant& variant) const +{ + return (!(*this == variant)); +} + + +wxString wxVariant::MakeString() const +{ + if (!IsNull()) + { + wxString str; + if (GetData()->Write(str)) + return str; + } + return wxEmptyString; +} + +void wxVariant::SetData(wxVariantData* data) +{ + UnRef(); + m_data = data; +} + +void wxVariant::Ref(const wxVariant& clone) +{ + // nothing to be done + if (m_data == clone.m_data) + return; + + // delete reference to old data + UnRef(); + + // reference new data + if ( clone.m_data ) + { + m_data = clone.m_data; + m_data->m_count++; + } +} + + +void wxVariant::UnRef() +{ + if ( m_data ) + { + wxASSERT_MSG( m_data->m_count > 0, _T("invalid ref data count") ); + + m_data->DecRef(); + m_data = NULL; + } +} + + +// Returns a string representing the type of the variant, +// e.g. "string", "bool", "list", "double", "long" +wxString wxVariant::GetType() const +{ + if (IsNull()) + return wxString(wxT("null")); + else + return GetData()->GetType(); +} + + +bool wxVariant::IsType(const wxString& type) const +{ + return (GetType() == type); +} + +bool wxVariant::IsValueKindOf(const wxClassInfo* type) const +{ + wxClassInfo* info=GetData()->GetValueClassInfo(); + return info ? info->IsKindOf(type) : false ; +} + + +// ----------------------------------------------------------------- +// wxVariantDataLong +// ----------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxVariantDataLong: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataLong) +public: + wxVariantDataLong() { m_value = 0; } + wxVariantDataLong(long value) { m_value = value; } + + inline long GetValue() const { return m_value; } + inline void SetValue(long value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; + + virtual bool Read(wxString& str); + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); + virtual bool Write(wxSTD ostream& str) const; +#endif +#if wxUSE_STREAMS + virtual bool Read(wxInputStream& str); + virtual bool Write(wxOutputStream &str) const; +#endif // wxUSE_STREAMS + + virtual wxString GetType() const { return wxT("long"); } + +protected: + long m_value; +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataLong, wxVariantData) + +bool wxVariantDataLong::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("long")), wxT("wxVariantDataLong::Eq: argument mismatch") ); + + wxVariantDataLong& otherData = (wxVariantDataLong&) data; + + return (otherData.m_value == m_value); +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataLong::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDataLong::Write(wxString& str) const +{ + str.Printf(wxT("%ld"), m_value); + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataLong::Read(wxSTD istream& str) +{ + str >> m_value; + return true; +} +#endif + +#if wxUSE_STREAMS +bool wxVariantDataLong::Write(wxOutputStream& str) const +{ + wxTextOutputStream s(str); + + s.Write32((size_t)m_value); + return true; +} + +bool wxVariantDataLong::Read(wxInputStream& str) +{ + wxTextInputStream s(str); + m_value = s.Read32(); + return true; +} +#endif // wxUSE_STREAMS + +bool wxVariantDataLong::Read(wxString& str) +{ + m_value = wxAtol((const wxChar*) str); + return true; +} + +// wxVariant + +wxVariant::wxVariant(long val, const wxString& name) +{ + m_data = new wxVariantDataLong(val); + m_name = name; +} + +wxVariant::wxVariant(int val, const wxString& name) +{ + m_data = new wxVariantDataLong((long)val); + m_name = name; +} + +wxVariant::wxVariant(short val, const wxString& name) +{ + m_data = new wxVariantDataLong((long)val); + m_name = name; +} + +bool wxVariant::operator== (long value) const +{ + long thisValue; + if (!Convert(&thisValue)) + return false; + else + return (value == thisValue); +} + +bool wxVariant::operator!= (long value) const +{ + return (!((*this) == value)); +} + +void wxVariant::operator= (long value) +{ + if (GetType() == wxT("long") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataLong*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataLong(value); + } +} + +long wxVariant::GetLong() const +{ + long value; + if (Convert(& value)) + return value; + else + { + wxFAIL_MSG(wxT("Could not convert to a long")); + return 0; + } +} + +// ----------------------------------------------------------------- +// wxVariantDoubleData +// ----------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxVariantDoubleData: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDoubleData) +public: + wxVariantDoubleData() { m_value = 0.0; } + wxVariantDoubleData(double value) { m_value = value; } + + inline double GetValue() const { return m_value; } + inline void SetValue(double value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; + virtual bool Read(wxString& str); +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif +#if wxUSE_STREAMS + virtual bool Read(wxInputStream& str); + virtual bool Write(wxOutputStream &str) const; +#endif // wxUSE_STREAMS + virtual wxString GetType() const { return wxT("double"); } + +protected: + double m_value; +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDoubleData, wxVariantData) + +bool wxVariantDoubleData::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("double")), wxT("wxVariantDoubleData::Eq: argument mismatch") ); + + wxVariantDoubleData& otherData = (wxVariantDoubleData&) data; + + return wxIsSameDouble(otherData.m_value, m_value); +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDoubleData::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDoubleData::Write(wxString& str) const +{ + str.Printf(wxT("%.14g"), m_value); + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDoubleData::Read(wxSTD istream& str) +{ + str >> m_value; + return true; +} +#endif + +#if wxUSE_STREAMS +bool wxVariantDoubleData::Write(wxOutputStream& str) const +{ + wxTextOutputStream s(str); + s.WriteDouble((double)m_value); + return true; +} + +bool wxVariantDoubleData::Read(wxInputStream& str) +{ + wxTextInputStream s(str); + m_value = (float)s.ReadDouble(); + return true; +} +#endif // wxUSE_STREAMS + +bool wxVariantDoubleData::Read(wxString& str) +{ + m_value = wxAtof((const wxChar*) str); + return true; +} + +// wxVariant double code + +wxVariant::wxVariant(double val, const wxString& name) +{ + m_data = new wxVariantDoubleData(val); + m_name = name; +} + +bool wxVariant::operator== (double value) const +{ + double thisValue; + if (!Convert(&thisValue)) + return false; + + return wxIsSameDouble(value, thisValue); +} + +bool wxVariant::operator!= (double value) const +{ + return (!((*this) == value)); +} + +void wxVariant::operator= (double value) +{ + if (GetType() == wxT("double") && + m_data->GetRefCount() == 1) + { + ((wxVariantDoubleData*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDoubleData(value); + } +} + +double wxVariant::GetDouble() const +{ + double value; + if (Convert(& value)) + return value; + else + { + wxFAIL_MSG(wxT("Could not convert to a double number")); + return 0.0; + } +} + +// ----------------------------------------------------------------- +// wxVariantBoolData +// ----------------------------------------------------------------- + +#ifdef HAVE_BOOL + +class WXDLLIMPEXP_BASE wxVariantDataBool: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataBool) +public: + wxVariantDataBool() { m_value = 0; } + wxVariantDataBool(bool value) { m_value = value; } + + inline bool GetValue() const { return m_value; } + inline void SetValue(bool value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; + virtual bool Read(wxString& str); +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif +#if wxUSE_STREAMS + virtual bool Read(wxInputStream& str); + virtual bool Write(wxOutputStream& str) const; +#endif // wxUSE_STREAMS + virtual wxString GetType() const { return wxT("bool"); } + +protected: + bool m_value; +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataBool, wxVariantData) + +bool wxVariantDataBool::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("bool")), wxT("wxVariantDataBool::Eq: argument mismatch") ); + + wxVariantDataBool& otherData = (wxVariantDataBool&) data; + + return (otherData.m_value == m_value); +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataBool::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDataBool::Write(wxString& str) const +{ + str.Printf(wxT("%d"), (int) m_value); + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataBool::Read(wxSTD istream& WXUNUSED(str)) +{ + wxFAIL_MSG(wxT("Unimplemented")); +// str >> (long) m_value; + return false; +} +#endif + +#if wxUSE_STREAMS +bool wxVariantDataBool::Write(wxOutputStream& str) const +{ + wxTextOutputStream s(str); + + s.Write8(m_value); + return true; +} + +bool wxVariantDataBool::Read(wxInputStream& str) +{ + wxTextInputStream s(str); + + m_value = s.Read8() != 0; + return true; +} +#endif // wxUSE_STREAMS + +bool wxVariantDataBool::Read(wxString& str) +{ + m_value = (wxAtol((const wxChar*) str) != 0); + return true; +} + +// wxVariant **** + +wxVariant::wxVariant(bool val, const wxString& name) +{ + m_data = new wxVariantDataBool(val); + m_name = name; +} + +bool wxVariant::operator== (bool value) const +{ + bool thisValue; + if (!Convert(&thisValue)) + return false; + else + return (value == thisValue); +} + +bool wxVariant::operator!= (bool value) const +{ + return (!((*this) == value)); +} + +void wxVariant::operator= (bool value) +{ + if (GetType() == wxT("bool") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataBool*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataBool(value); + } +} + +bool wxVariant::GetBool() const +{ + bool value; + if (Convert(& value)) + return value; + else + { + wxFAIL_MSG(wxT("Could not convert to a bool")); + return 0; + } +} + +#endif // HAVE_BOOL + +// ----------------------------------------------------------------- +// wxVariantDataChar +// ----------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxVariantDataChar: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataChar) +public: + wxVariantDataChar() { m_value = 0; } + wxVariantDataChar(wxChar value) { m_value = value; } + + inline wxChar GetValue() const { return m_value; } + inline void SetValue(wxChar value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Read(wxString& str); + virtual bool Write(wxString& str) const; +#if wxUSE_STREAMS + virtual bool Read(wxInputStream& str); + virtual bool Write(wxOutputStream& str) const; +#endif // wxUSE_STREAMS + virtual wxString GetType() const { return wxT("char"); } + +protected: + wxChar m_value; +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataChar, wxVariantData) + +bool wxVariantDataChar::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("char")), wxT("wxVariantDataChar::Eq: argument mismatch") ); + + wxVariantDataChar& otherData = (wxVariantDataChar&) data; + + return (otherData.m_value == m_value); +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataChar::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDataChar::Write(wxString& str) const +{ + str.Printf(wxT("%c"), m_value); + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataChar::Read(wxSTD istream& WXUNUSED(str)) +{ + wxFAIL_MSG(wxT("Unimplemented")); + + return false; +} +#endif + +#if wxUSE_STREAMS +bool wxVariantDataChar::Write(wxOutputStream& str) const +{ + wxTextOutputStream s(str); + + s << m_value; + + return true; +} + +bool wxVariantDataChar::Read(wxInputStream& str) +{ + wxTextInputStream s(str); + + s >> m_value; + + return true; +} +#endif // wxUSE_STREAMS + +bool wxVariantDataChar::Read(wxString& str) +{ + m_value = str[size_t(0)]; + return true; +} + +wxVariant::wxVariant(wxChar val, const wxString& name) +{ + m_data = new wxVariantDataChar(val); + m_name = name; +} + +bool wxVariant::operator== (wxChar value) const +{ + wxChar thisValue; + if (!Convert(&thisValue)) + return false; + else + return (value == thisValue); +} + +bool wxVariant::operator!= (wxChar value) const +{ + return (!((*this) == value)); +} + +void wxVariant::operator= (wxChar value) +{ + if (GetType() == wxT("char") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataChar*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataChar(value); + } +} + +wxChar wxVariant::GetChar() const +{ + wxChar value; + if (Convert(& value)) + return value; + else + { + wxFAIL_MSG(wxT("Could not convert to a char")); + return 0; + } +} + +// ---------------------------------------------------------------------------- +// wxVariantDataString +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxVariantDataString: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataString) +public: + wxVariantDataString() { } + wxVariantDataString(const wxString& value) { m_value = value; } + + inline wxString GetValue() const { return m_value; } + inline void SetValue(const wxString& value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Read(wxString& str); + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& WXUNUSED(str)) { return false; } +#endif +#if wxUSE_STREAMS + virtual bool Read(wxInputStream& str); + virtual bool Write(wxOutputStream& str) const; +#endif // wxUSE_STREAMS + virtual wxString GetType() const { return wxT("string"); } + +protected: + wxString m_value; +}; + +bool wxVariantDataString::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("string")), wxT("wxVariantDataString::Eq: argument mismatch") ); + + wxVariantDataString& otherData = (wxVariantDataString&) data; + + return (otherData.m_value == m_value); +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataString::Write(wxSTD ostream& str) const +{ + str << (const char*) m_value.mb_str(); + return true; +} +#endif + +bool wxVariantDataString::Write(wxString& str) const +{ + str = m_value; + return true; +} + +#if wxUSE_STREAMS +bool wxVariantDataString::Write(wxOutputStream& str) const +{ + // why doesn't wxOutputStream::operator<< take "const wxString&" + wxTextOutputStream s(str); + s.WriteString(m_value); + return true; +} + +bool wxVariantDataString::Read(wxInputStream& str) +{ + wxTextInputStream s(str); + + m_value = s.ReadLine(); + return true; +} +#endif // wxUSE_STREAMS + +bool wxVariantDataString::Read(wxString& str) +{ + m_value = str; + return true; +} + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataString, wxVariantData) + +// wxVariant **** + +wxVariant::wxVariant(const wxString& val, const wxString& name) +{ + m_data = new wxVariantDataString(val); + m_name = name; +} + +wxVariant::wxVariant(const wxChar* val, const wxString& name) +{ + m_data = new wxVariantDataString(wxString(val)); + m_name = name; +} + +bool wxVariant::operator== (const wxString& value) const +{ + wxString thisValue; + if (!Convert(&thisValue)) + return false; + + return value == thisValue; +} + +bool wxVariant::operator!= (const wxString& value) const +{ + return (!((*this) == value)); +} + +void wxVariant::operator= (const wxString& value) +{ + if (GetType() == wxT("string") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataString*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataString(value); + } +} + +void wxVariant::operator= (const wxChar* value) +{ + if (GetType() == wxT("string") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataString*)GetData())->SetValue(wxString(value)); + } + else + { + UnRef(); + m_data = new wxVariantDataString(wxString(value)); + } +} + +wxString wxVariant::GetString() const +{ + wxString value; + if (!Convert(& value)) + { + wxFAIL_MSG(wxT("Could not convert to a string")); + } + + return value; +} + +// ---------------------------------------------------------------------------- +// wxVariantDataWxObjectPtr +// ---------------------------------------------------------------------------- + +class wxVariantDataWxObjectPtr: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataWxObjectPtr) +public: + wxVariantDataWxObjectPtr() { } + wxVariantDataWxObjectPtr(wxObject* value) { m_value = value; } + + inline wxObject* GetValue() const { return m_value; } + inline void SetValue(wxObject* value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif + virtual bool Read(wxString& str); + virtual wxString GetType() const ; + virtual wxVariantData* Clone() { return new wxVariantDataWxObjectPtr; } + + virtual wxClassInfo* GetValueClassInfo() ; +protected: + wxObject* m_value; + + DECLARE_NO_COPY_CLASS(wxVariantDataWxObjectPtr) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataWxObjectPtr, wxVariantData) + +bool wxVariantDataWxObjectPtr::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( wxIsKindOf((&data), wxVariantDataWxObjectPtr), wxT("wxVariantDataWxObjectPtr::Eq: argument mismatch") ); + + wxVariantDataWxObjectPtr& otherData = (wxVariantDataWxObjectPtr&) data; + + return (otherData.m_value == m_value); +} + +wxString wxVariantDataWxObjectPtr::GetType() const +{ + wxString returnVal(wxT("wxObject")); + if (m_value) { + returnVal = m_value->GetClassInfo()->GetClassName(); + } + return returnVal; +} + +wxClassInfo* wxVariantDataWxObjectPtr::GetValueClassInfo() +{ + wxClassInfo* returnVal=NULL; + + if (m_value) returnVal = m_value->GetClassInfo(); + + return returnVal; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataWxObjectPtr::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDataWxObjectPtr::Write(wxString& str) const +{ + str.Printf(wxT("%s(%p)"), GetType().c_str(), wx_static_cast(void*, m_value)); + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataWxObjectPtr::Read(wxSTD istream& WXUNUSED(str)) +{ + // Not implemented + return false; +} +#endif + +bool wxVariantDataWxObjectPtr::Read(wxString& WXUNUSED(str)) +{ + // Not implemented + return false; +} + +// wxVariant + +wxVariant::wxVariant( wxObject* val, const wxString& name) +{ + m_data = new wxVariantDataWxObjectPtr(val); + m_name = name; +} + +bool wxVariant::operator== (wxObject* value) const +{ + return (value == ((wxVariantDataWxObjectPtr*)GetData())->GetValue()); +} + +bool wxVariant::operator!= (wxObject* value) const +{ + return (!((*this) == (wxObject*) value)); +} + +void wxVariant::operator= (wxObject* value) +{ + UnRef(); + m_data = new wxVariantDataWxObjectPtr(value); +} + +wxObject* wxVariant::GetWxObjectPtr() const +{ + wxASSERT(wxIsKindOf(GetData(), wxVariantDataWxObjectPtr)); + return (wxObject*) ((wxVariantDataWxObjectPtr*) m_data)->GetValue(); +} + +// ---------------------------------------------------------------------------- +// wxVariantDataVoidPtr +// ---------------------------------------------------------------------------- + +class wxVariantDataVoidPtr: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataVoidPtr) +public: + wxVariantDataVoidPtr() { } + wxVariantDataVoidPtr(void* value) { m_value = value; } + + inline void* GetValue() const { return m_value; } + inline void SetValue(void* value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif + virtual bool Read(wxString& str); + virtual wxString GetType() const { return wxT("void*"); } + virtual wxVariantData* Clone() { return new wxVariantDataVoidPtr; } + +protected: + void* m_value; + + DECLARE_NO_COPY_CLASS(wxVariantDataVoidPtr) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataVoidPtr, wxVariantData) + +bool wxVariantDataVoidPtr::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("void*")), wxT("wxVariantDataVoidPtr::Eq: argument mismatch") ); + + wxVariantDataVoidPtr& otherData = (wxVariantDataVoidPtr&) data; + + return (otherData.m_value == m_value); +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataVoidPtr::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDataVoidPtr::Write(wxString& str) const +{ + str.Printf(wxT("%p"), m_value); + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataVoidPtr::Read(wxSTD istream& WXUNUSED(str)) +{ + // Not implemented + return false; +} +#endif + +bool wxVariantDataVoidPtr::Read(wxString& WXUNUSED(str)) +{ + // Not implemented + return false; +} + +// wxVariant + +wxVariant::wxVariant( void* val, const wxString& name) +{ + m_data = new wxVariantDataVoidPtr(val); + m_name = name; +} + +bool wxVariant::operator== (void* value) const +{ + return (value == ((wxVariantDataVoidPtr*)GetData())->GetValue()); +} + +bool wxVariant::operator!= (void* value) const +{ + return (!((*this) == (void*) value)); +} + +void wxVariant::operator= (void* value) +{ + if (GetType() == wxT("void*") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataVoidPtr*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataVoidPtr(value); + } +} + +void* wxVariant::GetVoidPtr() const +{ + wxASSERT( (GetType() == wxT("void*")) ); + + return (void*) ((wxVariantDataVoidPtr*) m_data)->GetValue(); +} + +// ---------------------------------------------------------------------------- +// wxVariantDataDateTime +// ---------------------------------------------------------------------------- + +#if wxUSE_DATETIME + +class wxVariantDataDateTime: public wxVariantData +{ + DECLARE_DYNAMIC_CLASS(wxVariantDataDateTime) + +public: + wxVariantDataDateTime() { } + wxVariantDataDateTime(const wxDateTime& value) { m_value = value; } +#if wxUSE_ODBC + wxVariantDataDateTime(const TIME_STRUCT* valptr) + { m_value = wxDateTime(valptr->hour, valptr->minute, valptr->second); } + wxVariantDataDateTime(const DATE_STRUCT* valptr) + { m_value = wxDateTime(valptr->day, (wxDateTime::Month) (valptr->month - 1),valptr->year); } + wxVariantDataDateTime(const TIMESTAMP_STRUCT* valptr) + { m_value = wxDateTime(valptr->day, (wxDateTime::Month) (valptr->month - 1), valptr->year, + valptr->hour, valptr->minute, valptr->second, (wxDateTime::wxDateTime_t)valptr->fraction ); } +#endif //ODBC + + inline wxDateTime GetValue() const { return m_value; } + inline void SetValue(const wxDateTime& value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif + virtual bool Read(wxString& str); + virtual wxString GetType() const { return wxT("datetime"); } + virtual wxVariantData* Clone() { return new wxVariantDataDateTime; } + +protected: + wxDateTime m_value; +}; + + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataDateTime, wxVariantData) + +bool wxVariantDataDateTime::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("datetime")), wxT("wxVariantDataDateTime::Eq: argument mismatch") ); + + wxVariantDataDateTime& otherData = (wxVariantDataDateTime&) data; + + return (otherData.m_value == m_value); +} + + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataDateTime::Write(wxSTD ostream& str) const +{ + wxString value; + Write( value ); + str << value.c_str(); + return true; +} +#endif + + +bool wxVariantDataDateTime::Write(wxString& str) const +{ + if ( m_value.IsValid() ) + str = m_value.Format(); + else + str = wxT("Invalid"); + + return true; +} + + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataDateTime::Read(wxSTD istream& WXUNUSED(str)) +{ + // Not implemented + return false; +} +#endif + + +bool wxVariantDataDateTime::Read(wxString& str) +{ + if ( str == wxT("Invalid") ) + { + m_value = wxInvalidDateTime; + return true; + } + + if(! m_value.ParseDateTime(str)) + return false; + return true; +} + +// wxVariant + +wxVariant::wxVariant(const wxDateTime& val, const wxString& name) // Date +{ + m_data = new wxVariantDataDateTime(val); + m_name = name; +} + +#if wxUSE_ODBC +wxVariant::wxVariant(const TIME_STRUCT* valptr, const wxString& name) // Date +{ + m_data = new wxVariantDataDateTime(valptr); + m_name = name; +} + +wxVariant::wxVariant(const TIMESTAMP_STRUCT* valptr, const wxString& name) // Date +{ + m_data = new wxVariantDataDateTime(valptr); + m_name = name; +} + +wxVariant::wxVariant(const DATE_STRUCT* valptr, const wxString& name) // Date +{ + m_data = new wxVariantDataDateTime(valptr); + m_name = name; +} +#endif // wxUSE_ODBC + +bool wxVariant::operator== (const wxDateTime& value) const +{ + wxDateTime thisValue; + if (!Convert(&thisValue)) + return false; + + return value.IsEqualTo(thisValue); +} + +bool wxVariant::operator!= (const wxDateTime& value) const +{ + return (!((*this) == value)); +} + +void wxVariant::operator= (const wxDateTime& value) +{ + if (GetType() == wxT("datetime") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataDateTime*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataDateTime(value); + } +} + +#if wxUSE_ODBC +void wxVariant::operator= (const DATE_STRUCT* value) +{ + UnRef(); + m_data = new wxVariantDataDateTime(value); +} + +void wxVariant::operator= (const TIME_STRUCT* value) +{ + UnRef(); + m_data = new wxVariantDataDateTime(value); +} + +void wxVariant::operator= (const TIMESTAMP_STRUCT* value) +{ + UnRef(); + m_data = new wxVariantDataDateTime(value); +} + +#endif // wxUSE_ODBC + +wxDateTime wxVariant::GetDateTime() const +{ + wxDateTime value; + if (!Convert(& value)) + { + wxFAIL_MSG(wxT("Could not convert to a datetime")); + } + + return value; +} + +#endif // wxUSE_DATETIME + +// ---------------------------------------------------------------------------- +// wxVariantDataArrayString +// ---------------------------------------------------------------------------- + +class wxVariantDataArrayString: public wxVariantData +{ +public: + wxVariantDataArrayString() { } + wxVariantDataArrayString(const wxArrayString& value) { m_value = value; } + + wxArrayString GetValue() const { return m_value; } + void SetValue(const wxArrayString& value) { m_value = value; } + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif + virtual bool Read(wxString& str); + virtual wxString GetType() const { return wxT("arrstring"); } + virtual wxVariantData* Clone() { return new wxVariantDataArrayString; } + +protected: + wxArrayString m_value; + + DECLARE_DYNAMIC_CLASS(wxVariantDataArrayString) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataArrayString, wxVariantData) + +bool wxVariantDataArrayString::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( data.GetType() == GetType(), wxT("wxVariantDataArrayString::Eq: argument mismatch") ); + + wxVariantDataArrayString& otherData = (wxVariantDataArrayString&) data; + + return otherData.m_value == m_value; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataArrayString::Write(wxSTD ostream& WXUNUSED(str)) const +{ + // Not implemented + return false; +} +#endif + +bool wxVariantDataArrayString::Write(wxString& str) const +{ + size_t count = m_value.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( n ) + str += _T(';'); + + str += m_value[n]; + } + + return true; +} + + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataArrayString::Read(wxSTD istream& WXUNUSED(str)) +{ + // Not implemented + return false; +} +#endif + + +bool wxVariantDataArrayString::Read(wxString& str) +{ + wxStringTokenizer tk(str, _T(";")); + while ( tk.HasMoreTokens() ) + { + m_value.Add(tk.GetNextToken()); + } + + return true; +} + +// wxVariant + +wxVariant::wxVariant(const wxArrayString& val, const wxString& name) // Strings +{ + m_data = new wxVariantDataArrayString(val); + m_name = name; +} + +bool wxVariant::operator==(const wxArrayString& WXUNUSED(value)) const +{ + wxFAIL_MSG( _T("TODO") ); + + return false; +} + +bool wxVariant::operator!=(const wxArrayString& value) const +{ + return !(*this == value); +} + +void wxVariant::operator=(const wxArrayString& value) +{ + if (GetType() == wxT("arrstring") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataArrayString *)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataArrayString(value); + } +} + +wxArrayString wxVariant::GetArrayString() const +{ + if ( GetType() == wxT("arrstring") ) + return ((wxVariantDataArrayString *)GetData())->GetValue(); + + return wxArrayString(); +} + +// ---------------------------------------------------------------------------- +// wxVariantDataList +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxVariantDataList: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataList) +public: + wxVariantDataList() {} + wxVariantDataList(const wxList& list); + virtual ~wxVariantDataList(); + + wxList& GetValue() { return m_value; } + void SetValue(const wxList& value) ; + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif + virtual bool Read(wxString& str); + virtual wxString GetType() const { return wxT("list"); } + + void Clear(); + +protected: + wxList m_value; +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataList, wxVariantData) + +wxVariantDataList::wxVariantDataList(const wxList& list) +{ + SetValue(list); +} + +wxVariantDataList::~wxVariantDataList() +{ + Clear(); +} + +void wxVariantDataList::SetValue(const wxList& value) +{ + Clear(); + wxList::compatibility_iterator node = value.GetFirst(); + while (node) + { + wxVariant* var = (wxVariant*) node->GetData(); + m_value.Append(new wxVariant(*var)); + node = node->GetNext(); + } +} + +void wxVariantDataList::Clear() +{ + wxList::compatibility_iterator node = m_value.GetFirst(); + while (node) + { + wxVariant* var = (wxVariant*) node->GetData(); + delete var; + node = node->GetNext(); + } + m_value.Clear(); +} + +bool wxVariantDataList::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("list")), wxT("wxVariantDataList::Eq: argument mismatch") ); + + wxVariantDataList& listData = (wxVariantDataList&) data; + wxList::compatibility_iterator node1 = m_value.GetFirst(); + wxList::compatibility_iterator node2 = listData.GetValue().GetFirst(); + while (node1 && node2) + { + wxVariant* var1 = (wxVariant*) node1->GetData(); + wxVariant* var2 = (wxVariant*) node2->GetData(); + if ((*var1) != (*var2)) + return false; + node1 = node1->GetNext(); + node2 = node2->GetNext(); + } + if (node1 || node2) return false; + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataList::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDataList::Write(wxString& str) const +{ + str = wxEmptyString; + wxList::compatibility_iterator node = m_value.GetFirst(); + while (node) + { + wxVariant* var = (wxVariant*) node->GetData(); + if (node != m_value.GetFirst()) + str += wxT(" "); + wxString str1; + str += var->MakeString(); + node = node->GetNext(); + } + + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataList::Read(wxSTD istream& WXUNUSED(str)) +{ + wxFAIL_MSG(wxT("Unimplemented")); + // TODO + return false; +} +#endif + +bool wxVariantDataList::Read(wxString& WXUNUSED(str)) +{ + wxFAIL_MSG(wxT("Unimplemented")); + // TODO + return false; +} + +// wxVariant + +wxVariant::wxVariant(const wxList& val, const wxString& name) // List of variants +{ + m_data = new wxVariantDataList(val); + m_name = name; +} + +bool wxVariant::operator== (const wxList& value) const +{ + wxASSERT_MSG( (GetType() == wxT("list")), wxT("Invalid type for == operator") ); + + wxVariantDataList other(value); + return (GetData()->Eq(other)); +} + +bool wxVariant::operator!= (const wxList& value) const +{ + return (!((*this) == value)); +} + +void wxVariant::operator= (const wxList& value) +{ + if (GetType() == wxT("list") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataList*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataList(value); + } +} + +wxList& wxVariant::GetList() const +{ + wxASSERT( (GetType() == wxT("list")) ); + + return (wxList&) ((wxVariantDataList*) m_data)->GetValue(); +} + +// Make empty list +void wxVariant::NullList() +{ + SetData(new wxVariantDataList()); +} + +// Append to list +void wxVariant::Append(const wxVariant& value) +{ + wxList& list = GetList(); + + list.Append(new wxVariant(value)); +} + +// Insert at front of list +void wxVariant::Insert(const wxVariant& value) +{ + wxList& list = GetList(); + + list.Insert(new wxVariant(value)); +} + +// Returns true if the variant is a member of the list +bool wxVariant::Member(const wxVariant& value) const +{ + wxList& list = GetList(); + + wxList::compatibility_iterator node = list.GetFirst(); + while (node) + { + wxVariant* other = (wxVariant*) node->GetData(); + if (value == *other) + return true; + node = node->GetNext(); + } + return false; +} + +// Deletes the nth element of the list +bool wxVariant::Delete(size_t item) +{ + wxList& list = GetList(); + + wxASSERT_MSG( (item < list.GetCount()), wxT("Invalid index to Delete") ); + wxList::compatibility_iterator node = list.Item(item); + wxVariant* variant = (wxVariant*) node->GetData(); + delete variant; + list.Erase(node); + return true; +} + +// Clear list +void wxVariant::ClearList() +{ + if (!IsNull() && (GetType() == wxT("list"))) + { + ((wxVariantDataList*) m_data)->Clear(); + } + else + { + if (!GetType().IsSameAs(wxT("list"))) + UnRef(); + + m_data = new wxVariantDataList; + } +} + +#if WXWIN_COMPATIBILITY_2_4 + +// ---------------------------------------------------------------------------- +// wxVariantDataStringList +// ---------------------------------------------------------------------------- + +class WXDLLIMPEXP_BASE wxVariantDataStringList: public wxVariantData +{ +DECLARE_DYNAMIC_CLASS(wxVariantDataStringList) +public: + wxVariantDataStringList() {} + wxVariantDataStringList(const wxStringList& list) { m_value = list; } + + wxStringList& GetValue() const { return (wxStringList&) m_value; } + void SetValue(const wxStringList& value); + + virtual bool Eq(wxVariantData& data) const; +#if wxUSE_STD_IOSTREAM + virtual bool Write(wxSTD ostream& str) const; +#endif + virtual bool Write(wxString& str) const; +#if wxUSE_STD_IOSTREAM + virtual bool Read(wxSTD istream& str); +#endif + virtual bool Read(wxString& str); + virtual wxString GetType() const { return wxT("stringlist"); }; + +protected: + wxStringList m_value; +}; + +IMPLEMENT_DYNAMIC_CLASS(wxVariantDataStringList, wxVariantData) + +void wxVariantDataStringList::SetValue(const wxStringList& value) +{ + m_value = value; +} + +bool wxVariantDataStringList::Eq(wxVariantData& data) const +{ + wxASSERT_MSG( (data.GetType() == wxT("stringlist")), wxT("wxVariantDataStringList::Eq: argument mismatch") ); + + wxVariantDataStringList& listData = (wxVariantDataStringList&) data; + wxStringList::compatibility_iterator node1 = m_value.GetFirst(); + wxStringList::compatibility_iterator node2 = listData.GetValue().GetFirst(); + while (node1 && node2) + { + wxString str1 ( node1->GetData() ); + wxString str2 ( node2->GetData() ); + if (str1 != str2) + return false; + node1 = node1->GetNext(); + node2 = node2->GetNext(); + } + if (node1 || node2) return false; + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataStringList::Write(wxSTD ostream& str) const +{ + wxString s; + Write(s); + str << (const char*) s.mb_str(); + return true; +} +#endif + +bool wxVariantDataStringList::Write(wxString& str) const +{ + str.Empty(); + wxStringList::compatibility_iterator node = m_value.GetFirst(); + while (node) + { + const wxChar* s = node->GetData(); + if (node != m_value.GetFirst()) + str += wxT(" "); + str += s; + node = node->GetNext(); + } + + return true; +} + +#if wxUSE_STD_IOSTREAM +bool wxVariantDataStringList::Read(wxSTD istream& WXUNUSED(str)) +{ + wxFAIL_MSG(wxT("Unimplemented")); + // TODO + return false; +} +#endif + +bool wxVariantDataStringList::Read(wxString& WXUNUSED(str)) +{ + wxFAIL_MSG(wxT("Unimplemented")); + // TODO + return false; +} + +#endif //2.4 compat + +#if WXWIN_COMPATIBILITY_2_4 + +wxVariant::wxVariant(const wxStringList& val, const wxString& name) +{ + m_data = new wxVariantDataStringList(val); + m_name = name; +} + +bool wxVariant::operator== (const wxStringList& value) const +{ + wxASSERT_MSG( (GetType() == wxT("stringlist")), wxT("Invalid type for == operator") ); + + wxVariantDataStringList other(value); + return (GetData()->Eq(other)); +} + +bool wxVariant::operator!= (const wxStringList& value) const +{ + wxASSERT_MSG( (GetType() == wxT("stringlist")), wxT("Invalid type for == operator") ); + + wxVariantDataStringList other(value); + return !(GetData()->Eq(other)); +} + +void wxVariant::operator= (const wxStringList& value) +{ + if (GetType() == wxT("stringlist") && + m_data->GetRefCount() == 1) + { + ((wxVariantDataStringList*)GetData())->SetValue(value); + } + else + { + UnRef(); + m_data = new wxVariantDataStringList(value); + } +} + +// wxVariant + +wxStringList& wxVariant::GetStringList() const +{ + wxASSERT( (GetType() == wxT("stringlist")) ); + + return (wxStringList&) ((wxVariantDataStringList*) m_data)->GetValue(); +} + +#endif + +// Treat a list variant as an array +wxVariant wxVariant::operator[] (size_t idx) const +{ +#if WXWIN_COMPATIBILITY_2_4 + wxASSERT_MSG( (GetType() == wxT("list") || GetType() == wxT("stringlist")), wxT("Invalid type for array operator") ); +#else + wxASSERT_MSG( GetType() == wxT("list"), wxT("Invalid type for array operator") ); +#endif + + if (GetType() == wxT("list")) + { + wxVariantDataList* data = (wxVariantDataList*) m_data; + wxASSERT_MSG( (idx < data->GetValue().GetCount()), wxT("Invalid index for array") ); + return * (wxVariant*) (data->GetValue().Item(idx)->GetData()); + } +#if WXWIN_COMPATIBILITY_2_4 + else if (GetType() == wxT("stringlist")) + { + wxVariantDataStringList* data = (wxVariantDataStringList*) m_data; + wxASSERT_MSG( (idx < data->GetValue().GetCount()), wxT("Invalid index for array") ); + + wxString str( (const wxChar*) (data->GetValue().Item(idx)->GetData()) ); + wxVariant variant( str ); + return variant; + } +#endif + return wxNullVariant; +} + +wxVariant& wxVariant::operator[] (size_t idx) +{ + // We can't return a reference to a variant for a string list, since the string + // is actually stored as a char*, not a variant. + + wxASSERT_MSG( (GetType() == wxT("list")), wxT("Invalid type for array operator") ); + + wxVariantDataList* data = (wxVariantDataList*) m_data; + wxASSERT_MSG( (idx < data->GetValue().GetCount()), wxT("Invalid index for array") ); + + return * (wxVariant*) (data->GetValue().Item(idx)->GetData()); +} + +// Return the number of elements in a list +size_t wxVariant::GetCount() const +{ +#if WXWIN_COMPATIBILITY_2_4 + wxASSERT_MSG( (GetType() == wxT("list") || GetType() == wxT("stringlist")), wxT("Invalid type for GetCount()") ); +#else + wxASSERT_MSG( GetType() == wxT("list"), wxT("Invalid type for GetCount()") ); +#endif + + if (GetType() == wxT("list")) + { + wxVariantDataList* data = (wxVariantDataList*) m_data; + return data->GetValue().GetCount(); + } +#if WXWIN_COMPATIBILITY_2_4 + else if (GetType() == wxT("stringlist")) + { + wxVariantDataStringList* data = (wxVariantDataStringList*) m_data; + return data->GetValue().GetCount(); + } +#endif + return 0; +} + +// ---------------------------------------------------------------------------- +// Type conversion +// ---------------------------------------------------------------------------- + +bool wxVariant::Convert(long* value) const +{ + wxString type(GetType()); + if (type == wxT("double")) + *value = (long) (((wxVariantDoubleData*)GetData())->GetValue()); + else if (type == wxT("long")) + *value = ((wxVariantDataLong*)GetData())->GetValue(); +#ifdef HAVE_BOOL + else if (type == wxT("bool")) + *value = (long) (((wxVariantDataBool*)GetData())->GetValue()); +#endif + else if (type == wxT("string")) + *value = wxAtol((const wxChar*) ((wxVariantDataString*)GetData())->GetValue()); + else + return false; + + return true; +} + +bool wxVariant::Convert(bool* value) const +{ + wxString type(GetType()); + if (type == wxT("double")) + *value = ((int) (((wxVariantDoubleData*)GetData())->GetValue()) != 0); + else if (type == wxT("long")) + *value = (((wxVariantDataLong*)GetData())->GetValue() != 0); +#ifdef HAVE_BOOL + else if (type == wxT("bool")) + *value = ((wxVariantDataBool*)GetData())->GetValue(); +#endif + else if (type == wxT("string")) + { + wxString val(((wxVariantDataString*)GetData())->GetValue()); + val.MakeLower(); + if (val == wxT("true") || val == wxT("yes") || val == wxT('1') ) + *value = true; + else if (val == wxT("false") || val == wxT("no") || val == wxT('0') ) + *value = false; + else + return false; + } + else + return false; + + return true; +} + +bool wxVariant::Convert(double* value) const +{ + wxString type(GetType()); + if (type == wxT("double")) + *value = ((wxVariantDoubleData*)GetData())->GetValue(); + else if (type == wxT("long")) + *value = (double) (((wxVariantDataLong*)GetData())->GetValue()); +#ifdef HAVE_BOOL + else if (type == wxT("bool")) + *value = (double) (((wxVariantDataBool*)GetData())->GetValue()); +#endif + else if (type == wxT("string")) + *value = (double) wxAtof((const wxChar*) ((wxVariantDataString*)GetData())->GetValue()); + else + return false; + + return true; +} + +bool wxVariant::Convert(wxChar* value) const +{ + wxString type(GetType()); + if (type == wxT("char")) + *value = ((wxVariantDataChar*)GetData())->GetValue(); + else if (type == wxT("long")) + *value = (char) (((wxVariantDataLong*)GetData())->GetValue()); +#ifdef HAVE_BOOL + else if (type == wxT("bool")) + *value = (char) (((wxVariantDataBool*)GetData())->GetValue()); +#endif + else + return false; + + return true; +} + +bool wxVariant::Convert(wxString* value) const +{ + *value = MakeString(); + return true; +} + +#if wxUSE_DATETIME +bool wxVariant::Convert(wxDateTime* value) const +{ + wxString type(GetType()); + if (type == wxT("datetime")) + { + *value = ((wxVariantDataDateTime*)GetData())->GetValue(); + return true; + } + // Fallback to string conversion + wxString val; + return Convert(&val) && + (value->ParseDateTime(val) || value->ParseDate(val) || value->ParseTime(val)); +} +#endif // wxUSE_DATETIME + +#endif // wxUSE_VARIANT diff --git a/Source/3rd Party/wx/src/common/wfstream.cpp b/Source/3rd Party/wx/src/common/wfstream.cpp index 332610c01..c5fe73be6 100644 --- a/Source/3rd Party/wx/src/common/wfstream.cpp +++ b/Source/3rd Party/wx/src/common/wfstream.cpp @@ -1,418 +1,418 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/fstream.cpp -// Purpose: "File stream" classes -// Author: Julian Smart -// Modified by: -// Created: 11/07/98 -// RCS-ID: $Id: wfstream.cpp 54418 2008-06-29 01:28:43Z VZ $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_STREAMS - -#include "wx/wfstream.h" - -#ifndef WX_PRECOMP - #include "wx/stream.h" -#endif - -#include - -#if wxUSE_FILE - -// ---------------------------------------------------------------------------- -// wxFileInputStream -// ---------------------------------------------------------------------------- - -wxFileInputStream::wxFileInputStream(const wxString& fileName) - : wxInputStream() -{ - m_file = new wxFile(fileName, wxFile::read); - m_file_destroy = true; - if ( !m_file->IsOpened() ) - m_lasterror = wxSTREAM_READ_ERROR; -} - -wxFileInputStream::wxFileInputStream() - : wxInputStream() -{ - m_file_destroy = false; - m_file = NULL; -} - -wxFileInputStream::wxFileInputStream(wxFile& file) -{ - m_file = &file; - m_file_destroy = false; -} - -wxFileInputStream::wxFileInputStream(int fd) -{ - m_file = new wxFile(fd); - m_file_destroy = true; -} - -wxFileInputStream::~wxFileInputStream() -{ - if (m_file_destroy) - delete m_file; -} - -wxFileOffset wxFileInputStream::GetLength() const -{ - return m_file->Length(); -} - -size_t wxFileInputStream::OnSysRead(void *buffer, size_t size) -{ - ssize_t ret = m_file->Read(buffer, size); - - // NB: we can't use a switch here because HP-UX CC doesn't allow - // switching over long long (which size_t is in 64bit mode) - - if ( !ret ) - { - // nothing read, so nothing more to read - m_lasterror = wxSTREAM_EOF; - } - else if ( ret == wxInvalidOffset ) - { - m_lasterror = wxSTREAM_READ_ERROR; - ret = 0; - } - else - { - // normal case - m_lasterror = wxSTREAM_NO_ERROR; - } - - return ret; -} - -wxFileOffset wxFileInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - return m_file->Seek(pos, mode); -} - -wxFileOffset wxFileInputStream::OnSysTell() const -{ - return m_file->Tell(); -} - -bool wxFileInputStream::IsOk() const -{ - return (wxStreamBase::IsOk() && m_file->IsOpened()); -} - -// ---------------------------------------------------------------------------- -// wxFileOutputStream -// ---------------------------------------------------------------------------- - -wxFileOutputStream::wxFileOutputStream(const wxString& fileName) -{ - m_file = new wxFile(fileName, wxFile::write); - m_file_destroy = true; - - if (!m_file->IsOpened()) - m_lasterror = wxSTREAM_WRITE_ERROR; -} - -wxFileOutputStream::wxFileOutputStream(wxFile& file) -{ - m_file = &file; - m_file_destroy = false; -} - -wxFileOutputStream::wxFileOutputStream() - : wxOutputStream() -{ - m_file_destroy = false; - m_file = NULL; -} - -wxFileOutputStream::wxFileOutputStream(int fd) -{ - m_file = new wxFile(fd); - m_file_destroy = true; -} - -wxFileOutputStream::~wxFileOutputStream() -{ - if (m_file_destroy) - { - Sync(); - delete m_file; - } -} - -size_t wxFileOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - size_t ret = m_file->Write(buffer, size); - - m_lasterror = m_file->Error() ? wxSTREAM_WRITE_ERROR : wxSTREAM_NO_ERROR; - - return ret; -} - -wxFileOffset wxFileOutputStream::OnSysTell() const -{ - return m_file->Tell(); -} - -wxFileOffset wxFileOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - return m_file->Seek(pos, mode); -} - -void wxFileOutputStream::Sync() -{ - wxOutputStream::Sync(); - m_file->Flush(); -} - -wxFileOffset wxFileOutputStream::GetLength() const -{ - return m_file->Length(); -} - -bool wxFileOutputStream::IsOk() const -{ - return (wxStreamBase::IsOk() && m_file->IsOpened()); -} - -// ---------------------------------------------------------------------------- -// wxTempFileOutputStream -// ---------------------------------------------------------------------------- - -wxTempFileOutputStream::wxTempFileOutputStream(const wxString& fileName) -{ - m_file = new wxTempFile(fileName); - - if (!m_file->IsOpened()) - m_lasterror = wxSTREAM_WRITE_ERROR; -} - -wxTempFileOutputStream::~wxTempFileOutputStream() -{ - if (m_file->IsOpened()) - Discard(); - delete m_file; -} - -size_t wxTempFileOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - if (IsOk() && m_file->Write(buffer, size)) - return size; - m_lasterror = wxSTREAM_WRITE_ERROR; - return 0; -} - -// ---------------------------------------------------------------------------- -// wxFileStream -// ---------------------------------------------------------------------------- - -wxFileStream::wxFileStream(const wxString& fileName) - : wxFileInputStream(), - wxFileOutputStream() -{ - wxFileOutputStream::m_file = - wxFileInputStream::m_file = new wxFile(fileName, wxFile::read_write); - - // this is a bit ugly as streams are symmetric but we still have to delete - // the file we created above exactly once so we decide to (arbitrarily) do - // it in wxFileInputStream - wxFileInputStream::m_file_destroy = true; -} - -#endif //wxUSE_FILE - -#if wxUSE_FFILE - -// ---------------------------------------------------------------------------- -// wxFFileInputStream -// ---------------------------------------------------------------------------- - -wxFFileInputStream::wxFFileInputStream(const wxString& fileName, - const wxChar *mode) - : wxInputStream() -{ - m_file = new wxFFile(fileName, mode); - m_file_destroy = true; - - if (!m_file->IsOpened()) - m_lasterror = wxSTREAM_WRITE_ERROR; -} - -wxFFileInputStream::wxFFileInputStream() - : wxInputStream() -{ - m_file = NULL; - m_file_destroy = false; -} - -wxFFileInputStream::wxFFileInputStream(wxFFile& file) -{ - m_file = &file; - m_file_destroy = false; -} - -wxFFileInputStream::wxFFileInputStream(FILE *file) -{ - m_file = new wxFFile(file); - m_file_destroy = true; -} - -wxFFileInputStream::~wxFFileInputStream() -{ - if (m_file_destroy) - delete m_file; -} - -wxFileOffset wxFFileInputStream::GetLength() const -{ - return m_file->Length(); -} - -size_t wxFFileInputStream::OnSysRead(void *buffer, size_t size) -{ - ssize_t ret = m_file->Read(buffer, size); - - // It is not safe to call Eof() if the file is not opened. - if (!m_file->IsOpened() || m_file->Eof()) - m_lasterror = wxSTREAM_EOF; - if (ret == wxInvalidOffset) - { - m_lasterror = wxSTREAM_READ_ERROR; - ret = 0; - } - - return ret; -} - -wxFileOffset wxFFileInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - return m_file->Seek(pos, mode) ? m_file->Tell() : wxInvalidOffset; -} - -wxFileOffset wxFFileInputStream::OnSysTell() const -{ - return m_file->Tell(); -} - -bool wxFFileInputStream::IsOk() const -{ - return (wxStreamBase::IsOk() && m_file->IsOpened()); -} - -// ---------------------------------------------------------------------------- -// wxFFileOutputStream -// ---------------------------------------------------------------------------- - -wxFFileOutputStream::wxFFileOutputStream(const wxString& fileName, - const wxChar *mode) -{ - m_file = new wxFFile(fileName, mode); - m_file_destroy = true; - - if (!m_file->IsOpened()) - { - m_lasterror = wxSTREAM_WRITE_ERROR; - } - else - { - if (m_file->Error()) - m_lasterror = wxSTREAM_WRITE_ERROR; - } -} - -wxFFileOutputStream::wxFFileOutputStream(wxFFile& file) -{ - m_file = &file; - m_file_destroy = false; -} - -wxFFileOutputStream::wxFFileOutputStream() - : wxOutputStream() -{ - m_file = NULL; - m_file_destroy = false; -} - -wxFFileOutputStream::wxFFileOutputStream(FILE *file) -{ - m_file = new wxFFile(file); - m_file_destroy = true; -} - -wxFFileOutputStream::~wxFFileOutputStream() -{ - if (m_file_destroy) - { - Sync(); - delete m_file; - } -} - -size_t wxFFileOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - size_t ret = m_file->Write(buffer, size); - // It is not safe to call Error() if the file is not opened. - if (!m_file->IsOpened() || m_file->Error()) - m_lasterror = wxSTREAM_WRITE_ERROR; - else - m_lasterror = wxSTREAM_NO_ERROR; - return ret; -} - -wxFileOffset wxFFileOutputStream::OnSysTell() const -{ - return m_file->Tell(); -} - -wxFileOffset wxFFileOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) -{ - return m_file->Seek(pos, mode) ? m_file->Tell() : wxInvalidOffset; -} - -void wxFFileOutputStream::Sync() -{ - wxOutputStream::Sync(); - m_file->Flush(); -} - -wxFileOffset wxFFileOutputStream::GetLength() const -{ - return m_file->Length(); -} - -bool wxFFileOutputStream::IsOk() const -{ - return (wxStreamBase::IsOk() && m_file->IsOpened()); -} - -// ---------------------------------------------------------------------------- -// wxFFileStream -// ---------------------------------------------------------------------------- - -wxFFileStream::wxFFileStream(const wxString& fileName) - : wxFFileInputStream(), - wxFFileOutputStream() -{ - wxFFileOutputStream::m_file = - wxFFileInputStream::m_file = new wxFFile(fileName, _T("w+b")); - - // see comment in wxFileStream ctor - wxFFileInputStream::m_file_destroy = true; -} - -#endif //wxUSE_FFILE - -#endif // wxUSE_STREAMS +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/fstream.cpp +// Purpose: "File stream" classes +// Author: Julian Smart +// Modified by: +// Created: 11/07/98 +// RCS-ID: $Id: wfstream.cpp 54418 2008-06-29 01:28:43Z VZ $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STREAMS + +#include "wx/wfstream.h" + +#ifndef WX_PRECOMP + #include "wx/stream.h" +#endif + +#include + +#if wxUSE_FILE + +// ---------------------------------------------------------------------------- +// wxFileInputStream +// ---------------------------------------------------------------------------- + +wxFileInputStream::wxFileInputStream(const wxString& fileName) + : wxInputStream() +{ + m_file = new wxFile(fileName, wxFile::read); + m_file_destroy = true; + if ( !m_file->IsOpened() ) + m_lasterror = wxSTREAM_READ_ERROR; +} + +wxFileInputStream::wxFileInputStream() + : wxInputStream() +{ + m_file_destroy = false; + m_file = NULL; +} + +wxFileInputStream::wxFileInputStream(wxFile& file) +{ + m_file = &file; + m_file_destroy = false; +} + +wxFileInputStream::wxFileInputStream(int fd) +{ + m_file = new wxFile(fd); + m_file_destroy = true; +} + +wxFileInputStream::~wxFileInputStream() +{ + if (m_file_destroy) + delete m_file; +} + +wxFileOffset wxFileInputStream::GetLength() const +{ + return m_file->Length(); +} + +size_t wxFileInputStream::OnSysRead(void *buffer, size_t size) +{ + ssize_t ret = m_file->Read(buffer, size); + + // NB: we can't use a switch here because HP-UX CC doesn't allow + // switching over long long (which size_t is in 64bit mode) + + if ( !ret ) + { + // nothing read, so nothing more to read + m_lasterror = wxSTREAM_EOF; + } + else if ( ret == wxInvalidOffset ) + { + m_lasterror = wxSTREAM_READ_ERROR; + ret = 0; + } + else + { + // normal case + m_lasterror = wxSTREAM_NO_ERROR; + } + + return ret; +} + +wxFileOffset wxFileInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + return m_file->Seek(pos, mode); +} + +wxFileOffset wxFileInputStream::OnSysTell() const +{ + return m_file->Tell(); +} + +bool wxFileInputStream::IsOk() const +{ + return (wxStreamBase::IsOk() && m_file->IsOpened()); +} + +// ---------------------------------------------------------------------------- +// wxFileOutputStream +// ---------------------------------------------------------------------------- + +wxFileOutputStream::wxFileOutputStream(const wxString& fileName) +{ + m_file = new wxFile(fileName, wxFile::write); + m_file_destroy = true; + + if (!m_file->IsOpened()) + m_lasterror = wxSTREAM_WRITE_ERROR; +} + +wxFileOutputStream::wxFileOutputStream(wxFile& file) +{ + m_file = &file; + m_file_destroy = false; +} + +wxFileOutputStream::wxFileOutputStream() + : wxOutputStream() +{ + m_file_destroy = false; + m_file = NULL; +} + +wxFileOutputStream::wxFileOutputStream(int fd) +{ + m_file = new wxFile(fd); + m_file_destroy = true; +} + +wxFileOutputStream::~wxFileOutputStream() +{ + if (m_file_destroy) + { + Sync(); + delete m_file; + } +} + +size_t wxFileOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + size_t ret = m_file->Write(buffer, size); + + m_lasterror = m_file->Error() ? wxSTREAM_WRITE_ERROR : wxSTREAM_NO_ERROR; + + return ret; +} + +wxFileOffset wxFileOutputStream::OnSysTell() const +{ + return m_file->Tell(); +} + +wxFileOffset wxFileOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + return m_file->Seek(pos, mode); +} + +void wxFileOutputStream::Sync() +{ + wxOutputStream::Sync(); + m_file->Flush(); +} + +wxFileOffset wxFileOutputStream::GetLength() const +{ + return m_file->Length(); +} + +bool wxFileOutputStream::IsOk() const +{ + return (wxStreamBase::IsOk() && m_file->IsOpened()); +} + +// ---------------------------------------------------------------------------- +// wxTempFileOutputStream +// ---------------------------------------------------------------------------- + +wxTempFileOutputStream::wxTempFileOutputStream(const wxString& fileName) +{ + m_file = new wxTempFile(fileName); + + if (!m_file->IsOpened()) + m_lasterror = wxSTREAM_WRITE_ERROR; +} + +wxTempFileOutputStream::~wxTempFileOutputStream() +{ + if (m_file->IsOpened()) + Discard(); + delete m_file; +} + +size_t wxTempFileOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + if (IsOk() && m_file->Write(buffer, size)) + return size; + m_lasterror = wxSTREAM_WRITE_ERROR; + return 0; +} + +// ---------------------------------------------------------------------------- +// wxFileStream +// ---------------------------------------------------------------------------- + +wxFileStream::wxFileStream(const wxString& fileName) + : wxFileInputStream(), + wxFileOutputStream() +{ + wxFileOutputStream::m_file = + wxFileInputStream::m_file = new wxFile(fileName, wxFile::read_write); + + // this is a bit ugly as streams are symmetric but we still have to delete + // the file we created above exactly once so we decide to (arbitrarily) do + // it in wxFileInputStream + wxFileInputStream::m_file_destroy = true; +} + +#endif //wxUSE_FILE + +#if wxUSE_FFILE + +// ---------------------------------------------------------------------------- +// wxFFileInputStream +// ---------------------------------------------------------------------------- + +wxFFileInputStream::wxFFileInputStream(const wxString& fileName, + const wxChar *mode) + : wxInputStream() +{ + m_file = new wxFFile(fileName, mode); + m_file_destroy = true; + + if (!m_file->IsOpened()) + m_lasterror = wxSTREAM_WRITE_ERROR; +} + +wxFFileInputStream::wxFFileInputStream() + : wxInputStream() +{ + m_file = NULL; + m_file_destroy = false; +} + +wxFFileInputStream::wxFFileInputStream(wxFFile& file) +{ + m_file = &file; + m_file_destroy = false; +} + +wxFFileInputStream::wxFFileInputStream(FILE *file) +{ + m_file = new wxFFile(file); + m_file_destroy = true; +} + +wxFFileInputStream::~wxFFileInputStream() +{ + if (m_file_destroy) + delete m_file; +} + +wxFileOffset wxFFileInputStream::GetLength() const +{ + return m_file->Length(); +} + +size_t wxFFileInputStream::OnSysRead(void *buffer, size_t size) +{ + ssize_t ret = m_file->Read(buffer, size); + + // It is not safe to call Eof() if the file is not opened. + if (!m_file->IsOpened() || m_file->Eof()) + m_lasterror = wxSTREAM_EOF; + if (ret == wxInvalidOffset) + { + m_lasterror = wxSTREAM_READ_ERROR; + ret = 0; + } + + return ret; +} + +wxFileOffset wxFFileInputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + return m_file->Seek(pos, mode) ? m_file->Tell() : wxInvalidOffset; +} + +wxFileOffset wxFFileInputStream::OnSysTell() const +{ + return m_file->Tell(); +} + +bool wxFFileInputStream::IsOk() const +{ + return (wxStreamBase::IsOk() && m_file->IsOpened()); +} + +// ---------------------------------------------------------------------------- +// wxFFileOutputStream +// ---------------------------------------------------------------------------- + +wxFFileOutputStream::wxFFileOutputStream(const wxString& fileName, + const wxChar *mode) +{ + m_file = new wxFFile(fileName, mode); + m_file_destroy = true; + + if (!m_file->IsOpened()) + { + m_lasterror = wxSTREAM_WRITE_ERROR; + } + else + { + if (m_file->Error()) + m_lasterror = wxSTREAM_WRITE_ERROR; + } +} + +wxFFileOutputStream::wxFFileOutputStream(wxFFile& file) +{ + m_file = &file; + m_file_destroy = false; +} + +wxFFileOutputStream::wxFFileOutputStream() + : wxOutputStream() +{ + m_file = NULL; + m_file_destroy = false; +} + +wxFFileOutputStream::wxFFileOutputStream(FILE *file) +{ + m_file = new wxFFile(file); + m_file_destroy = true; +} + +wxFFileOutputStream::~wxFFileOutputStream() +{ + if (m_file_destroy) + { + Sync(); + delete m_file; + } +} + +size_t wxFFileOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + size_t ret = m_file->Write(buffer, size); + // It is not safe to call Error() if the file is not opened. + if (!m_file->IsOpened() || m_file->Error()) + m_lasterror = wxSTREAM_WRITE_ERROR; + else + m_lasterror = wxSTREAM_NO_ERROR; + return ret; +} + +wxFileOffset wxFFileOutputStream::OnSysTell() const +{ + return m_file->Tell(); +} + +wxFileOffset wxFFileOutputStream::OnSysSeek(wxFileOffset pos, wxSeekMode mode) +{ + return m_file->Seek(pos, mode) ? m_file->Tell() : wxInvalidOffset; +} + +void wxFFileOutputStream::Sync() +{ + wxOutputStream::Sync(); + m_file->Flush(); +} + +wxFileOffset wxFFileOutputStream::GetLength() const +{ + return m_file->Length(); +} + +bool wxFFileOutputStream::IsOk() const +{ + return (wxStreamBase::IsOk() && m_file->IsOpened()); +} + +// ---------------------------------------------------------------------------- +// wxFFileStream +// ---------------------------------------------------------------------------- + +wxFFileStream::wxFFileStream(const wxString& fileName) + : wxFFileInputStream(), + wxFFileOutputStream() +{ + wxFFileOutputStream::m_file = + wxFFileInputStream::m_file = new wxFFile(fileName, _T("w+b")); + + // see comment in wxFileStream ctor + wxFFileInputStream::m_file_destroy = true; +} + +#endif //wxUSE_FFILE + +#endif // wxUSE_STREAMS diff --git a/Source/3rd Party/wx/src/common/wincmn.cpp b/Source/3rd Party/wx/src/common/wincmn.cpp index 1802f8b3b..03394bf2b 100644 --- a/Source/3rd Party/wx/src/common/wincmn.cpp +++ b/Source/3rd Party/wx/src/common/wincmn.cpp @@ -1,3255 +1,3255 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/window.cpp -// Purpose: common (to all ports) wxWindow functions -// Author: Julian Smart, Vadim Zeitlin -// Modified by: -// Created: 13/07/98 -// RCS-ID: $Id: wincmn.cpp 63032 2009-12-31 13:37:24Z VZ $ -// Copyright: (c) wxWidgets team -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// ============================================================================ -// declarations -// ============================================================================ - -// ---------------------------------------------------------------------------- -// headers -// ---------------------------------------------------------------------------- - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#ifndef WX_PRECOMP - #include "wx/string.h" - #include "wx/log.h" - #include "wx/intl.h" - #include "wx/frame.h" - #include "wx/window.h" - #include "wx/control.h" - #include "wx/checkbox.h" - #include "wx/radiobut.h" - #include "wx/statbox.h" - #include "wx/textctrl.h" - #include "wx/settings.h" - #include "wx/dialog.h" - #include "wx/msgdlg.h" - #include "wx/statusbr.h" - #include "wx/toolbar.h" - #include "wx/dcclient.h" - #include "wx/scrolbar.h" - #include "wx/layout.h" - #include "wx/sizer.h" -#endif //WX_PRECOMP - -#if wxUSE_DRAG_AND_DROP - #include "wx/dnd.h" -#endif // wxUSE_DRAG_AND_DROP - -#if wxUSE_ACCESSIBILITY - #include "wx/access.h" -#endif - -#if wxUSE_HELP - #include "wx/cshelp.h" -#endif // wxUSE_HELP - -#if wxUSE_TOOLTIPS - #include "wx/tooltip.h" -#endif // wxUSE_TOOLTIPS - -#if wxUSE_CARET - #include "wx/caret.h" -#endif // wxUSE_CARET - -#if wxUSE_SYSTEM_OPTIONS - #include "wx/sysopt.h" -#endif - -// For reporting compile- and runtime version of GTK+ in the ctrl+alt+mclick dialog. -// The gtk includes don't pull any other headers in, at least not on my system - MR -#ifdef __WXGTK__ - #ifdef __WXGTK20__ - #include - #else - #include - #endif - extern const unsigned int gtk_major_version; - extern const unsigned int gtk_minor_version; - extern const unsigned int gtk_micro_version; -#endif - -#include "wx/platinfo.h" - -// Windows List -WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows; - -// ---------------------------------------------------------------------------- -// static data -// ---------------------------------------------------------------------------- - -#if defined(__WXPALMOS__) -int wxWindowBase::ms_lastControlId = 32767; -#elif defined(__WXPM__) -int wxWindowBase::ms_lastControlId = 2000; -#else -int wxWindowBase::ms_lastControlId = -200; -#endif - -IMPLEMENT_ABSTRACT_CLASS(wxWindowBase, wxEvtHandler) - -// ---------------------------------------------------------------------------- -// event table -// ---------------------------------------------------------------------------- - -BEGIN_EVENT_TABLE(wxWindowBase, wxEvtHandler) - EVT_SYS_COLOUR_CHANGED(wxWindowBase::OnSysColourChanged) - EVT_INIT_DIALOG(wxWindowBase::OnInitDialog) - EVT_MIDDLE_DOWN(wxWindowBase::OnMiddleClick) - -#if wxUSE_HELP - EVT_HELP(wxID_ANY, wxWindowBase::OnHelp) -#endif // wxUSE_HELP - -END_EVENT_TABLE() - -// ============================================================================ -// implementation of the common functionality of the wxWindow class -// ============================================================================ - -// ---------------------------------------------------------------------------- -// initialization -// ---------------------------------------------------------------------------- - -// the default initialization -wxWindowBase::wxWindowBase() -{ - // no window yet, no parent nor children - m_parent = (wxWindow *)NULL; - m_windowId = wxID_ANY; - - // no constraints on the minimal window size - m_minWidth = - m_maxWidth = wxDefaultCoord; - m_minHeight = - m_maxHeight = wxDefaultCoord; - - // invalidiated cache value - m_bestSizeCache = wxDefaultSize; - - // window are created enabled and visible by default - m_isShown = - m_isEnabled = true; - - // the default event handler is just this window - m_eventHandler = this; - -#if wxUSE_VALIDATORS - // no validator - m_windowValidator = (wxValidator *) NULL; -#endif // wxUSE_VALIDATORS - - // the colours/fonts are default for now, so leave m_font, - // m_backgroundColour and m_foregroundColour uninitialized and set those - m_hasBgCol = - m_hasFgCol = - m_hasFont = false; - m_inheritBgCol = - m_inheritFgCol = - m_inheritFont = false; - - // no style bits - m_exStyle = - m_windowStyle = 0; - - m_backgroundStyle = wxBG_STYLE_SYSTEM; - -#if wxUSE_CONSTRAINTS - // no constraints whatsoever - m_constraints = (wxLayoutConstraints *) NULL; - m_constraintsInvolvedIn = (wxWindowList *) NULL; -#endif // wxUSE_CONSTRAINTS - - m_windowSizer = (wxSizer *) NULL; - m_containingSizer = (wxSizer *) NULL; - m_autoLayout = false; - -#if wxUSE_DRAG_AND_DROP - m_dropTarget = (wxDropTarget *)NULL; -#endif // wxUSE_DRAG_AND_DROP - -#if wxUSE_TOOLTIPS - m_tooltip = (wxToolTip *)NULL; -#endif // wxUSE_TOOLTIPS - -#if wxUSE_CARET - m_caret = (wxCaret *)NULL; -#endif // wxUSE_CARET - -#if wxUSE_PALETTE - m_hasCustomPalette = false; -#endif // wxUSE_PALETTE - -#if wxUSE_ACCESSIBILITY - m_accessible = NULL; -#endif - - m_virtualSize = wxDefaultSize; - - m_scrollHelper = (wxScrollHelper *) NULL; - - m_minVirtualWidth = - m_maxVirtualWidth = wxDefaultCoord; - m_minVirtualHeight = - m_maxVirtualHeight = wxDefaultCoord; - - m_windowVariant = wxWINDOW_VARIANT_NORMAL; -#if wxUSE_SYSTEM_OPTIONS - if ( wxSystemOptions::HasOption(wxWINDOW_DEFAULT_VARIANT) ) - { - m_windowVariant = (wxWindowVariant) wxSystemOptions::GetOptionInt( wxWINDOW_DEFAULT_VARIANT ) ; - } -#endif - - // Whether we're using the current theme for this window (wxGTK only for now) - m_themeEnabled = false; - - // VZ: this one shouldn't exist... - m_isBeingDeleted = false; -} - -// common part of window creation process -bool wxWindowBase::CreateBase(wxWindowBase *parent, - wxWindowID id, - const wxPoint& WXUNUSED(pos), - const wxSize& WXUNUSED(size), - long style, - const wxValidator& wxVALIDATOR_PARAM(validator), - const wxString& name) -{ -#if wxUSE_STATBOX - // wxGTK doesn't allow to create controls with static box as the parent so - // this will result in a crash when the program is ported to wxGTK so warn - // the user about it - - // if you get this assert, the correct solution is to create the controls - // as siblings of the static box - wxASSERT_MSG( !parent || !wxDynamicCast(parent, wxStaticBox), - _T("wxStaticBox can't be used as a window parent!") ); -#endif // wxUSE_STATBOX - - // ids are limited to 16 bits under MSW so if you care about portability, - // it's not a good idea to use ids out of this range (and negative ids are - // reserved for wxWidgets own usage) - wxASSERT_MSG( id == wxID_ANY || (id >= 0 && id < 32767), - _T("invalid id value") ); - - // generate a new id if the user doesn't care about it - m_windowId = id == wxID_ANY ? NewControlId() : id; - - // don't use SetWindowStyleFlag() here, this function should only be called - // to change the flag after creation as it tries to reflect the changes in - // flags by updating the window dynamically and we don't need this here - m_windowStyle = style; - - SetName(name); - SetParent(parent); - -#if wxUSE_VALIDATORS - SetValidator(validator); -#endif // wxUSE_VALIDATORS - - // if the parent window has wxWS_EX_VALIDATE_RECURSIVELY set, we want to - // have it too - like this it's possible to set it only in the top level - // dialog/frame and all children will inherit it by defult - if ( parent && (parent->GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) ) - { - SetExtraStyle(GetExtraStyle() | wxWS_EX_VALIDATE_RECURSIVELY); - } - - return true; -} - -bool wxWindowBase::ToggleWindowStyle(int flag) -{ - wxASSERT_MSG( flag, _T("flags with 0 value can't be toggled") ); - - bool rc; - long style = GetWindowStyleFlag(); - if ( style & flag ) - { - style &= ~flag; - rc = false; - } - else // currently off - { - style |= flag; - rc = true; - } - - SetWindowStyleFlag(style); - - return rc; -} - -// ---------------------------------------------------------------------------- -// destruction -// ---------------------------------------------------------------------------- - -// common clean up -wxWindowBase::~wxWindowBase() -{ - wxASSERT_MSG( GetCapture() != this, wxT("attempt to destroy window with mouse capture") ); - - // FIXME if these 2 cases result from programming errors in the user code - // we should probably assert here instead of silently fixing them - - // Just in case the window has been Closed, but we're then deleting - // immediately: don't leave dangling pointers. - wxPendingDelete.DeleteObject(this); - - // Just in case we've loaded a top-level window via LoadNativeDialog but - // we weren't a dialog class - wxTopLevelWindows.DeleteObject((wxWindow*)this); - - wxASSERT_MSG( GetChildren().GetCount() == 0, wxT("children not destroyed") ); - - // reset the top-level parent's default item if it is this widget - if ( m_parent ) - { - wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent((wxWindow*)this), - wxTopLevelWindow); - - if ( tlw ) - { - wxWindow* tmpDefaultItem = tlw->GetTmpDefaultItem(); - if ( tmpDefaultItem == this ) - tlw->SetTmpDefaultItem(NULL); - else if ( tmpDefaultItem ) - { - // A temporary default item masks the real default item, so - // temporarily unset the temporary default item so we can access the - // real default item. - tlw->SetTmpDefaultItem(NULL); - - if ( tlw->GetDefaultItem() == this ) - tlw->SetDefaultItem(NULL); - - // Set the temporary default item back. - tlw->SetTmpDefaultItem(tmpDefaultItem); - } - else if ( tlw->GetDefaultItem() == this ) - tlw->SetDefaultItem(NULL); - } - } - - // reset the dangling pointer our parent window may keep to us - if ( m_parent ) - { - m_parent->RemoveChild(this); - } - -#if wxUSE_CARET - delete m_caret; -#endif // wxUSE_CARET - -#if wxUSE_VALIDATORS - delete m_windowValidator; -#endif // wxUSE_VALIDATORS - -#if wxUSE_CONSTRAINTS - // Have to delete constraints/sizer FIRST otherwise sizers may try to look - // at deleted windows as they delete themselves. - DeleteRelatedConstraints(); - - if ( m_constraints ) - { - // This removes any dangling pointers to this window in other windows' - // constraintsInvolvedIn lists. - UnsetConstraints(m_constraints); - delete m_constraints; - m_constraints = NULL; - } -#endif // wxUSE_CONSTRAINTS - - if ( m_containingSizer ) - m_containingSizer->Detach( (wxWindow*)this ); - - delete m_windowSizer; - -#if wxUSE_DRAG_AND_DROP - delete m_dropTarget; -#endif // wxUSE_DRAG_AND_DROP - -#if wxUSE_TOOLTIPS - delete m_tooltip; -#endif // wxUSE_TOOLTIPS - -#if wxUSE_ACCESSIBILITY - delete m_accessible; -#endif - -#if wxUSE_HELP - // NB: this has to be called unconditionally, because we don't - // know whether this window has associated help text or not - wxHelpProvider *helpProvider = wxHelpProvider::Get(); - if ( helpProvider ) - helpProvider->RemoveHelp(this); -#endif -} - -void wxWindowBase::SendDestroyEvent() -{ - wxWindowDestroyEvent event; - event.SetEventObject(this); - event.SetId(GetId()); - GetEventHandler()->ProcessEvent(event); -} - -bool wxWindowBase::Destroy() -{ - delete this; - - return true; -} - -bool wxWindowBase::Close(bool force) -{ - wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId); - event.SetEventObject(this); - event.SetCanVeto(!force); - - // return false if window wasn't closed because the application vetoed the - // close event - return GetEventHandler()->ProcessEvent(event) && !event.GetVeto(); -} - -bool wxWindowBase::DestroyChildren() -{ - wxWindowList::compatibility_iterator node; - for ( ;; ) - { - // we iterate until the list becomes empty - node = GetChildren().GetFirst(); - if ( !node ) - break; - - wxWindow *child = node->GetData(); - - // note that we really want to call delete and not ->Destroy() here - // because we want to delete the child immediately, before we are - // deleted, and delayed deletion would result in problems as our (top - // level) child could outlive its parent - delete child; - - wxASSERT_MSG( !GetChildren().Find(child), - wxT("child didn't remove itself using RemoveChild()") ); - } - - return true; -} - -// ---------------------------------------------------------------------------- -// size/position related methods -// ---------------------------------------------------------------------------- - -// centre the window with respect to its parent in either (or both) directions -void wxWindowBase::DoCentre(int dir) -{ - wxCHECK_RET( !(dir & wxCENTRE_ON_SCREEN) && GetParent(), - _T("this method only implements centering child windows") ); - - SetSize(GetRect().CentreIn(GetParent()->GetClientSize(), dir)); -} - -// fits the window around the children -void wxWindowBase::Fit() -{ - if ( !GetChildren().empty() ) - { - SetSize(GetBestSize()); - } - //else: do nothing if we have no children -} - -// fits virtual size (ie. scrolled area etc.) around children -void wxWindowBase::FitInside() -{ - if ( GetChildren().GetCount() > 0 ) - { - SetVirtualSize( GetBestVirtualSize() ); - } -} - -// On Mac, scrollbars are explicitly children. -#ifdef __WXMAC__ -static bool wxHasRealChildren(const wxWindowBase* win) -{ - int realChildCount = 0; - - for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - wxWindow *win = node->GetData(); - if ( !win->IsTopLevel() && win->IsShown() && !win->IsKindOf(CLASSINFO(wxScrollBar))) - realChildCount ++; - } - return (realChildCount > 0); -} -#endif - -void wxWindowBase::InvalidateBestSize() -{ - m_bestSizeCache = wxDefaultSize; - - // parent's best size calculation may depend on its children's - // as long as child window we are in is not top level window itself - // (because the TLW size is never resized automatically) - // so let's invalidate it as well to be safe: - if (m_parent && !IsTopLevel()) - m_parent->InvalidateBestSize(); -} - -// return the size best suited for the current window -wxSize wxWindowBase::DoGetBestSize() const -{ - wxSize best; - - if ( m_windowSizer ) - { - // Adjust to window size, since the return value of GetWindowSizeForVirtualSize is - // expressed in window and not client size - wxSize minSize = m_windowSizer->GetMinSize(); - wxSize size(GetSize()); - wxSize clientSize(GetClientSize()); - - wxSize minWindowSize(minSize.x + size.x - clientSize.x, - minSize.y + size.y - clientSize.y); - - best = GetWindowSizeForVirtualSize(minWindowSize); - - return best; - } -#if wxUSE_CONSTRAINTS - else if ( m_constraints ) - { - wxConstCast(this, wxWindowBase)->SatisfyConstraints(); - - // our minimal acceptable size is such that all our windows fit inside - int maxX = 0, - maxY = 0; - - for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - wxLayoutConstraints *c = node->GetData()->GetConstraints(); - if ( !c ) - { - // it's not normal that we have an unconstrained child, but - // what can we do about it? - continue; - } - - int x = c->right.GetValue(), - y = c->bottom.GetValue(); - - if ( x > maxX ) - maxX = x; - - if ( y > maxY ) - maxY = y; - - // TODO: we must calculate the overlaps somehow, otherwise we - // will never return a size bigger than the current one :-( - } - - best = wxSize(maxX, maxY); - } -#endif // wxUSE_CONSTRAINTS - else if ( !GetChildren().empty() -#ifdef __WXMAC__ - && wxHasRealChildren(this) -#endif - ) - { - // our minimal acceptable size is such that all our visible child - // windows fit inside - int maxX = 0, - maxY = 0; - - for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - wxWindow *win = node->GetData(); - if ( win->IsTopLevel() - || !win->IsShown() -#if wxUSE_STATUSBAR - || wxDynamicCast(win, wxStatusBar) -#endif // wxUSE_STATUSBAR - ) - { - // dialogs and frames lie in different top level windows - - // don't deal with them here; as for the status bars, they - // don't lie in the client area at all - continue; - } - - int wx, wy, ww, wh; - win->GetPosition(&wx, &wy); - - // if the window hadn't been positioned yet, assume that it is in - // the origin - if ( wx == wxDefaultCoord ) - wx = 0; - if ( wy == wxDefaultCoord ) - wy = 0; - - win->GetSize(&ww, &wh); - if ( wx + ww > maxX ) - maxX = wx + ww; - if ( wy + wh > maxY ) - maxY = wy + wh; - } - - best = wxSize(maxX, maxY); - } - else // ! has children - { - // for a generic window there is no natural best size so, if the - // minimal size is not set, use the current size but take care to - // remember it as minimal size for the next time because our best size - // should be constant: otherwise we could get into a situation when the - // window is initially at some size, then expanded to a larger size and - // then, when the containing window is shrunk back (because our initial - // best size had been used for computing the parent min size), we can't - // be shrunk back any more because our best size is now bigger - wxSize size = GetMinSize(); - if ( !size.IsFullySpecified() ) - { - size.SetDefaults(GetSize()); - wxConstCast(this, wxWindowBase)->SetMinSize(size); - } - - // return as-is, unadjusted by the client size difference. - return size; - } - - // Add any difference between size and client size - wxSize diff = GetSize() - GetClientSize(); - best.x += wxMax(0, diff.x); - best.y += wxMax(0, diff.y); - - return best; -} - -// helper of GetWindowBorderSize(): as many ports don't implement support for -// wxSYS_BORDER/EDGE_X/Y metrics in their wxSystemSettings, use hard coded -// fallbacks in this case -static int wxGetMetricOrDefault(wxSystemMetric what) -{ - int rc = wxSystemSettings::GetMetric(what); - if ( rc == -1 ) - { - switch ( what ) - { - case wxSYS_BORDER_X: - case wxSYS_BORDER_Y: - // 2D border is by default 1 pixel wide - rc = 1; - break; - - case wxSYS_EDGE_X: - case wxSYS_EDGE_Y: - // 3D borders are by default 2 pixels - rc = 2; - break; - - default: - wxFAIL_MSG( _T("unexpected wxGetMetricOrDefault() argument") ); - rc = 0; - } - } - - return rc; -} - -wxSize wxWindowBase::GetWindowBorderSize() const -{ - wxSize size; - - switch ( GetBorder() ) - { - case wxBORDER_NONE: - // nothing to do, size is already (0, 0) - break; - - case wxBORDER_SIMPLE: - case wxBORDER_STATIC: - size.x = wxGetMetricOrDefault(wxSYS_BORDER_X); - size.y = wxGetMetricOrDefault(wxSYS_BORDER_Y); - break; - - case wxBORDER_SUNKEN: - case wxBORDER_RAISED: - size.x = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_X), - wxGetMetricOrDefault(wxSYS_BORDER_X)); - size.y = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_Y), - wxGetMetricOrDefault(wxSYS_BORDER_Y)); - break; - - case wxBORDER_DOUBLE: - size.x = wxGetMetricOrDefault(wxSYS_EDGE_X) + - wxGetMetricOrDefault(wxSYS_BORDER_X); - size.y = wxGetMetricOrDefault(wxSYS_EDGE_Y) + - wxGetMetricOrDefault(wxSYS_BORDER_Y); - break; - - default: - wxFAIL_MSG(_T("Unknown border style.")); - break; - } - - // we have borders on both sides - return size*2; -} - -wxSize wxWindowBase::GetEffectiveMinSize() const -{ - // merge the best size with the min size, giving priority to the min size - wxSize min = GetMinSize(); - if (min.x == wxDefaultCoord || min.y == wxDefaultCoord) - { - wxSize best = GetBestSize(); - if (min.x == wxDefaultCoord) min.x = best.x; - if (min.y == wxDefaultCoord) min.y = best.y; - } - return min; -} - - -void wxWindowBase::SetInitialSize(const wxSize& size) -{ - // Set the min size to the size passed in. This will usually either be - // wxDefaultSize or the size passed to this window's ctor/Create function. - SetMinSize(size); - - // Merge the size with the best size if needed - wxSize best = GetEffectiveMinSize(); - - // If the current size doesn't match then change it - if (GetSize() != best) - SetSize(best); -} - - -// by default the origin is not shifted -wxPoint wxWindowBase::GetClientAreaOrigin() const -{ - return wxPoint(0,0); -} - -wxSize wxWindowBase::ClientToWindowSize(const wxSize& size) const -{ - const wxSize diff(GetSize() - GetClientSize()); - - return wxSize(size.x == -1 ? -1 : size.x + diff.x, - size.y == -1 ? -1 : size.y + diff.y); -} - -wxSize wxWindowBase::WindowToClientSize(const wxSize& size) const -{ - const wxSize diff(GetSize() - GetClientSize()); - - return wxSize(size.x == -1 ? -1 : size.x - diff.x, - size.y == -1 ? -1 : size.y - diff.y); -} - -void wxWindowBase::SetWindowVariant( wxWindowVariant variant ) -{ - if ( m_windowVariant != variant ) - { - m_windowVariant = variant; - - DoSetWindowVariant(variant); - } -} - -void wxWindowBase::DoSetWindowVariant( wxWindowVariant variant ) -{ - // adjust the font height to correspond to our new variant (notice that - // we're only called if something really changed) - wxFont font = GetFont(); - int size = font.GetPointSize(); - switch ( variant ) - { - case wxWINDOW_VARIANT_NORMAL: - break; - - case wxWINDOW_VARIANT_SMALL: - size *= 3; - size /= 4; - break; - - case wxWINDOW_VARIANT_MINI: - size *= 2; - size /= 3; - break; - - case wxWINDOW_VARIANT_LARGE: - size *= 5; - size /= 4; - break; - - default: - wxFAIL_MSG(_T("unexpected window variant")); - break; - } - - font.SetPointSize(size); - SetFont(font); -} - -void wxWindowBase::DoSetSizeHints( int minW, int minH, - int maxW, int maxH, - int WXUNUSED(incW), int WXUNUSED(incH) ) -{ - wxCHECK_RET( (minW == wxDefaultCoord || maxW == wxDefaultCoord || minW <= maxW) && - (minH == wxDefaultCoord || maxH == wxDefaultCoord || minH <= maxH), - _T("min width/height must be less than max width/height!") ); - - m_minWidth = minW; - m_maxWidth = maxW; - m_minHeight = minH; - m_maxHeight = maxH; -} - - -void wxWindowBase::SetVirtualSizeHints( int minW, int minH, - int maxW, int maxH ) -{ - m_minVirtualWidth = minW; - m_maxVirtualWidth = maxW; - m_minVirtualHeight = minH; - m_maxVirtualHeight = maxH; -} - -void wxWindowBase::DoSetVirtualSize( int x, int y ) -{ - if ( m_minVirtualWidth != wxDefaultCoord && m_minVirtualWidth > x ) - x = m_minVirtualWidth; - if ( m_maxVirtualWidth != wxDefaultCoord && m_maxVirtualWidth < x ) - x = m_maxVirtualWidth; - if ( m_minVirtualHeight != wxDefaultCoord && m_minVirtualHeight > y ) - y = m_minVirtualHeight; - if ( m_maxVirtualHeight != wxDefaultCoord && m_maxVirtualHeight < y ) - y = m_maxVirtualHeight; - - m_virtualSize = wxSize(x, y); -} - -wxSize wxWindowBase::DoGetVirtualSize() const -{ - // we should use the entire client area so if it is greater than our - // virtual size, expand it to fit (otherwise if the window is big enough we - // wouldn't be using parts of it) - wxSize size = GetClientSize(); - if ( m_virtualSize.x > size.x ) - size.x = m_virtualSize.x; - - if ( m_virtualSize.y >= size.y ) - size.y = m_virtualSize.y; - - return size; -} - -void wxWindowBase::DoGetScreenPosition(int *x, int *y) const -{ - // screen position is the same as (0, 0) in client coords for non TLWs (and - // TLWs override this method) - if ( x ) - *x = 0; - if ( y ) - *y = 0; - - ClientToScreen(x, y); -} - -// ---------------------------------------------------------------------------- -// show/hide/enable/disable the window -// ---------------------------------------------------------------------------- - -bool wxWindowBase::Show(bool show) -{ - if ( show != m_isShown ) - { - m_isShown = show; - - return true; - } - else - { - return false; - } -} - -bool wxWindowBase::Enable(bool enable) -{ - if ( enable != m_isEnabled ) - { - m_isEnabled = enable; - - return true; - } - else - { - return false; - } -} - -bool wxWindowBase::IsShownOnScreen() const -{ - // A window is shown on screen if it itself is shown and so are all its - // parents. But if a window is toplevel one, then its always visible on - // screen if IsShown() returns true, even if it has a hidden parent. - return IsShown() && - (IsTopLevel() || !GetParent() || GetParent()->IsShownOnScreen()); -} - -// ---------------------------------------------------------------------------- -// RTTI -// ---------------------------------------------------------------------------- - -bool wxWindowBase::IsTopLevel() const -{ - return false; -} - -// ---------------------------------------------------------------------------- -// reparenting the window -// ---------------------------------------------------------------------------- - -void wxWindowBase::AddChild(wxWindowBase *child) -{ - wxCHECK_RET( child, wxT("can't add a NULL child") ); - - // this should never happen and it will lead to a crash later if it does - // because RemoveChild() will remove only one node from the children list - // and the other(s) one(s) will be left with dangling pointers in them - wxASSERT_MSG( !GetChildren().Find((wxWindow*)child), _T("AddChild() called twice") ); - - GetChildren().Append((wxWindow*)child); - child->SetParent(this); -} - -void wxWindowBase::RemoveChild(wxWindowBase *child) -{ - wxCHECK_RET( child, wxT("can't remove a NULL child") ); - - GetChildren().DeleteObject((wxWindow *)child); - child->SetParent(NULL); -} - -bool wxWindowBase::Reparent(wxWindowBase *newParent) -{ - wxWindow *oldParent = GetParent(); - if ( newParent == oldParent ) - { - // nothing done - return false; - } - - // unlink this window from the existing parent. - if ( oldParent ) - { - oldParent->RemoveChild(this); - } - else - { - wxTopLevelWindows.DeleteObject((wxWindow *)this); - } - - // add it to the new one - if ( newParent ) - { - newParent->AddChild(this); - } - else - { - wxTopLevelWindows.Append((wxWindow *)this); - } - - return true; -} - -// ---------------------------------------------------------------------------- -// event handler stuff -// ---------------------------------------------------------------------------- - -void wxWindowBase::PushEventHandler(wxEvtHandler *handler) -{ - wxEvtHandler *handlerOld = GetEventHandler(); - - handler->SetNextHandler(handlerOld); - - if ( handlerOld ) - GetEventHandler()->SetPreviousHandler(handler); - - SetEventHandler(handler); -} - -wxEvtHandler *wxWindowBase::PopEventHandler(bool deleteHandler) -{ - wxEvtHandler *handlerA = GetEventHandler(); - if ( handlerA ) - { - wxEvtHandler *handlerB = handlerA->GetNextHandler(); - handlerA->SetNextHandler((wxEvtHandler *)NULL); - - if ( handlerB ) - handlerB->SetPreviousHandler((wxEvtHandler *)NULL); - SetEventHandler(handlerB); - - if ( deleteHandler ) - { - delete handlerA; - handlerA = (wxEvtHandler *)NULL; - } - } - - return handlerA; -} - -bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler) -{ - wxCHECK_MSG( handler, false, _T("RemoveEventHandler(NULL) called") ); - - wxEvtHandler *handlerPrev = NULL, - *handlerCur = GetEventHandler(); - while ( handlerCur ) - { - wxEvtHandler *handlerNext = handlerCur->GetNextHandler(); - - if ( handlerCur == handler ) - { - if ( handlerPrev ) - { - handlerPrev->SetNextHandler(handlerNext); - } - else - { - SetEventHandler(handlerNext); - } - - if ( handlerNext ) - { - handlerNext->SetPreviousHandler ( handlerPrev ); - } - - handler->SetNextHandler(NULL); - handler->SetPreviousHandler(NULL); - - return true; - } - - handlerPrev = handlerCur; - handlerCur = handlerNext; - } - - wxFAIL_MSG( _T("where has the event handler gone?") ); - - return false; -} - -// ---------------------------------------------------------------------------- -// colours, fonts &c -// ---------------------------------------------------------------------------- - -void wxWindowBase::InheritAttributes() -{ - const wxWindowBase * const parent = GetParent(); - if ( !parent ) - return; - - // we only inherit attributes which had been explicitly set for the parent - // which ensures that this only happens if the user really wants it and - // not by default which wouldn't make any sense in modern GUIs where the - // controls don't all use the same fonts (nor colours) - if ( parent->m_inheritFont && !m_hasFont ) - SetFont(parent->GetFont()); - - // in addition, there is a possibility to explicitly forbid inheriting - // colours at each class level by overriding ShouldInheritColours() - if ( ShouldInheritColours() ) - { - if ( parent->m_inheritFgCol && !m_hasFgCol ) - SetForegroundColour(parent->GetForegroundColour()); - - // inheriting (solid) background colour is wrong as it totally breaks - // any kind of themed backgrounds - // - // instead, the controls should use the same background as their parent - // (ideally by not drawing it at all) -#if 0 - if ( parent->m_inheritBgCol && !m_hasBgCol ) - SetBackgroundColour(parent->GetBackgroundColour()); -#endif // 0 - } -} - -/* static */ wxVisualAttributes -wxWindowBase::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) -{ - // it is important to return valid values for all attributes from here, - // GetXXX() below rely on this - wxVisualAttributes attrs; - attrs.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); - attrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); - - // On Smartphone/PocketPC, wxSYS_COLOUR_WINDOW is a better reflection of - // the usual background colour than wxSYS_COLOUR_BTNFACE. - // It's a pity that wxSYS_COLOUR_WINDOW isn't always a suitable background - // colour on other platforms. - -#if defined(__WXWINCE__) && (defined(__SMARTPHONE__) || defined(__POCKETPC__)) - attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); -#else - attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); -#endif - return attrs; -} - -wxColour wxWindowBase::GetBackgroundColour() const -{ - if ( !m_backgroundColour.Ok() ) - { - wxASSERT_MSG( !m_hasBgCol, _T("we have invalid explicit bg colour?") ); - - // get our default background colour - wxColour colBg = GetDefaultAttributes().colBg; - - // we must return some valid colour to avoid redoing this every time - // and also to avoid surprizing the applications written for older - // wxWidgets versions where GetBackgroundColour() always returned - // something -- so give them something even if it doesn't make sense - // for this window (e.g. it has a themed background) - if ( !colBg.Ok() ) - colBg = GetClassDefaultAttributes().colBg; - - return colBg; - } - else - return m_backgroundColour; -} - -wxColour wxWindowBase::GetForegroundColour() const -{ - // logic is the same as above - if ( !m_hasFgCol && !m_foregroundColour.Ok() ) - { - wxASSERT_MSG( !m_hasFgCol, _T("we have invalid explicit fg colour?") ); - - wxColour colFg = GetDefaultAttributes().colFg; - - if ( !colFg.Ok() ) - colFg = GetClassDefaultAttributes().colFg; - - return colFg; - } - else - return m_foregroundColour; -} - -bool wxWindowBase::SetBackgroundColour( const wxColour &colour ) -{ - if ( colour == m_backgroundColour ) - return false; - - m_hasBgCol = colour.Ok(); - if ( m_backgroundStyle != wxBG_STYLE_CUSTOM ) - m_backgroundStyle = m_hasBgCol ? wxBG_STYLE_COLOUR : wxBG_STYLE_SYSTEM; - - m_inheritBgCol = m_hasBgCol; - m_backgroundColour = colour; - SetThemeEnabled( !m_hasBgCol && !m_foregroundColour.Ok() ); - return true; -} - -bool wxWindowBase::SetForegroundColour( const wxColour &colour ) -{ - if (colour == m_foregroundColour ) - return false; - - m_hasFgCol = colour.Ok(); - m_inheritFgCol = m_hasFgCol; - m_foregroundColour = colour; - SetThemeEnabled( !m_hasFgCol && !m_backgroundColour.Ok() ); - return true; -} - -bool wxWindowBase::SetCursor(const wxCursor& cursor) -{ - // setting an invalid cursor is ok, it means that we don't have any special - // cursor - if ( m_cursor.IsSameAs(cursor) ) - { - // no change - return false; - } - - m_cursor = cursor; - - return true; -} - -wxFont wxWindowBase::GetFont() const -{ - // logic is the same as in GetBackgroundColour() - if ( !m_font.Ok() ) - { - wxASSERT_MSG( !m_hasFont, _T("we have invalid explicit font?") ); - - wxFont font = GetDefaultAttributes().font; - if ( !font.Ok() ) - font = GetClassDefaultAttributes().font; - - return font; - } - else - return m_font; -} - -bool wxWindowBase::SetFont(const wxFont& font) -{ - if ( font == m_font ) - { - // no change - return false; - } - - m_font = font; - m_hasFont = font.Ok(); - m_inheritFont = m_hasFont; - - InvalidateBestSize(); - - return true; -} - -#if wxUSE_PALETTE - -void wxWindowBase::SetPalette(const wxPalette& pal) -{ - m_hasCustomPalette = true; - m_palette = pal; - - // VZ: can anyone explain me what do we do here? - wxWindowDC d((wxWindow *) this); - d.SetPalette(pal); -} - -wxWindow *wxWindowBase::GetAncestorWithCustomPalette() const -{ - wxWindow *win = (wxWindow *)this; - while ( win && !win->HasCustomPalette() ) - { - win = win->GetParent(); - } - - return win; -} - -#endif // wxUSE_PALETTE - -#if wxUSE_CARET -void wxWindowBase::SetCaret(wxCaret *caret) -{ - if ( m_caret ) - { - delete m_caret; - } - - m_caret = caret; - - if ( m_caret ) - { - wxASSERT_MSG( m_caret->GetWindow() == this, - wxT("caret should be created associated to this window") ); - } -} -#endif // wxUSE_CARET - -#if wxUSE_VALIDATORS -// ---------------------------------------------------------------------------- -// validators -// ---------------------------------------------------------------------------- - -void wxWindowBase::SetValidator(const wxValidator& validator) -{ - if ( m_windowValidator ) - delete m_windowValidator; - - m_windowValidator = (wxValidator *)validator.Clone(); - - if ( m_windowValidator ) - m_windowValidator->SetWindow(this); -} -#endif // wxUSE_VALIDATORS - -// ---------------------------------------------------------------------------- -// update region stuff -// ---------------------------------------------------------------------------- - -wxRect wxWindowBase::GetUpdateClientRect() const -{ - wxRegion rgnUpdate = GetUpdateRegion(); - rgnUpdate.Intersect(GetClientRect()); - wxRect rectUpdate = rgnUpdate.GetBox(); - wxPoint ptOrigin = GetClientAreaOrigin(); - rectUpdate.x -= ptOrigin.x; - rectUpdate.y -= ptOrigin.y; - - return rectUpdate; -} - -bool wxWindowBase::DoIsExposed(int x, int y) const -{ - return m_updateRegion.Contains(x, y) != wxOutRegion; -} - -bool wxWindowBase::DoIsExposed(int x, int y, int w, int h) const -{ - return m_updateRegion.Contains(x, y, w, h) != wxOutRegion; -} - -void wxWindowBase::ClearBackground() -{ - // wxGTK uses its own version, no need to add never used code -#ifndef __WXGTK__ - wxClientDC dc((wxWindow *)this); - wxBrush brush(GetBackgroundColour(), wxSOLID); - dc.SetBackground(brush); - dc.Clear(); -#endif // __WXGTK__ -} - -// ---------------------------------------------------------------------------- -// find child window by id or name -// ---------------------------------------------------------------------------- - -wxWindow *wxWindowBase::FindWindow(long id) const -{ - if ( id == m_windowId ) - return (wxWindow *)this; - - wxWindowBase *res = (wxWindow *)NULL; - wxWindowList::compatibility_iterator node; - for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() ) - { - wxWindowBase *child = node->GetData(); - res = child->FindWindow( id ); - } - - return (wxWindow *)res; -} - -wxWindow *wxWindowBase::FindWindow(const wxString& name) const -{ - if ( name == m_windowName ) - return (wxWindow *)this; - - wxWindowBase *res = (wxWindow *)NULL; - wxWindowList::compatibility_iterator node; - for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() ) - { - wxWindow *child = node->GetData(); - res = child->FindWindow(name); - } - - return (wxWindow *)res; -} - - -// find any window by id or name or label: If parent is non-NULL, look through -// children for a label or title matching the specified string. If NULL, look -// through all top-level windows. -// -// to avoid duplicating code we reuse the same helper function but with -// different comparators - -typedef bool (*wxFindWindowCmp)(const wxWindow *win, - const wxString& label, long id); - -static -bool wxFindWindowCmpLabels(const wxWindow *win, const wxString& label, - long WXUNUSED(id)) -{ - return win->GetLabel() == label; -} - -static -bool wxFindWindowCmpNames(const wxWindow *win, const wxString& label, - long WXUNUSED(id)) -{ - return win->GetName() == label; -} - -static -bool wxFindWindowCmpIds(const wxWindow *win, const wxString& WXUNUSED(label), - long id) -{ - return win->GetId() == id; -} - -// recursive helper for the FindWindowByXXX() functions -static -wxWindow *wxFindWindowRecursively(const wxWindow *parent, - const wxString& label, - long id, - wxFindWindowCmp cmp) -{ - if ( parent ) - { - // see if this is the one we're looking for - if ( (*cmp)(parent, label, id) ) - return (wxWindow *)parent; - - // It wasn't, so check all its children - for ( wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - // recursively check each child - wxWindow *win = (wxWindow *)node->GetData(); - wxWindow *retwin = wxFindWindowRecursively(win, label, id, cmp); - if (retwin) - return retwin; - } - } - - // Not found - return NULL; -} - -// helper for FindWindowByXXX() -static -wxWindow *wxFindWindowHelper(const wxWindow *parent, - const wxString& label, - long id, - wxFindWindowCmp cmp) -{ - if ( parent ) - { - // just check parent and all its children - return wxFindWindowRecursively(parent, label, id, cmp); - } - - // start at very top of wx's windows - for ( wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst(); - node; - node = node->GetNext() ) - { - // recursively check each window & its children - wxWindow *win = node->GetData(); - wxWindow *retwin = wxFindWindowRecursively(win, label, id, cmp); - if (retwin) - return retwin; - } - - return NULL; -} - -/* static */ -wxWindow * -wxWindowBase::FindWindowByLabel(const wxString& title, const wxWindow *parent) -{ - return wxFindWindowHelper(parent, title, 0, wxFindWindowCmpLabels); -} - -/* static */ -wxWindow * -wxWindowBase::FindWindowByName(const wxString& title, const wxWindow *parent) -{ - wxWindow *win = wxFindWindowHelper(parent, title, 0, wxFindWindowCmpNames); - - if ( !win ) - { - // fall back to the label - win = FindWindowByLabel(title, parent); - } - - return win; -} - -/* static */ -wxWindow * -wxWindowBase::FindWindowById( long id, const wxWindow* parent ) -{ - return wxFindWindowHelper(parent, wxEmptyString, id, wxFindWindowCmpIds); -} - -// ---------------------------------------------------------------------------- -// dialog oriented functions -// ---------------------------------------------------------------------------- - -void wxWindowBase::MakeModal(bool modal) -{ - // Disable all other windows - if ( IsTopLevel() ) - { - wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst(); - while (node) - { - wxWindow *win = node->GetData(); - if (win != this) - win->Enable(!modal); - - node = node->GetNext(); - } - } -} - -bool wxWindowBase::Validate() -{ -#if wxUSE_VALIDATORS - bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0; - - wxWindowList::compatibility_iterator node; - for ( node = m_children.GetFirst(); node; node = node->GetNext() ) - { - wxWindowBase *child = node->GetData(); - wxValidator *validator = child->GetValidator(); - if ( validator && !validator->Validate((wxWindow *)this) ) - { - return false; - } - - if ( recurse && !child->Validate() ) - { - return false; - } - } -#endif // wxUSE_VALIDATORS - - return true; -} - -bool wxWindowBase::TransferDataToWindow() -{ -#if wxUSE_VALIDATORS - bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0; - - wxWindowList::compatibility_iterator node; - for ( node = m_children.GetFirst(); node; node = node->GetNext() ) - { - wxWindowBase *child = node->GetData(); - wxValidator *validator = child->GetValidator(); - if ( validator && !validator->TransferToWindow() ) - { - wxLogWarning(_("Could not transfer data to window")); -#if wxUSE_LOG - wxLog::FlushActive(); -#endif // wxUSE_LOG - - return false; - } - - if ( recurse ) - { - if ( !child->TransferDataToWindow() ) - { - // warning already given - return false; - } - } - } -#endif // wxUSE_VALIDATORS - - return true; -} - -bool wxWindowBase::TransferDataFromWindow() -{ -#if wxUSE_VALIDATORS - bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0; - - wxWindowList::compatibility_iterator node; - for ( node = m_children.GetFirst(); node; node = node->GetNext() ) - { - wxWindow *child = node->GetData(); - wxValidator *validator = child->GetValidator(); - if ( validator && !validator->TransferFromWindow() ) - { - // nop warning here because the application is supposed to give - // one itself - we don't know here what might have gone wrongly - - return false; - } - - if ( recurse ) - { - if ( !child->TransferDataFromWindow() ) - { - // warning already given - return false; - } - } - } -#endif // wxUSE_VALIDATORS - - return true; -} - -void wxWindowBase::InitDialog() -{ - wxInitDialogEvent event(GetId()); - event.SetEventObject( this ); - GetEventHandler()->ProcessEvent(event); -} - -// ---------------------------------------------------------------------------- -// context-sensitive help support -// ---------------------------------------------------------------------------- - -#if wxUSE_HELP - -// associate this help text with this window -void wxWindowBase::SetHelpText(const wxString& text) -{ - wxHelpProvider *helpProvider = wxHelpProvider::Get(); - if ( helpProvider ) - { - helpProvider->AddHelp(this, text); - } -} - -// associate this help text with all windows with the same id as this -// one -void wxWindowBase::SetHelpTextForId(const wxString& text) -{ - wxHelpProvider *helpProvider = wxHelpProvider::Get(); - if ( helpProvider ) - { - helpProvider->AddHelp(GetId(), text); - } -} - -// get the help string associated with this window (may be empty) -// default implementation forwards calls to the help provider -wxString -wxWindowBase::GetHelpTextAtPoint(const wxPoint & WXUNUSED(pt), - wxHelpEvent::Origin WXUNUSED(origin)) const -{ - wxString text; - wxHelpProvider *helpProvider = wxHelpProvider::Get(); - if ( helpProvider ) - { - text = helpProvider->GetHelp(this); - } - - return text; -} - -// show help for this window -void wxWindowBase::OnHelp(wxHelpEvent& event) -{ - wxHelpProvider *helpProvider = wxHelpProvider::Get(); - if ( helpProvider ) - { - wxPoint pos = event.GetPosition(); - const wxHelpEvent::Origin origin = event.GetOrigin(); - if ( origin == wxHelpEvent::Origin_Keyboard ) - { - // if the help event was generated from keyboard it shouldn't - // appear at the mouse position (which is still the only position - // associated with help event) if the mouse is far away, although - // we still do use the mouse position if it's over the window - // because we suppose the user looks approximately at the mouse - // already and so it would be more convenient than showing tooltip - // at some arbitrary position which can be quite far from it - const wxRect rectClient = GetClientRect(); - if ( !rectClient.Contains(ScreenToClient(pos)) ) - { - // position help slightly under and to the right of this window - pos = ClientToScreen(wxPoint( - 2*GetCharWidth(), - rectClient.height + GetCharHeight() - )); - } - } - - if ( helpProvider->ShowHelpAtPoint(this, pos, origin) ) - { - // skip the event.Skip() below - return; - } - } - - event.Skip(); -} - -#endif // wxUSE_HELP - -// ---------------------------------------------------------------------------- -// tooltips -// ---------------------------------------------------------------------------- - -#if wxUSE_TOOLTIPS - -void wxWindowBase::SetToolTip( const wxString &tip ) -{ - // don't create the new tooltip if we already have one - if ( m_tooltip ) - { - m_tooltip->SetTip( tip ); - } - else - { - SetToolTip( new wxToolTip( tip ) ); - } - - // setting empty tooltip text does not remove the tooltip any more - use - // SetToolTip((wxToolTip *)NULL) for this -} - -void wxWindowBase::DoSetToolTip(wxToolTip *tooltip) -{ - if ( m_tooltip != tooltip ) - { - if ( m_tooltip ) - delete m_tooltip; - - m_tooltip = tooltip; - } -} - -#endif // wxUSE_TOOLTIPS - -// ---------------------------------------------------------------------------- -// constraints and sizers -// ---------------------------------------------------------------------------- - -#if wxUSE_CONSTRAINTS - -void wxWindowBase::SetConstraints( wxLayoutConstraints *constraints ) -{ - if ( m_constraints ) - { - UnsetConstraints(m_constraints); - delete m_constraints; - } - m_constraints = constraints; - if ( m_constraints ) - { - // Make sure other windows know they're part of a 'meaningful relationship' - if ( m_constraints->left.GetOtherWindow() && (m_constraints->left.GetOtherWindow() != this) ) - m_constraints->left.GetOtherWindow()->AddConstraintReference(this); - if ( m_constraints->top.GetOtherWindow() && (m_constraints->top.GetOtherWindow() != this) ) - m_constraints->top.GetOtherWindow()->AddConstraintReference(this); - if ( m_constraints->right.GetOtherWindow() && (m_constraints->right.GetOtherWindow() != this) ) - m_constraints->right.GetOtherWindow()->AddConstraintReference(this); - if ( m_constraints->bottom.GetOtherWindow() && (m_constraints->bottom.GetOtherWindow() != this) ) - m_constraints->bottom.GetOtherWindow()->AddConstraintReference(this); - if ( m_constraints->width.GetOtherWindow() && (m_constraints->width.GetOtherWindow() != this) ) - m_constraints->width.GetOtherWindow()->AddConstraintReference(this); - if ( m_constraints->height.GetOtherWindow() && (m_constraints->height.GetOtherWindow() != this) ) - m_constraints->height.GetOtherWindow()->AddConstraintReference(this); - if ( m_constraints->centreX.GetOtherWindow() && (m_constraints->centreX.GetOtherWindow() != this) ) - m_constraints->centreX.GetOtherWindow()->AddConstraintReference(this); - if ( m_constraints->centreY.GetOtherWindow() && (m_constraints->centreY.GetOtherWindow() != this) ) - m_constraints->centreY.GetOtherWindow()->AddConstraintReference(this); - } -} - -// This removes any dangling pointers to this window in other windows' -// constraintsInvolvedIn lists. -void wxWindowBase::UnsetConstraints(wxLayoutConstraints *c) -{ - if ( c ) - { - if ( c->left.GetOtherWindow() && (c->top.GetOtherWindow() != this) ) - c->left.GetOtherWindow()->RemoveConstraintReference(this); - if ( c->top.GetOtherWindow() && (c->top.GetOtherWindow() != this) ) - c->top.GetOtherWindow()->RemoveConstraintReference(this); - if ( c->right.GetOtherWindow() && (c->right.GetOtherWindow() != this) ) - c->right.GetOtherWindow()->RemoveConstraintReference(this); - if ( c->bottom.GetOtherWindow() && (c->bottom.GetOtherWindow() != this) ) - c->bottom.GetOtherWindow()->RemoveConstraintReference(this); - if ( c->width.GetOtherWindow() && (c->width.GetOtherWindow() != this) ) - c->width.GetOtherWindow()->RemoveConstraintReference(this); - if ( c->height.GetOtherWindow() && (c->height.GetOtherWindow() != this) ) - c->height.GetOtherWindow()->RemoveConstraintReference(this); - if ( c->centreX.GetOtherWindow() && (c->centreX.GetOtherWindow() != this) ) - c->centreX.GetOtherWindow()->RemoveConstraintReference(this); - if ( c->centreY.GetOtherWindow() && (c->centreY.GetOtherWindow() != this) ) - c->centreY.GetOtherWindow()->RemoveConstraintReference(this); - } -} - -// Back-pointer to other windows we're involved with, so if we delete this -// window, we must delete any constraints we're involved with. -void wxWindowBase::AddConstraintReference(wxWindowBase *otherWin) -{ - if ( !m_constraintsInvolvedIn ) - m_constraintsInvolvedIn = new wxWindowList; - if ( !m_constraintsInvolvedIn->Find((wxWindow *)otherWin) ) - m_constraintsInvolvedIn->Append((wxWindow *)otherWin); -} - -// REMOVE back-pointer to other windows we're involved with. -void wxWindowBase::RemoveConstraintReference(wxWindowBase *otherWin) -{ - if ( m_constraintsInvolvedIn ) - m_constraintsInvolvedIn->DeleteObject((wxWindow *)otherWin); -} - -// Reset any constraints that mention this window -void wxWindowBase::DeleteRelatedConstraints() -{ - if ( m_constraintsInvolvedIn ) - { - wxWindowList::compatibility_iterator node = m_constraintsInvolvedIn->GetFirst(); - while (node) - { - wxWindow *win = node->GetData(); - wxLayoutConstraints *constr = win->GetConstraints(); - - // Reset any constraints involving this window - if ( constr ) - { - constr->left.ResetIfWin(this); - constr->top.ResetIfWin(this); - constr->right.ResetIfWin(this); - constr->bottom.ResetIfWin(this); - constr->width.ResetIfWin(this); - constr->height.ResetIfWin(this); - constr->centreX.ResetIfWin(this); - constr->centreY.ResetIfWin(this); - } - - wxWindowList::compatibility_iterator next = node->GetNext(); - m_constraintsInvolvedIn->Erase(node); - node = next; - } - - delete m_constraintsInvolvedIn; - m_constraintsInvolvedIn = (wxWindowList *) NULL; - } -} - -#endif // wxUSE_CONSTRAINTS - -void wxWindowBase::SetSizer(wxSizer *sizer, bool deleteOld) -{ - if ( sizer == m_windowSizer) - return; - - if ( m_windowSizer ) - { - m_windowSizer->SetContainingWindow(NULL); - - if ( deleteOld ) - delete m_windowSizer; - } - - m_windowSizer = sizer; - if ( m_windowSizer ) - { - m_windowSizer->SetContainingWindow((wxWindow *)this); - } - - SetAutoLayout(m_windowSizer != NULL); -} - -void wxWindowBase::SetSizerAndFit(wxSizer *sizer, bool deleteOld) -{ - SetSizer( sizer, deleteOld ); - sizer->SetSizeHints( (wxWindow*) this ); -} - - -void wxWindowBase::SetContainingSizer(wxSizer* sizer) -{ - // adding a window to a sizer twice is going to result in fatal and - // hard to debug problems later because when deleting the second - // associated wxSizerItem we're going to dereference a dangling - // pointer; so try to detect this as early as possible - wxASSERT_MSG( !sizer || m_containingSizer != sizer, - _T("Adding a window to the same sizer twice?") ); - - m_containingSizer = sizer; -} - -#if wxUSE_CONSTRAINTS - -void wxWindowBase::SatisfyConstraints() -{ - wxLayoutConstraints *constr = GetConstraints(); - bool wasOk = constr && constr->AreSatisfied(); - - ResetConstraints(); // Mark all constraints as unevaluated - - int noChanges = 1; - - // if we're a top level panel (i.e. our parent is frame/dialog), our - // own constraints will never be satisfied any more unless we do it - // here - if ( wasOk ) - { - while ( noChanges > 0 ) - { - LayoutPhase1(&noChanges); - } - } - - LayoutPhase2(&noChanges); -} - -#endif // wxUSE_CONSTRAINTS - -bool wxWindowBase::Layout() -{ - // If there is a sizer, use it instead of the constraints - if ( GetSizer() ) - { - int w = 0, h = 0; - GetVirtualSize(&w, &h); - GetSizer()->SetDimension( 0, 0, w, h ); - } -#if wxUSE_CONSTRAINTS - else - { - SatisfyConstraints(); // Find the right constraints values - SetConstraintSizes(); // Recursively set the real window sizes - } -#endif - - return true; -} - -#if wxUSE_CONSTRAINTS - -// first phase of the constraints evaluation: set our own constraints -bool wxWindowBase::LayoutPhase1(int *noChanges) -{ - wxLayoutConstraints *constr = GetConstraints(); - - return !constr || constr->SatisfyConstraints(this, noChanges); -} - -// second phase: set the constraints for our children -bool wxWindowBase::LayoutPhase2(int *noChanges) -{ - *noChanges = 0; - - // Layout children - DoPhase(1); - - // Layout grand children - DoPhase(2); - - return true; -} - -// Do a phase of evaluating child constraints -bool wxWindowBase::DoPhase(int phase) -{ - // the list containing the children for which the constraints are already - // set correctly - wxWindowList succeeded; - - // the max number of iterations we loop before concluding that we can't set - // the constraints - static const int maxIterations = 500; - - for ( int noIterations = 0; noIterations < maxIterations; noIterations++ ) - { - int noChanges = 0; - - // loop over all children setting their constraints - for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - node; - node = node->GetNext() ) - { - wxWindow *child = node->GetData(); - if ( child->IsTopLevel() ) - { - // top level children are not inside our client area - continue; - } - - if ( !child->GetConstraints() || succeeded.Find(child) ) - { - // this one is either already ok or nothing we can do about it - continue; - } - - int tempNoChanges = 0; - bool success = phase == 1 ? child->LayoutPhase1(&tempNoChanges) - : child->LayoutPhase2(&tempNoChanges); - noChanges += tempNoChanges; - - if ( success ) - { - succeeded.Append(child); - } - } - - if ( !noChanges ) - { - // constraints are set - break; - } - } - - return true; -} - -void wxWindowBase::ResetConstraints() -{ - wxLayoutConstraints *constr = GetConstraints(); - if ( constr ) - { - constr->left.SetDone(false); - constr->top.SetDone(false); - constr->right.SetDone(false); - constr->bottom.SetDone(false); - constr->width.SetDone(false); - constr->height.SetDone(false); - constr->centreX.SetDone(false); - constr->centreY.SetDone(false); - } - - wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - while (node) - { - wxWindow *win = node->GetData(); - if ( !win->IsTopLevel() ) - win->ResetConstraints(); - node = node->GetNext(); - } -} - -// Need to distinguish between setting the 'fake' size for windows and sizers, -// and setting the real values. -void wxWindowBase::SetConstraintSizes(bool recurse) -{ - wxLayoutConstraints *constr = GetConstraints(); - if ( constr && constr->AreSatisfied() ) - { - int x = constr->left.GetValue(); - int y = constr->top.GetValue(); - int w = constr->width.GetValue(); - int h = constr->height.GetValue(); - - if ( (constr->width.GetRelationship() != wxAsIs ) || - (constr->height.GetRelationship() != wxAsIs) ) - { - SetSize(x, y, w, h); - } - else - { - // If we don't want to resize this window, just move it... - Move(x, y); - } - } - else if ( constr ) - { - wxLogDebug(wxT("Constraints not satisfied for %s named '%s'."), - GetClassInfo()->GetClassName(), - GetName().c_str()); - } - - if ( recurse ) - { - wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - while (node) - { - wxWindow *win = node->GetData(); - if ( !win->IsTopLevel() && win->GetConstraints() ) - win->SetConstraintSizes(); - node = node->GetNext(); - } - } -} - -// Only set the size/position of the constraint (if any) -void wxWindowBase::SetSizeConstraint(int x, int y, int w, int h) -{ - wxLayoutConstraints *constr = GetConstraints(); - if ( constr ) - { - if ( x != wxDefaultCoord ) - { - constr->left.SetValue(x); - constr->left.SetDone(true); - } - if ( y != wxDefaultCoord ) - { - constr->top.SetValue(y); - constr->top.SetDone(true); - } - if ( w != wxDefaultCoord ) - { - constr->width.SetValue(w); - constr->width.SetDone(true); - } - if ( h != wxDefaultCoord ) - { - constr->height.SetValue(h); - constr->height.SetDone(true); - } - } -} - -void wxWindowBase::MoveConstraint(int x, int y) -{ - wxLayoutConstraints *constr = GetConstraints(); - if ( constr ) - { - if ( x != wxDefaultCoord ) - { - constr->left.SetValue(x); - constr->left.SetDone(true); - } - if ( y != wxDefaultCoord ) - { - constr->top.SetValue(y); - constr->top.SetDone(true); - } - } -} - -void wxWindowBase::GetSizeConstraint(int *w, int *h) const -{ - wxLayoutConstraints *constr = GetConstraints(); - if ( constr ) - { - *w = constr->width.GetValue(); - *h = constr->height.GetValue(); - } - else - GetSize(w, h); -} - -void wxWindowBase::GetClientSizeConstraint(int *w, int *h) const -{ - wxLayoutConstraints *constr = GetConstraints(); - if ( constr ) - { - *w = constr->width.GetValue(); - *h = constr->height.GetValue(); - } - else - GetClientSize(w, h); -} - -void wxWindowBase::GetPositionConstraint(int *x, int *y) const -{ - wxLayoutConstraints *constr = GetConstraints(); - if ( constr ) - { - *x = constr->left.GetValue(); - *y = constr->top.GetValue(); - } - else - GetPosition(x, y); -} - -#endif // wxUSE_CONSTRAINTS - -void wxWindowBase::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) const -{ - // don't do it for the dialogs/frames - they float independently of their - // parent - if ( !IsTopLevel() ) - { - wxWindow *parent = GetParent(); - if ( !(sizeFlags & wxSIZE_NO_ADJUSTMENTS) && parent ) - { - wxPoint pt(parent->GetClientAreaOrigin()); - x += pt.x; - y += pt.y; - } - } -} - -// ---------------------------------------------------------------------------- -// Update UI processing -// ---------------------------------------------------------------------------- - -void wxWindowBase::UpdateWindowUI(long flags) -{ - wxUpdateUIEvent event(GetId()); - event.SetEventObject(this); - - if ( GetEventHandler()->ProcessEvent(event) ) - { - DoUpdateWindowUI(event); - } - - if (flags & wxUPDATE_UI_RECURSE) - { - wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - while (node) - { - wxWindow* child = (wxWindow*) node->GetData(); - child->UpdateWindowUI(flags); - node = node->GetNext(); - } - } -} - -// do the window-specific processing after processing the update event -void wxWindowBase::DoUpdateWindowUI(wxUpdateUIEvent& event) -{ - if ( event.GetSetEnabled() ) - Enable(event.GetEnabled()); - - if ( event.GetSetShown() ) - Show(event.GetShown()); -} - -// ---------------------------------------------------------------------------- -// dialog units translations -// ---------------------------------------------------------------------------- - -wxPoint wxWindowBase::ConvertPixelsToDialog(const wxPoint& pt) -{ - int charWidth = GetCharWidth(); - int charHeight = GetCharHeight(); - wxPoint pt2 = wxDefaultPosition; - if (pt.x != wxDefaultCoord) - pt2.x = (int) ((pt.x * 4) / charWidth); - if (pt.y != wxDefaultCoord) - pt2.y = (int) ((pt.y * 8) / charHeight); - - return pt2; -} - -wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt) -{ - int charWidth = GetCharWidth(); - int charHeight = GetCharHeight(); - wxPoint pt2 = wxDefaultPosition; - if (pt.x != wxDefaultCoord) - pt2.x = (int) ((pt.x * charWidth) / 4); - if (pt.y != wxDefaultCoord) - pt2.y = (int) ((pt.y * charHeight) / 8); - - return pt2; -} - -// ---------------------------------------------------------------------------- -// event handlers -// ---------------------------------------------------------------------------- - -// propagate the colour change event to the subwindows -void wxWindowBase::OnSysColourChanged(wxSysColourChangedEvent& event) -{ - wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); - while ( node ) - { - // Only propagate to non-top-level windows - wxWindow *win = node->GetData(); - if ( !win->IsTopLevel() ) - { - wxSysColourChangedEvent event2; - event.SetEventObject(win); - win->GetEventHandler()->ProcessEvent(event2); - } - - node = node->GetNext(); - } - - Refresh(); -} - -// the default action is to populate dialog with data when it's created, -// and nudge the UI into displaying itself correctly in case -// we've turned the wxUpdateUIEvents frequency down low. -void wxWindowBase::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) ) -{ - TransferDataToWindow(); - - // Update the UI at this point - UpdateWindowUI(wxUPDATE_UI_RECURSE); -} - -// methods for drawing the sizers in a visible way -#ifdef __WXDEBUG__ - -static void DrawSizers(wxWindowBase *win); - -static void DrawBorder(wxWindowBase *win, const wxRect& rect, bool fill = false) -{ - wxClientDC dc((wxWindow *)win); - dc.SetPen(*wxRED_PEN); - dc.SetBrush(fill ? wxBrush(*wxRED, wxCROSSDIAG_HATCH): *wxTRANSPARENT_BRUSH); - dc.DrawRectangle(rect.Deflate(1, 1)); -} - -static void DrawSizer(wxWindowBase *win, wxSizer *sizer) -{ - const wxSizerItemList& items = sizer->GetChildren(); - for ( wxSizerItemList::const_iterator i = items.begin(), - end = items.end(); - i != end; - ++i ) - { - wxSizerItem *item = *i; - if ( item->IsSizer() ) - { - DrawBorder(win, item->GetRect().Deflate(2)); - DrawSizer(win, item->GetSizer()); - } - else if ( item->IsSpacer() ) - { - DrawBorder(win, item->GetRect().Deflate(2), true); - } - else if ( item->IsWindow() ) - { - DrawSizers(item->GetWindow()); - } - } -} - -static void DrawSizers(wxWindowBase *win) -{ - wxSizer *sizer = win->GetSizer(); - if ( sizer ) - { - DrawBorder(win, win->GetClientSize()); - DrawSizer(win, sizer); - } - else // no sizer, still recurse into the children - { - const wxWindowList& children = win->GetChildren(); - for ( wxWindowList::const_iterator i = children.begin(), - end = children.end(); - i != end; - ++i ) - { - DrawSizers(*i); - } - } -} - -#endif // __WXDEBUG__ - -// process special middle clicks -void wxWindowBase::OnMiddleClick( wxMouseEvent& event ) -{ - if ( event.ControlDown() && event.AltDown() ) - { -#ifdef __WXDEBUG__ - // Ctrl-Alt-Shift-mclick makes the sizers visible in debug builds - if ( event.ShiftDown() ) - { - DrawSizers(this); - return; - } -#endif // __WXDEBUG__ - -#if wxUSE_MSGDLG - // don't translate these strings, they're for diagnostics purposes only - wxString msg; - msg.Printf(_T("wxWidgets Library (%s port)\n") - _T("Version %d.%d.%d%s%s, compiled at %s %s\n") - _T("Runtime version of toolkit used is %d.%d.%s\n") - _T("Copyright (c) 1995-2010 wxWidgets team"), - wxPlatformInfo::Get().GetPortIdName().c_str(), - wxMAJOR_VERSION, - wxMINOR_VERSION, - wxRELEASE_NUMBER, -#if wxUSE_UNICODE - L" (Unicode)", -#else - wxEmptyString, -#endif -#ifdef __WXDEBUG__ - _T(" Debug build"), -#else - wxEmptyString, -#endif - __TDATE__, - __TTIME__, - wxPlatformInfo::Get().GetToolkitMajorVersion(), - wxPlatformInfo::Get().GetToolkitMinorVersion(), -#ifdef __WXGTK__ - wxString::Format(_T("\nThe compile-time GTK+ version is %d.%d.%d."), GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION).c_str() -#else - wxEmptyString -#endif - ); - - wxMessageBox(msg, _T("wxWidgets information"), - wxICON_INFORMATION | wxOK, - (wxWindow *)this); - } - else -#endif // wxUSE_MSGDLG - { - event.Skip(); - } -} - -// ---------------------------------------------------------------------------- -// accessibility -// ---------------------------------------------------------------------------- - -#if wxUSE_ACCESSIBILITY -void wxWindowBase::SetAccessible(wxAccessible* accessible) -{ - if (m_accessible && (accessible != m_accessible)) - delete m_accessible; - m_accessible = accessible; - if (m_accessible) - m_accessible->SetWindow((wxWindow*) this); -} - -// Returns the accessible object, creating if necessary. -wxAccessible* wxWindowBase::GetOrCreateAccessible() -{ - if (!m_accessible) - m_accessible = CreateAccessible(); - return m_accessible; -} - -// Override to create a specific accessible object. -wxAccessible* wxWindowBase::CreateAccessible() -{ - return new wxWindowAccessible((wxWindow*) this); -} - -#endif - -// ---------------------------------------------------------------------------- -// list classes implementation -// ---------------------------------------------------------------------------- - -#if wxUSE_STL - -#include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxWindowList) - -#else // !wxUSE_STL - -void wxWindowListNode::DeleteData() -{ - delete (wxWindow *)GetData(); -} - -#endif // wxUSE_STL/!wxUSE_STL - -// ---------------------------------------------------------------------------- -// borders -// ---------------------------------------------------------------------------- - -wxBorder wxWindowBase::GetBorder(long flags) const -{ - wxBorder border = (wxBorder)(flags & wxBORDER_MASK); - if ( border == wxBORDER_DEFAULT ) - { - border = GetDefaultBorder(); - } - - return border; -} - -wxBorder wxWindowBase::GetDefaultBorder() const -{ - return wxBORDER_NONE; -} - -// ---------------------------------------------------------------------------- -// hit testing -// ---------------------------------------------------------------------------- - -wxHitTest wxWindowBase::DoHitTest(wxCoord x, wxCoord y) const -{ - // here we just check if the point is inside the window or not - - // check the top and left border first - bool outside = x < 0 || y < 0; - if ( !outside ) - { - // check the right and bottom borders too - wxSize size = GetSize(); - outside = x >= size.x || y >= size.y; - } - - return outside ? wxHT_WINDOW_OUTSIDE : wxHT_WINDOW_INSIDE; -} - -// ---------------------------------------------------------------------------- -// mouse capture -// ---------------------------------------------------------------------------- - -struct WXDLLEXPORT wxWindowNext -{ - wxWindow *win; - wxWindowNext *next; -} *wxWindowBase::ms_winCaptureNext = NULL; -wxWindow *wxWindowBase::ms_winCaptureCurrent = NULL; -bool wxWindowBase::ms_winCaptureChanging = false; - -void wxWindowBase::CaptureMouse() -{ - wxLogTrace(_T("mousecapture"), _T("CaptureMouse(%p)"), wx_static_cast(void*, this)); - - wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive CaptureMouse call?") ); - - ms_winCaptureChanging = true; - - wxWindow *winOld = GetCapture(); - if ( winOld ) - { - ((wxWindowBase*) winOld)->DoReleaseMouse(); - - // save it on stack - wxWindowNext *item = new wxWindowNext; - item->win = winOld; - item->next = ms_winCaptureNext; - ms_winCaptureNext = item; - } - //else: no mouse capture to save - - DoCaptureMouse(); - ms_winCaptureCurrent = (wxWindow*)this; - - ms_winCaptureChanging = false; -} - -void wxWindowBase::ReleaseMouse() -{ - wxLogTrace(_T("mousecapture"), _T("ReleaseMouse(%p)"), wx_static_cast(void*, this)); - - wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive ReleaseMouse call?") ); - - wxASSERT_MSG( GetCapture() == this, wxT("attempt to release mouse, but this window hasn't captured it") ); - - ms_winCaptureChanging = true; - - DoReleaseMouse(); - ms_winCaptureCurrent = NULL; - - if ( ms_winCaptureNext ) - { - ((wxWindowBase*)ms_winCaptureNext->win)->DoCaptureMouse(); - ms_winCaptureCurrent = ms_winCaptureNext->win; - - wxWindowNext *item = ms_winCaptureNext; - ms_winCaptureNext = item->next; - delete item; - } - //else: stack is empty, no previous capture - - ms_winCaptureChanging = false; - - wxLogTrace(_T("mousecapture"), - (const wxChar *) _T("After ReleaseMouse() mouse is captured by %p"), - wx_static_cast(void*, GetCapture())); -} - -static void DoNotifyWindowAboutCaptureLost(wxWindow *win) -{ - wxMouseCaptureLostEvent event(win->GetId()); - event.SetEventObject(win); - if ( !win->GetEventHandler()->ProcessEvent(event) ) - { - // windows must handle this event, otherwise the app wouldn't behave - // correctly if it loses capture unexpectedly; see the discussion here: - // http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863 - // http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/82376 - wxFAIL_MSG( _T("window that captured the mouse didn't process wxEVT_MOUSE_CAPTURE_LOST") ); - } -} - -/* static */ -void wxWindowBase::NotifyCaptureLost() -{ - // don't do anything if capture lost was expected, i.e. resulted from - // a wx call to ReleaseMouse or CaptureMouse: - if ( ms_winCaptureChanging ) - return; - - // if the capture was lost unexpectedly, notify every window that has - // capture (on stack or current) about it and clear the stack: - - if ( ms_winCaptureCurrent ) - { - DoNotifyWindowAboutCaptureLost(ms_winCaptureCurrent); - ms_winCaptureCurrent = NULL; - } - - while ( ms_winCaptureNext ) - { - wxWindowNext *item = ms_winCaptureNext; - ms_winCaptureNext = item->next; - - DoNotifyWindowAboutCaptureLost(item->win); - - delete item; - } -} - -#if wxUSE_HOTKEY - -bool -wxWindowBase::RegisterHotKey(int WXUNUSED(hotkeyId), - int WXUNUSED(modifiers), - int WXUNUSED(keycode)) -{ - // not implemented - return false; -} - -bool wxWindowBase::UnregisterHotKey(int WXUNUSED(hotkeyId)) -{ - // not implemented - return false; -} - -#endif // wxUSE_HOTKEY - -// ---------------------------------------------------------------------------- -// event processing -// ---------------------------------------------------------------------------- - -bool wxWindowBase::TryValidator(wxEvent& wxVALIDATOR_PARAM(event)) -{ -#if wxUSE_VALIDATORS - // Can only use the validator of the window which - // is receiving the event - if ( event.GetEventObject() == this ) - { - wxValidator *validator = GetValidator(); - if ( validator && validator->ProcessEvent(event) ) - { - return true; - } - } -#endif // wxUSE_VALIDATORS - - return false; -} - -bool wxWindowBase::TryParent(wxEvent& event) -{ - // carry on up the parent-child hierarchy if the propagation count hasn't - // reached zero yet - if ( event.ShouldPropagate() ) - { - // honour the requests to stop propagation at this window: this is - // used by the dialogs, for example, to prevent processing the events - // from the dialog controls in the parent frame which rarely, if ever, - // makes sense - if ( !(GetExtraStyle() & wxWS_EX_BLOCK_EVENTS) ) - { - wxWindow *parent = GetParent(); - if ( parent && !parent->IsBeingDeleted() ) - { - wxPropagateOnce propagateOnce(event); - - return parent->GetEventHandler()->ProcessEvent(event); - } - } - } - - return wxEvtHandler::TryParent(event); -} - -// ---------------------------------------------------------------------------- -// window relationships -// ---------------------------------------------------------------------------- - -wxWindow *wxWindowBase::DoGetSibling(MoveKind order) const -{ - wxCHECK_MSG( GetParent(), NULL, - _T("GetPrev/NextSibling() don't work for TLWs!") ); - - wxWindowList& siblings = GetParent()->GetChildren(); - wxWindowList::compatibility_iterator i = siblings.Find((wxWindow *)this); - wxCHECK_MSG( i, NULL, _T("window not a child of its parent?") ); - - if ( order == MoveBefore ) - i = i->GetPrevious(); - else // MoveAfter - i = i->GetNext(); - - return i ? i->GetData() : NULL; -} - -// ---------------------------------------------------------------------------- -// keyboard navigation -// ---------------------------------------------------------------------------- - -// Navigates in the specified direction. -bool wxWindowBase::Navigate(int flags) -{ - wxNavigationKeyEvent eventNav; - eventNav.SetFlags(flags); - eventNav.SetEventObject(this); - if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) ) - { - return true; - } - return false; -} - -void wxWindowBase::DoMoveInTabOrder(wxWindow *win, MoveKind move) -{ - // check that we're not a top level window - wxCHECK_RET( GetParent(), - _T("MoveBefore/AfterInTabOrder() don't work for TLWs!") ); - - // detect the special case when we have nothing to do anyhow and when the - // code below wouldn't work - if ( win == this ) - return; - - // find the target window in the siblings list - wxWindowList& siblings = GetParent()->GetChildren(); - wxWindowList::compatibility_iterator i = siblings.Find(win); - wxCHECK_RET( i, _T("MoveBefore/AfterInTabOrder(): win is not a sibling") ); - - // unfortunately, when wxUSE_STL == 1 DetachNode() is not implemented so we - // can't just move the node around - wxWindow *self = (wxWindow *)this; - siblings.DeleteObject(self); - if ( move == MoveAfter ) - { - i = i->GetNext(); - } - - if ( i ) - { - siblings.Insert(i, self); - } - else // MoveAfter and win was the last sibling - { - siblings.Append(self); - } -} - -// ---------------------------------------------------------------------------- -// focus handling -// ---------------------------------------------------------------------------- - -/*static*/ wxWindow* wxWindowBase::FindFocus() -{ - wxWindowBase *win = DoFindFocus(); - return win ? win->GetMainWindowOfCompositeControl() : NULL; -} - -// ---------------------------------------------------------------------------- -// drag and drop -// ---------------------------------------------------------------------------- - -#if wxUSE_DRAG_AND_DROP && !defined(__WXMSW__) - -class wxDragAcceptFilesImplTarget : public wxFileDropTarget -{ -public: - wxDragAcceptFilesImplTarget(wxWindowBase *win) : m_win(win) {} - - virtual bool OnDropFiles(wxCoord x, wxCoord y, - const wxArrayString& filenames) - { - wxDropFilesEvent event(wxEVT_DROP_FILES, - filenames.size(), - wxCArrayString(filenames).Release()); - event.SetEventObject(m_win); - event.m_pos.x = x; - event.m_pos.y = y; - - return m_win->GetEventHandler()->ProcessEvent(event); - } - -private: - wxWindowBase * const m_win; - - DECLARE_NO_COPY_CLASS(wxDragAcceptFilesImplTarget) -}; - - -// Generic version of DragAcceptFiles(). It works by installing a simple -// wxFileDropTarget-to-EVT_DROP_FILES adaptor and therefore cannot be used -// together with explicit SetDropTarget() calls. -void wxWindowBase::DragAcceptFiles(bool accept) -{ - if ( accept ) - { - wxASSERT_MSG( !GetDropTarget(), - _T("cannot use DragAcceptFiles() and SetDropTarget() together") ); - SetDropTarget(new wxDragAcceptFilesImplTarget(this)); - } - else - { - SetDropTarget(NULL); - } -} - -#endif // wxUSE_DRAG_AND_DROP && !defined(__WXMSW__) - -// ---------------------------------------------------------------------------- -// global functions -// ---------------------------------------------------------------------------- - -wxWindow* wxGetTopLevelParent(wxWindow *win) -{ - while ( win && !win->IsTopLevel() ) - win = win->GetParent(); - - return win; -} - -#if wxUSE_ACCESSIBILITY -// ---------------------------------------------------------------------------- -// accessible object for windows -// ---------------------------------------------------------------------------- - -// Can return either a child object, or an integer -// representing the child element, starting from 1. -wxAccStatus wxWindowAccessible::HitTest(const wxPoint& WXUNUSED(pt), int* WXUNUSED(childId), wxAccessible** WXUNUSED(childObject)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} - -// Returns the rectangle for this object (id = 0) or a child element (id > 0). -wxAccStatus wxWindowAccessible::GetLocation(wxRect& rect, int elementId) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - wxWindow* win = NULL; - if (elementId == 0) - { - win = GetWindow(); - } - else - { - if (elementId <= (int) GetWindow()->GetChildren().GetCount()) - { - win = GetWindow()->GetChildren().Item(elementId-1)->GetData(); - } - else - return wxACC_FAIL; - } - if (win) - { - rect = win->GetRect(); - if (win->GetParent() && !win->IsKindOf(CLASSINFO(wxTopLevelWindow))) - rect.SetPosition(win->GetParent()->ClientToScreen(rect.GetPosition())); - return wxACC_OK; - } - - return wxACC_NOT_IMPLEMENTED; -} - -// Navigates from fromId to toId/toObject. -wxAccStatus wxWindowAccessible::Navigate(wxNavDir navDir, int fromId, - int* WXUNUSED(toId), wxAccessible** toObject) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - switch (navDir) - { - case wxNAVDIR_FIRSTCHILD: - { - if (GetWindow()->GetChildren().GetCount() == 0) - return wxACC_FALSE; - wxWindow* childWindow = (wxWindow*) GetWindow()->GetChildren().GetFirst()->GetData(); - *toObject = childWindow->GetOrCreateAccessible(); - - return wxACC_OK; - } - case wxNAVDIR_LASTCHILD: - { - if (GetWindow()->GetChildren().GetCount() == 0) - return wxACC_FALSE; - wxWindow* childWindow = (wxWindow*) GetWindow()->GetChildren().GetLast()->GetData(); - *toObject = childWindow->GetOrCreateAccessible(); - - return wxACC_OK; - } - case wxNAVDIR_RIGHT: - case wxNAVDIR_DOWN: - case wxNAVDIR_NEXT: - { - wxWindowList::compatibility_iterator node = - wxWindowList::compatibility_iterator(); - if (fromId == 0) - { - // Can't navigate to sibling of this window - // if we're a top-level window. - if (!GetWindow()->GetParent()) - return wxACC_NOT_IMPLEMENTED; - - node = GetWindow()->GetParent()->GetChildren().Find(GetWindow()); - } - else - { - if (fromId <= (int) GetWindow()->GetChildren().GetCount()) - node = GetWindow()->GetChildren().Item(fromId-1); - } - - if (node && node->GetNext()) - { - wxWindow* nextWindow = node->GetNext()->GetData(); - *toObject = nextWindow->GetOrCreateAccessible(); - return wxACC_OK; - } - else - return wxACC_FALSE; - } - case wxNAVDIR_LEFT: - case wxNAVDIR_UP: - case wxNAVDIR_PREVIOUS: - { - wxWindowList::compatibility_iterator node = - wxWindowList::compatibility_iterator(); - if (fromId == 0) - { - // Can't navigate to sibling of this window - // if we're a top-level window. - if (!GetWindow()->GetParent()) - return wxACC_NOT_IMPLEMENTED; - - node = GetWindow()->GetParent()->GetChildren().Find(GetWindow()); - } - else - { - if (fromId <= (int) GetWindow()->GetChildren().GetCount()) - node = GetWindow()->GetChildren().Item(fromId-1); - } - - if (node && node->GetPrevious()) - { - wxWindow* previousWindow = node->GetPrevious()->GetData(); - *toObject = previousWindow->GetOrCreateAccessible(); - return wxACC_OK; - } - else - return wxACC_FALSE; - } - } - - return wxACC_NOT_IMPLEMENTED; -} - -// Gets the name of the specified object. -wxAccStatus wxWindowAccessible::GetName(int childId, wxString* name) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - wxString title; - - // If a child, leave wxWidgets to call the function on the actual - // child object. - if (childId > 0) - return wxACC_NOT_IMPLEMENTED; - - // This will eventually be replaced by specialised - // accessible classes, one for each kind of wxWidgets - // control or window. -#if wxUSE_BUTTON - if (GetWindow()->IsKindOf(CLASSINFO(wxButton))) - title = ((wxButton*) GetWindow())->GetLabel(); - else -#endif - title = GetWindow()->GetName(); - - if (!title.empty()) - { - *name = title; - return wxACC_OK; - } - else - return wxACC_NOT_IMPLEMENTED; -} - -// Gets the number of children. -wxAccStatus wxWindowAccessible::GetChildCount(int* childId) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - *childId = (int) GetWindow()->GetChildren().GetCount(); - return wxACC_OK; -} - -// Gets the specified child (starting from 1). -// If *child is NULL and return value is wxACC_OK, -// this means that the child is a simple element and -// not an accessible object. -wxAccStatus wxWindowAccessible::GetChild(int childId, wxAccessible** child) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - if (childId == 0) - { - *child = this; - return wxACC_OK; - } - - if (childId > (int) GetWindow()->GetChildren().GetCount()) - return wxACC_FAIL; - - wxWindow* childWindow = GetWindow()->GetChildren().Item(childId-1)->GetData(); - *child = childWindow->GetOrCreateAccessible(); - if (*child) - return wxACC_OK; - else - return wxACC_FAIL; -} - -// Gets the parent, or NULL. -wxAccStatus wxWindowAccessible::GetParent(wxAccessible** parent) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - wxWindow* parentWindow = GetWindow()->GetParent(); - if (!parentWindow) - { - *parent = NULL; - return wxACC_OK; - } - else - { - *parent = parentWindow->GetOrCreateAccessible(); - if (*parent) - return wxACC_OK; - else - return wxACC_FAIL; - } -} - -// Performs the default action. childId is 0 (the action for this object) -// or > 0 (the action for a child). -// Return wxACC_NOT_SUPPORTED if there is no default action for this -// window (e.g. an edit control). -wxAccStatus wxWindowAccessible::DoDefaultAction(int WXUNUSED(childId)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} - -// Gets the default action for this object (0) or > 0 (the action for a child). -// Return wxACC_OK even if there is no action. actionName is the action, or the empty -// string if there is no action. -// The retrieved string describes the action that is performed on an object, -// not what the object does as a result. For example, a toolbar button that prints -// a document has a default action of "Press" rather than "Prints the current document." -wxAccStatus wxWindowAccessible::GetDefaultAction(int WXUNUSED(childId), wxString* WXUNUSED(actionName)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} - -// Returns the description for this object or a child. -wxAccStatus wxWindowAccessible::GetDescription(int WXUNUSED(childId), wxString* description) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - wxString ht(GetWindow()->GetHelpTextAtPoint(wxDefaultPosition, wxHelpEvent::Origin_Keyboard)); - if (!ht.empty()) - { - *description = ht; - return wxACC_OK; - } - return wxACC_NOT_IMPLEMENTED; -} - -// Returns help text for this object or a child, similar to tooltip text. -wxAccStatus wxWindowAccessible::GetHelpText(int WXUNUSED(childId), wxString* helpText) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - wxString ht(GetWindow()->GetHelpTextAtPoint(wxDefaultPosition, wxHelpEvent::Origin_Keyboard)); - if (!ht.empty()) - { - *helpText = ht; - return wxACC_OK; - } - return wxACC_NOT_IMPLEMENTED; -} - -// Returns the keyboard shortcut for this object or child. -// Return e.g. ALT+K -wxAccStatus wxWindowAccessible::GetKeyboardShortcut(int WXUNUSED(childId), wxString* WXUNUSED(shortcut)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} - -// Returns a role constant. -wxAccStatus wxWindowAccessible::GetRole(int childId, wxAccRole* role) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - // If a child, leave wxWidgets to call the function on the actual - // child object. - if (childId > 0) - return wxACC_NOT_IMPLEMENTED; - - if (GetWindow()->IsKindOf(CLASSINFO(wxControl))) - return wxACC_NOT_IMPLEMENTED; -#if wxUSE_STATUSBAR - if (GetWindow()->IsKindOf(CLASSINFO(wxStatusBar))) - return wxACC_NOT_IMPLEMENTED; -#endif -#if wxUSE_TOOLBAR - if (GetWindow()->IsKindOf(CLASSINFO(wxToolBar))) - return wxACC_NOT_IMPLEMENTED; -#endif - - //*role = wxROLE_SYSTEM_CLIENT; - *role = wxROLE_SYSTEM_CLIENT; - return wxACC_OK; - - #if 0 - return wxACC_NOT_IMPLEMENTED; - #endif -} - -// Returns a state constant. -wxAccStatus wxWindowAccessible::GetState(int childId, long* state) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - // If a child, leave wxWidgets to call the function on the actual - // child object. - if (childId > 0) - return wxACC_NOT_IMPLEMENTED; - - if (GetWindow()->IsKindOf(CLASSINFO(wxControl))) - return wxACC_NOT_IMPLEMENTED; - -#if wxUSE_STATUSBAR - if (GetWindow()->IsKindOf(CLASSINFO(wxStatusBar))) - return wxACC_NOT_IMPLEMENTED; -#endif -#if wxUSE_TOOLBAR - if (GetWindow()->IsKindOf(CLASSINFO(wxToolBar))) - return wxACC_NOT_IMPLEMENTED; -#endif - - *state = 0; - return wxACC_OK; - - #if 0 - return wxACC_NOT_IMPLEMENTED; - #endif -} - -// Returns a localized string representing the value for the object -// or child. -wxAccStatus wxWindowAccessible::GetValue(int WXUNUSED(childId), wxString* WXUNUSED(strValue)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} - -// Selects the object or child. -wxAccStatus wxWindowAccessible::Select(int WXUNUSED(childId), wxAccSelectionFlags WXUNUSED(selectFlags)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} - -// Gets the window with the keyboard focus. -// If childId is 0 and child is NULL, no object in -// this subhierarchy has the focus. -// If this object has the focus, child should be 'this'. -wxAccStatus wxWindowAccessible::GetFocus(int* WXUNUSED(childId), wxAccessible** WXUNUSED(child)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} - -#if wxUSE_VARIANT -// Gets a variant representing the selected children -// of this object. -// Acceptable values: -// - a null variant (IsNull() returns true) -// - a list variant (GetType() == wxT("list") -// - an integer representing the selected child element, -// or 0 if this object is selected (GetType() == wxT("long") -// - a "void*" pointer to a wxAccessible child object -wxAccStatus wxWindowAccessible::GetSelections(wxVariant* WXUNUSED(selections)) -{ - wxASSERT( GetWindow() != NULL ); - if (!GetWindow()) - return wxACC_FAIL; - - return wxACC_NOT_IMPLEMENTED; -} -#endif // wxUSE_VARIANT - -#endif // wxUSE_ACCESSIBILITY - -// ---------------------------------------------------------------------------- -// RTL support -// ---------------------------------------------------------------------------- - -wxCoord -wxWindowBase::AdjustForLayoutDirection(wxCoord x, - wxCoord width, - wxCoord widthTotal) const -{ - if ( GetLayoutDirection() == wxLayout_RightToLeft ) - { - x = widthTotal - x - width; - } - - return x; -} - +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/window.cpp +// Purpose: common (to all ports) wxWindow functions +// Author: Julian Smart, Vadim Zeitlin +// Modified by: +// Created: 13/07/98 +// RCS-ID: $Id: wincmn.cpp 63032 2009-12-31 13:37:24Z VZ $ +// Copyright: (c) wxWidgets team +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/log.h" + #include "wx/intl.h" + #include "wx/frame.h" + #include "wx/window.h" + #include "wx/control.h" + #include "wx/checkbox.h" + #include "wx/radiobut.h" + #include "wx/statbox.h" + #include "wx/textctrl.h" + #include "wx/settings.h" + #include "wx/dialog.h" + #include "wx/msgdlg.h" + #include "wx/statusbr.h" + #include "wx/toolbar.h" + #include "wx/dcclient.h" + #include "wx/scrolbar.h" + #include "wx/layout.h" + #include "wx/sizer.h" +#endif //WX_PRECOMP + +#if wxUSE_DRAG_AND_DROP + #include "wx/dnd.h" +#endif // wxUSE_DRAG_AND_DROP + +#if wxUSE_ACCESSIBILITY + #include "wx/access.h" +#endif + +#if wxUSE_HELP + #include "wx/cshelp.h" +#endif // wxUSE_HELP + +#if wxUSE_TOOLTIPS + #include "wx/tooltip.h" +#endif // wxUSE_TOOLTIPS + +#if wxUSE_CARET + #include "wx/caret.h" +#endif // wxUSE_CARET + +#if wxUSE_SYSTEM_OPTIONS + #include "wx/sysopt.h" +#endif + +// For reporting compile- and runtime version of GTK+ in the ctrl+alt+mclick dialog. +// The gtk includes don't pull any other headers in, at least not on my system - MR +#ifdef __WXGTK__ + #ifdef __WXGTK20__ + #include + #else + #include + #endif + extern const unsigned int gtk_major_version; + extern const unsigned int gtk_minor_version; + extern const unsigned int gtk_micro_version; +#endif + +#include "wx/platinfo.h" + +// Windows List +WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows; + +// ---------------------------------------------------------------------------- +// static data +// ---------------------------------------------------------------------------- + +#if defined(__WXPALMOS__) +int wxWindowBase::ms_lastControlId = 32767; +#elif defined(__WXPM__) +int wxWindowBase::ms_lastControlId = 2000; +#else +int wxWindowBase::ms_lastControlId = -200; +#endif + +IMPLEMENT_ABSTRACT_CLASS(wxWindowBase, wxEvtHandler) + +// ---------------------------------------------------------------------------- +// event table +// ---------------------------------------------------------------------------- + +BEGIN_EVENT_TABLE(wxWindowBase, wxEvtHandler) + EVT_SYS_COLOUR_CHANGED(wxWindowBase::OnSysColourChanged) + EVT_INIT_DIALOG(wxWindowBase::OnInitDialog) + EVT_MIDDLE_DOWN(wxWindowBase::OnMiddleClick) + +#if wxUSE_HELP + EVT_HELP(wxID_ANY, wxWindowBase::OnHelp) +#endif // wxUSE_HELP + +END_EVENT_TABLE() + +// ============================================================================ +// implementation of the common functionality of the wxWindow class +// ============================================================================ + +// ---------------------------------------------------------------------------- +// initialization +// ---------------------------------------------------------------------------- + +// the default initialization +wxWindowBase::wxWindowBase() +{ + // no window yet, no parent nor children + m_parent = (wxWindow *)NULL; + m_windowId = wxID_ANY; + + // no constraints on the minimal window size + m_minWidth = + m_maxWidth = wxDefaultCoord; + m_minHeight = + m_maxHeight = wxDefaultCoord; + + // invalidiated cache value + m_bestSizeCache = wxDefaultSize; + + // window are created enabled and visible by default + m_isShown = + m_isEnabled = true; + + // the default event handler is just this window + m_eventHandler = this; + +#if wxUSE_VALIDATORS + // no validator + m_windowValidator = (wxValidator *) NULL; +#endif // wxUSE_VALIDATORS + + // the colours/fonts are default for now, so leave m_font, + // m_backgroundColour and m_foregroundColour uninitialized and set those + m_hasBgCol = + m_hasFgCol = + m_hasFont = false; + m_inheritBgCol = + m_inheritFgCol = + m_inheritFont = false; + + // no style bits + m_exStyle = + m_windowStyle = 0; + + m_backgroundStyle = wxBG_STYLE_SYSTEM; + +#if wxUSE_CONSTRAINTS + // no constraints whatsoever + m_constraints = (wxLayoutConstraints *) NULL; + m_constraintsInvolvedIn = (wxWindowList *) NULL; +#endif // wxUSE_CONSTRAINTS + + m_windowSizer = (wxSizer *) NULL; + m_containingSizer = (wxSizer *) NULL; + m_autoLayout = false; + +#if wxUSE_DRAG_AND_DROP + m_dropTarget = (wxDropTarget *)NULL; +#endif // wxUSE_DRAG_AND_DROP + +#if wxUSE_TOOLTIPS + m_tooltip = (wxToolTip *)NULL; +#endif // wxUSE_TOOLTIPS + +#if wxUSE_CARET + m_caret = (wxCaret *)NULL; +#endif // wxUSE_CARET + +#if wxUSE_PALETTE + m_hasCustomPalette = false; +#endif // wxUSE_PALETTE + +#if wxUSE_ACCESSIBILITY + m_accessible = NULL; +#endif + + m_virtualSize = wxDefaultSize; + + m_scrollHelper = (wxScrollHelper *) NULL; + + m_minVirtualWidth = + m_maxVirtualWidth = wxDefaultCoord; + m_minVirtualHeight = + m_maxVirtualHeight = wxDefaultCoord; + + m_windowVariant = wxWINDOW_VARIANT_NORMAL; +#if wxUSE_SYSTEM_OPTIONS + if ( wxSystemOptions::HasOption(wxWINDOW_DEFAULT_VARIANT) ) + { + m_windowVariant = (wxWindowVariant) wxSystemOptions::GetOptionInt( wxWINDOW_DEFAULT_VARIANT ) ; + } +#endif + + // Whether we're using the current theme for this window (wxGTK only for now) + m_themeEnabled = false; + + // VZ: this one shouldn't exist... + m_isBeingDeleted = false; +} + +// common part of window creation process +bool wxWindowBase::CreateBase(wxWindowBase *parent, + wxWindowID id, + const wxPoint& WXUNUSED(pos), + const wxSize& WXUNUSED(size), + long style, + const wxValidator& wxVALIDATOR_PARAM(validator), + const wxString& name) +{ +#if wxUSE_STATBOX + // wxGTK doesn't allow to create controls with static box as the parent so + // this will result in a crash when the program is ported to wxGTK so warn + // the user about it + + // if you get this assert, the correct solution is to create the controls + // as siblings of the static box + wxASSERT_MSG( !parent || !wxDynamicCast(parent, wxStaticBox), + _T("wxStaticBox can't be used as a window parent!") ); +#endif // wxUSE_STATBOX + + // ids are limited to 16 bits under MSW so if you care about portability, + // it's not a good idea to use ids out of this range (and negative ids are + // reserved for wxWidgets own usage) + wxASSERT_MSG( id == wxID_ANY || (id >= 0 && id < 32767), + _T("invalid id value") ); + + // generate a new id if the user doesn't care about it + m_windowId = id == wxID_ANY ? NewControlId() : id; + + // don't use SetWindowStyleFlag() here, this function should only be called + // to change the flag after creation as it tries to reflect the changes in + // flags by updating the window dynamically and we don't need this here + m_windowStyle = style; + + SetName(name); + SetParent(parent); + +#if wxUSE_VALIDATORS + SetValidator(validator); +#endif // wxUSE_VALIDATORS + + // if the parent window has wxWS_EX_VALIDATE_RECURSIVELY set, we want to + // have it too - like this it's possible to set it only in the top level + // dialog/frame and all children will inherit it by defult + if ( parent && (parent->GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) ) + { + SetExtraStyle(GetExtraStyle() | wxWS_EX_VALIDATE_RECURSIVELY); + } + + return true; +} + +bool wxWindowBase::ToggleWindowStyle(int flag) +{ + wxASSERT_MSG( flag, _T("flags with 0 value can't be toggled") ); + + bool rc; + long style = GetWindowStyleFlag(); + if ( style & flag ) + { + style &= ~flag; + rc = false; + } + else // currently off + { + style |= flag; + rc = true; + } + + SetWindowStyleFlag(style); + + return rc; +} + +// ---------------------------------------------------------------------------- +// destruction +// ---------------------------------------------------------------------------- + +// common clean up +wxWindowBase::~wxWindowBase() +{ + wxASSERT_MSG( GetCapture() != this, wxT("attempt to destroy window with mouse capture") ); + + // FIXME if these 2 cases result from programming errors in the user code + // we should probably assert here instead of silently fixing them + + // Just in case the window has been Closed, but we're then deleting + // immediately: don't leave dangling pointers. + wxPendingDelete.DeleteObject(this); + + // Just in case we've loaded a top-level window via LoadNativeDialog but + // we weren't a dialog class + wxTopLevelWindows.DeleteObject((wxWindow*)this); + + wxASSERT_MSG( GetChildren().GetCount() == 0, wxT("children not destroyed") ); + + // reset the top-level parent's default item if it is this widget + if ( m_parent ) + { + wxTopLevelWindow *tlw = wxDynamicCast(wxGetTopLevelParent((wxWindow*)this), + wxTopLevelWindow); + + if ( tlw ) + { + wxWindow* tmpDefaultItem = tlw->GetTmpDefaultItem(); + if ( tmpDefaultItem == this ) + tlw->SetTmpDefaultItem(NULL); + else if ( tmpDefaultItem ) + { + // A temporary default item masks the real default item, so + // temporarily unset the temporary default item so we can access the + // real default item. + tlw->SetTmpDefaultItem(NULL); + + if ( tlw->GetDefaultItem() == this ) + tlw->SetDefaultItem(NULL); + + // Set the temporary default item back. + tlw->SetTmpDefaultItem(tmpDefaultItem); + } + else if ( tlw->GetDefaultItem() == this ) + tlw->SetDefaultItem(NULL); + } + } + + // reset the dangling pointer our parent window may keep to us + if ( m_parent ) + { + m_parent->RemoveChild(this); + } + +#if wxUSE_CARET + delete m_caret; +#endif // wxUSE_CARET + +#if wxUSE_VALIDATORS + delete m_windowValidator; +#endif // wxUSE_VALIDATORS + +#if wxUSE_CONSTRAINTS + // Have to delete constraints/sizer FIRST otherwise sizers may try to look + // at deleted windows as they delete themselves. + DeleteRelatedConstraints(); + + if ( m_constraints ) + { + // This removes any dangling pointers to this window in other windows' + // constraintsInvolvedIn lists. + UnsetConstraints(m_constraints); + delete m_constraints; + m_constraints = NULL; + } +#endif // wxUSE_CONSTRAINTS + + if ( m_containingSizer ) + m_containingSizer->Detach( (wxWindow*)this ); + + delete m_windowSizer; + +#if wxUSE_DRAG_AND_DROP + delete m_dropTarget; +#endif // wxUSE_DRAG_AND_DROP + +#if wxUSE_TOOLTIPS + delete m_tooltip; +#endif // wxUSE_TOOLTIPS + +#if wxUSE_ACCESSIBILITY + delete m_accessible; +#endif + +#if wxUSE_HELP + // NB: this has to be called unconditionally, because we don't + // know whether this window has associated help text or not + wxHelpProvider *helpProvider = wxHelpProvider::Get(); + if ( helpProvider ) + helpProvider->RemoveHelp(this); +#endif +} + +void wxWindowBase::SendDestroyEvent() +{ + wxWindowDestroyEvent event; + event.SetEventObject(this); + event.SetId(GetId()); + GetEventHandler()->ProcessEvent(event); +} + +bool wxWindowBase::Destroy() +{ + delete this; + + return true; +} + +bool wxWindowBase::Close(bool force) +{ + wxCloseEvent event(wxEVT_CLOSE_WINDOW, m_windowId); + event.SetEventObject(this); + event.SetCanVeto(!force); + + // return false if window wasn't closed because the application vetoed the + // close event + return GetEventHandler()->ProcessEvent(event) && !event.GetVeto(); +} + +bool wxWindowBase::DestroyChildren() +{ + wxWindowList::compatibility_iterator node; + for ( ;; ) + { + // we iterate until the list becomes empty + node = GetChildren().GetFirst(); + if ( !node ) + break; + + wxWindow *child = node->GetData(); + + // note that we really want to call delete and not ->Destroy() here + // because we want to delete the child immediately, before we are + // deleted, and delayed deletion would result in problems as our (top + // level) child could outlive its parent + delete child; + + wxASSERT_MSG( !GetChildren().Find(child), + wxT("child didn't remove itself using RemoveChild()") ); + } + + return true; +} + +// ---------------------------------------------------------------------------- +// size/position related methods +// ---------------------------------------------------------------------------- + +// centre the window with respect to its parent in either (or both) directions +void wxWindowBase::DoCentre(int dir) +{ + wxCHECK_RET( !(dir & wxCENTRE_ON_SCREEN) && GetParent(), + _T("this method only implements centering child windows") ); + + SetSize(GetRect().CentreIn(GetParent()->GetClientSize(), dir)); +} + +// fits the window around the children +void wxWindowBase::Fit() +{ + if ( !GetChildren().empty() ) + { + SetSize(GetBestSize()); + } + //else: do nothing if we have no children +} + +// fits virtual size (ie. scrolled area etc.) around children +void wxWindowBase::FitInside() +{ + if ( GetChildren().GetCount() > 0 ) + { + SetVirtualSize( GetBestVirtualSize() ); + } +} + +// On Mac, scrollbars are explicitly children. +#ifdef __WXMAC__ +static bool wxHasRealChildren(const wxWindowBase* win) +{ + int realChildCount = 0; + + for ( wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindow *win = node->GetData(); + if ( !win->IsTopLevel() && win->IsShown() && !win->IsKindOf(CLASSINFO(wxScrollBar))) + realChildCount ++; + } + return (realChildCount > 0); +} +#endif + +void wxWindowBase::InvalidateBestSize() +{ + m_bestSizeCache = wxDefaultSize; + + // parent's best size calculation may depend on its children's + // as long as child window we are in is not top level window itself + // (because the TLW size is never resized automatically) + // so let's invalidate it as well to be safe: + if (m_parent && !IsTopLevel()) + m_parent->InvalidateBestSize(); +} + +// return the size best suited for the current window +wxSize wxWindowBase::DoGetBestSize() const +{ + wxSize best; + + if ( m_windowSizer ) + { + // Adjust to window size, since the return value of GetWindowSizeForVirtualSize is + // expressed in window and not client size + wxSize minSize = m_windowSizer->GetMinSize(); + wxSize size(GetSize()); + wxSize clientSize(GetClientSize()); + + wxSize minWindowSize(minSize.x + size.x - clientSize.x, + minSize.y + size.y - clientSize.y); + + best = GetWindowSizeForVirtualSize(minWindowSize); + + return best; + } +#if wxUSE_CONSTRAINTS + else if ( m_constraints ) + { + wxConstCast(this, wxWindowBase)->SatisfyConstraints(); + + // our minimal acceptable size is such that all our windows fit inside + int maxX = 0, + maxY = 0; + + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxLayoutConstraints *c = node->GetData()->GetConstraints(); + if ( !c ) + { + // it's not normal that we have an unconstrained child, but + // what can we do about it? + continue; + } + + int x = c->right.GetValue(), + y = c->bottom.GetValue(); + + if ( x > maxX ) + maxX = x; + + if ( y > maxY ) + maxY = y; + + // TODO: we must calculate the overlaps somehow, otherwise we + // will never return a size bigger than the current one :-( + } + + best = wxSize(maxX, maxY); + } +#endif // wxUSE_CONSTRAINTS + else if ( !GetChildren().empty() +#ifdef __WXMAC__ + && wxHasRealChildren(this) +#endif + ) + { + // our minimal acceptable size is such that all our visible child + // windows fit inside + int maxX = 0, + maxY = 0; + + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindow *win = node->GetData(); + if ( win->IsTopLevel() + || !win->IsShown() +#if wxUSE_STATUSBAR + || wxDynamicCast(win, wxStatusBar) +#endif // wxUSE_STATUSBAR + ) + { + // dialogs and frames lie in different top level windows - + // don't deal with them here; as for the status bars, they + // don't lie in the client area at all + continue; + } + + int wx, wy, ww, wh; + win->GetPosition(&wx, &wy); + + // if the window hadn't been positioned yet, assume that it is in + // the origin + if ( wx == wxDefaultCoord ) + wx = 0; + if ( wy == wxDefaultCoord ) + wy = 0; + + win->GetSize(&ww, &wh); + if ( wx + ww > maxX ) + maxX = wx + ww; + if ( wy + wh > maxY ) + maxY = wy + wh; + } + + best = wxSize(maxX, maxY); + } + else // ! has children + { + // for a generic window there is no natural best size so, if the + // minimal size is not set, use the current size but take care to + // remember it as minimal size for the next time because our best size + // should be constant: otherwise we could get into a situation when the + // window is initially at some size, then expanded to a larger size and + // then, when the containing window is shrunk back (because our initial + // best size had been used for computing the parent min size), we can't + // be shrunk back any more because our best size is now bigger + wxSize size = GetMinSize(); + if ( !size.IsFullySpecified() ) + { + size.SetDefaults(GetSize()); + wxConstCast(this, wxWindowBase)->SetMinSize(size); + } + + // return as-is, unadjusted by the client size difference. + return size; + } + + // Add any difference between size and client size + wxSize diff = GetSize() - GetClientSize(); + best.x += wxMax(0, diff.x); + best.y += wxMax(0, diff.y); + + return best; +} + +// helper of GetWindowBorderSize(): as many ports don't implement support for +// wxSYS_BORDER/EDGE_X/Y metrics in their wxSystemSettings, use hard coded +// fallbacks in this case +static int wxGetMetricOrDefault(wxSystemMetric what) +{ + int rc = wxSystemSettings::GetMetric(what); + if ( rc == -1 ) + { + switch ( what ) + { + case wxSYS_BORDER_X: + case wxSYS_BORDER_Y: + // 2D border is by default 1 pixel wide + rc = 1; + break; + + case wxSYS_EDGE_X: + case wxSYS_EDGE_Y: + // 3D borders are by default 2 pixels + rc = 2; + break; + + default: + wxFAIL_MSG( _T("unexpected wxGetMetricOrDefault() argument") ); + rc = 0; + } + } + + return rc; +} + +wxSize wxWindowBase::GetWindowBorderSize() const +{ + wxSize size; + + switch ( GetBorder() ) + { + case wxBORDER_NONE: + // nothing to do, size is already (0, 0) + break; + + case wxBORDER_SIMPLE: + case wxBORDER_STATIC: + size.x = wxGetMetricOrDefault(wxSYS_BORDER_X); + size.y = wxGetMetricOrDefault(wxSYS_BORDER_Y); + break; + + case wxBORDER_SUNKEN: + case wxBORDER_RAISED: + size.x = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_X), + wxGetMetricOrDefault(wxSYS_BORDER_X)); + size.y = wxMax(wxGetMetricOrDefault(wxSYS_EDGE_Y), + wxGetMetricOrDefault(wxSYS_BORDER_Y)); + break; + + case wxBORDER_DOUBLE: + size.x = wxGetMetricOrDefault(wxSYS_EDGE_X) + + wxGetMetricOrDefault(wxSYS_BORDER_X); + size.y = wxGetMetricOrDefault(wxSYS_EDGE_Y) + + wxGetMetricOrDefault(wxSYS_BORDER_Y); + break; + + default: + wxFAIL_MSG(_T("Unknown border style.")); + break; + } + + // we have borders on both sides + return size*2; +} + +wxSize wxWindowBase::GetEffectiveMinSize() const +{ + // merge the best size with the min size, giving priority to the min size + wxSize min = GetMinSize(); + if (min.x == wxDefaultCoord || min.y == wxDefaultCoord) + { + wxSize best = GetBestSize(); + if (min.x == wxDefaultCoord) min.x = best.x; + if (min.y == wxDefaultCoord) min.y = best.y; + } + return min; +} + + +void wxWindowBase::SetInitialSize(const wxSize& size) +{ + // Set the min size to the size passed in. This will usually either be + // wxDefaultSize or the size passed to this window's ctor/Create function. + SetMinSize(size); + + // Merge the size with the best size if needed + wxSize best = GetEffectiveMinSize(); + + // If the current size doesn't match then change it + if (GetSize() != best) + SetSize(best); +} + + +// by default the origin is not shifted +wxPoint wxWindowBase::GetClientAreaOrigin() const +{ + return wxPoint(0,0); +} + +wxSize wxWindowBase::ClientToWindowSize(const wxSize& size) const +{ + const wxSize diff(GetSize() - GetClientSize()); + + return wxSize(size.x == -1 ? -1 : size.x + diff.x, + size.y == -1 ? -1 : size.y + diff.y); +} + +wxSize wxWindowBase::WindowToClientSize(const wxSize& size) const +{ + const wxSize diff(GetSize() - GetClientSize()); + + return wxSize(size.x == -1 ? -1 : size.x - diff.x, + size.y == -1 ? -1 : size.y - diff.y); +} + +void wxWindowBase::SetWindowVariant( wxWindowVariant variant ) +{ + if ( m_windowVariant != variant ) + { + m_windowVariant = variant; + + DoSetWindowVariant(variant); + } +} + +void wxWindowBase::DoSetWindowVariant( wxWindowVariant variant ) +{ + // adjust the font height to correspond to our new variant (notice that + // we're only called if something really changed) + wxFont font = GetFont(); + int size = font.GetPointSize(); + switch ( variant ) + { + case wxWINDOW_VARIANT_NORMAL: + break; + + case wxWINDOW_VARIANT_SMALL: + size *= 3; + size /= 4; + break; + + case wxWINDOW_VARIANT_MINI: + size *= 2; + size /= 3; + break; + + case wxWINDOW_VARIANT_LARGE: + size *= 5; + size /= 4; + break; + + default: + wxFAIL_MSG(_T("unexpected window variant")); + break; + } + + font.SetPointSize(size); + SetFont(font); +} + +void wxWindowBase::DoSetSizeHints( int minW, int minH, + int maxW, int maxH, + int WXUNUSED(incW), int WXUNUSED(incH) ) +{ + wxCHECK_RET( (minW == wxDefaultCoord || maxW == wxDefaultCoord || minW <= maxW) && + (minH == wxDefaultCoord || maxH == wxDefaultCoord || minH <= maxH), + _T("min width/height must be less than max width/height!") ); + + m_minWidth = minW; + m_maxWidth = maxW; + m_minHeight = minH; + m_maxHeight = maxH; +} + + +void wxWindowBase::SetVirtualSizeHints( int minW, int minH, + int maxW, int maxH ) +{ + m_minVirtualWidth = minW; + m_maxVirtualWidth = maxW; + m_minVirtualHeight = minH; + m_maxVirtualHeight = maxH; +} + +void wxWindowBase::DoSetVirtualSize( int x, int y ) +{ + if ( m_minVirtualWidth != wxDefaultCoord && m_minVirtualWidth > x ) + x = m_minVirtualWidth; + if ( m_maxVirtualWidth != wxDefaultCoord && m_maxVirtualWidth < x ) + x = m_maxVirtualWidth; + if ( m_minVirtualHeight != wxDefaultCoord && m_minVirtualHeight > y ) + y = m_minVirtualHeight; + if ( m_maxVirtualHeight != wxDefaultCoord && m_maxVirtualHeight < y ) + y = m_maxVirtualHeight; + + m_virtualSize = wxSize(x, y); +} + +wxSize wxWindowBase::DoGetVirtualSize() const +{ + // we should use the entire client area so if it is greater than our + // virtual size, expand it to fit (otherwise if the window is big enough we + // wouldn't be using parts of it) + wxSize size = GetClientSize(); + if ( m_virtualSize.x > size.x ) + size.x = m_virtualSize.x; + + if ( m_virtualSize.y >= size.y ) + size.y = m_virtualSize.y; + + return size; +} + +void wxWindowBase::DoGetScreenPosition(int *x, int *y) const +{ + // screen position is the same as (0, 0) in client coords for non TLWs (and + // TLWs override this method) + if ( x ) + *x = 0; + if ( y ) + *y = 0; + + ClientToScreen(x, y); +} + +// ---------------------------------------------------------------------------- +// show/hide/enable/disable the window +// ---------------------------------------------------------------------------- + +bool wxWindowBase::Show(bool show) +{ + if ( show != m_isShown ) + { + m_isShown = show; + + return true; + } + else + { + return false; + } +} + +bool wxWindowBase::Enable(bool enable) +{ + if ( enable != m_isEnabled ) + { + m_isEnabled = enable; + + return true; + } + else + { + return false; + } +} + +bool wxWindowBase::IsShownOnScreen() const +{ + // A window is shown on screen if it itself is shown and so are all its + // parents. But if a window is toplevel one, then its always visible on + // screen if IsShown() returns true, even if it has a hidden parent. + return IsShown() && + (IsTopLevel() || !GetParent() || GetParent()->IsShownOnScreen()); +} + +// ---------------------------------------------------------------------------- +// RTTI +// ---------------------------------------------------------------------------- + +bool wxWindowBase::IsTopLevel() const +{ + return false; +} + +// ---------------------------------------------------------------------------- +// reparenting the window +// ---------------------------------------------------------------------------- + +void wxWindowBase::AddChild(wxWindowBase *child) +{ + wxCHECK_RET( child, wxT("can't add a NULL child") ); + + // this should never happen and it will lead to a crash later if it does + // because RemoveChild() will remove only one node from the children list + // and the other(s) one(s) will be left with dangling pointers in them + wxASSERT_MSG( !GetChildren().Find((wxWindow*)child), _T("AddChild() called twice") ); + + GetChildren().Append((wxWindow*)child); + child->SetParent(this); +} + +void wxWindowBase::RemoveChild(wxWindowBase *child) +{ + wxCHECK_RET( child, wxT("can't remove a NULL child") ); + + GetChildren().DeleteObject((wxWindow *)child); + child->SetParent(NULL); +} + +bool wxWindowBase::Reparent(wxWindowBase *newParent) +{ + wxWindow *oldParent = GetParent(); + if ( newParent == oldParent ) + { + // nothing done + return false; + } + + // unlink this window from the existing parent. + if ( oldParent ) + { + oldParent->RemoveChild(this); + } + else + { + wxTopLevelWindows.DeleteObject((wxWindow *)this); + } + + // add it to the new one + if ( newParent ) + { + newParent->AddChild(this); + } + else + { + wxTopLevelWindows.Append((wxWindow *)this); + } + + return true; +} + +// ---------------------------------------------------------------------------- +// event handler stuff +// ---------------------------------------------------------------------------- + +void wxWindowBase::PushEventHandler(wxEvtHandler *handler) +{ + wxEvtHandler *handlerOld = GetEventHandler(); + + handler->SetNextHandler(handlerOld); + + if ( handlerOld ) + GetEventHandler()->SetPreviousHandler(handler); + + SetEventHandler(handler); +} + +wxEvtHandler *wxWindowBase::PopEventHandler(bool deleteHandler) +{ + wxEvtHandler *handlerA = GetEventHandler(); + if ( handlerA ) + { + wxEvtHandler *handlerB = handlerA->GetNextHandler(); + handlerA->SetNextHandler((wxEvtHandler *)NULL); + + if ( handlerB ) + handlerB->SetPreviousHandler((wxEvtHandler *)NULL); + SetEventHandler(handlerB); + + if ( deleteHandler ) + { + delete handlerA; + handlerA = (wxEvtHandler *)NULL; + } + } + + return handlerA; +} + +bool wxWindowBase::RemoveEventHandler(wxEvtHandler *handler) +{ + wxCHECK_MSG( handler, false, _T("RemoveEventHandler(NULL) called") ); + + wxEvtHandler *handlerPrev = NULL, + *handlerCur = GetEventHandler(); + while ( handlerCur ) + { + wxEvtHandler *handlerNext = handlerCur->GetNextHandler(); + + if ( handlerCur == handler ) + { + if ( handlerPrev ) + { + handlerPrev->SetNextHandler(handlerNext); + } + else + { + SetEventHandler(handlerNext); + } + + if ( handlerNext ) + { + handlerNext->SetPreviousHandler ( handlerPrev ); + } + + handler->SetNextHandler(NULL); + handler->SetPreviousHandler(NULL); + + return true; + } + + handlerPrev = handlerCur; + handlerCur = handlerNext; + } + + wxFAIL_MSG( _T("where has the event handler gone?") ); + + return false; +} + +// ---------------------------------------------------------------------------- +// colours, fonts &c +// ---------------------------------------------------------------------------- + +void wxWindowBase::InheritAttributes() +{ + const wxWindowBase * const parent = GetParent(); + if ( !parent ) + return; + + // we only inherit attributes which had been explicitly set for the parent + // which ensures that this only happens if the user really wants it and + // not by default which wouldn't make any sense in modern GUIs where the + // controls don't all use the same fonts (nor colours) + if ( parent->m_inheritFont && !m_hasFont ) + SetFont(parent->GetFont()); + + // in addition, there is a possibility to explicitly forbid inheriting + // colours at each class level by overriding ShouldInheritColours() + if ( ShouldInheritColours() ) + { + if ( parent->m_inheritFgCol && !m_hasFgCol ) + SetForegroundColour(parent->GetForegroundColour()); + + // inheriting (solid) background colour is wrong as it totally breaks + // any kind of themed backgrounds + // + // instead, the controls should use the same background as their parent + // (ideally by not drawing it at all) +#if 0 + if ( parent->m_inheritBgCol && !m_hasBgCol ) + SetBackgroundColour(parent->GetBackgroundColour()); +#endif // 0 + } +} + +/* static */ wxVisualAttributes +wxWindowBase::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant)) +{ + // it is important to return valid values for all attributes from here, + // GetXXX() below rely on this + wxVisualAttributes attrs; + attrs.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT); + attrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); + + // On Smartphone/PocketPC, wxSYS_COLOUR_WINDOW is a better reflection of + // the usual background colour than wxSYS_COLOUR_BTNFACE. + // It's a pity that wxSYS_COLOUR_WINDOW isn't always a suitable background + // colour on other platforms. + +#if defined(__WXWINCE__) && (defined(__SMARTPHONE__) || defined(__POCKETPC__)) + attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW); +#else + attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE); +#endif + return attrs; +} + +wxColour wxWindowBase::GetBackgroundColour() const +{ + if ( !m_backgroundColour.Ok() ) + { + wxASSERT_MSG( !m_hasBgCol, _T("we have invalid explicit bg colour?") ); + + // get our default background colour + wxColour colBg = GetDefaultAttributes().colBg; + + // we must return some valid colour to avoid redoing this every time + // and also to avoid surprizing the applications written for older + // wxWidgets versions where GetBackgroundColour() always returned + // something -- so give them something even if it doesn't make sense + // for this window (e.g. it has a themed background) + if ( !colBg.Ok() ) + colBg = GetClassDefaultAttributes().colBg; + + return colBg; + } + else + return m_backgroundColour; +} + +wxColour wxWindowBase::GetForegroundColour() const +{ + // logic is the same as above + if ( !m_hasFgCol && !m_foregroundColour.Ok() ) + { + wxASSERT_MSG( !m_hasFgCol, _T("we have invalid explicit fg colour?") ); + + wxColour colFg = GetDefaultAttributes().colFg; + + if ( !colFg.Ok() ) + colFg = GetClassDefaultAttributes().colFg; + + return colFg; + } + else + return m_foregroundColour; +} + +bool wxWindowBase::SetBackgroundColour( const wxColour &colour ) +{ + if ( colour == m_backgroundColour ) + return false; + + m_hasBgCol = colour.Ok(); + if ( m_backgroundStyle != wxBG_STYLE_CUSTOM ) + m_backgroundStyle = m_hasBgCol ? wxBG_STYLE_COLOUR : wxBG_STYLE_SYSTEM; + + m_inheritBgCol = m_hasBgCol; + m_backgroundColour = colour; + SetThemeEnabled( !m_hasBgCol && !m_foregroundColour.Ok() ); + return true; +} + +bool wxWindowBase::SetForegroundColour( const wxColour &colour ) +{ + if (colour == m_foregroundColour ) + return false; + + m_hasFgCol = colour.Ok(); + m_inheritFgCol = m_hasFgCol; + m_foregroundColour = colour; + SetThemeEnabled( !m_hasFgCol && !m_backgroundColour.Ok() ); + return true; +} + +bool wxWindowBase::SetCursor(const wxCursor& cursor) +{ + // setting an invalid cursor is ok, it means that we don't have any special + // cursor + if ( m_cursor.IsSameAs(cursor) ) + { + // no change + return false; + } + + m_cursor = cursor; + + return true; +} + +wxFont wxWindowBase::GetFont() const +{ + // logic is the same as in GetBackgroundColour() + if ( !m_font.Ok() ) + { + wxASSERT_MSG( !m_hasFont, _T("we have invalid explicit font?") ); + + wxFont font = GetDefaultAttributes().font; + if ( !font.Ok() ) + font = GetClassDefaultAttributes().font; + + return font; + } + else + return m_font; +} + +bool wxWindowBase::SetFont(const wxFont& font) +{ + if ( font == m_font ) + { + // no change + return false; + } + + m_font = font; + m_hasFont = font.Ok(); + m_inheritFont = m_hasFont; + + InvalidateBestSize(); + + return true; +} + +#if wxUSE_PALETTE + +void wxWindowBase::SetPalette(const wxPalette& pal) +{ + m_hasCustomPalette = true; + m_palette = pal; + + // VZ: can anyone explain me what do we do here? + wxWindowDC d((wxWindow *) this); + d.SetPalette(pal); +} + +wxWindow *wxWindowBase::GetAncestorWithCustomPalette() const +{ + wxWindow *win = (wxWindow *)this; + while ( win && !win->HasCustomPalette() ) + { + win = win->GetParent(); + } + + return win; +} + +#endif // wxUSE_PALETTE + +#if wxUSE_CARET +void wxWindowBase::SetCaret(wxCaret *caret) +{ + if ( m_caret ) + { + delete m_caret; + } + + m_caret = caret; + + if ( m_caret ) + { + wxASSERT_MSG( m_caret->GetWindow() == this, + wxT("caret should be created associated to this window") ); + } +} +#endif // wxUSE_CARET + +#if wxUSE_VALIDATORS +// ---------------------------------------------------------------------------- +// validators +// ---------------------------------------------------------------------------- + +void wxWindowBase::SetValidator(const wxValidator& validator) +{ + if ( m_windowValidator ) + delete m_windowValidator; + + m_windowValidator = (wxValidator *)validator.Clone(); + + if ( m_windowValidator ) + m_windowValidator->SetWindow(this); +} +#endif // wxUSE_VALIDATORS + +// ---------------------------------------------------------------------------- +// update region stuff +// ---------------------------------------------------------------------------- + +wxRect wxWindowBase::GetUpdateClientRect() const +{ + wxRegion rgnUpdate = GetUpdateRegion(); + rgnUpdate.Intersect(GetClientRect()); + wxRect rectUpdate = rgnUpdate.GetBox(); + wxPoint ptOrigin = GetClientAreaOrigin(); + rectUpdate.x -= ptOrigin.x; + rectUpdate.y -= ptOrigin.y; + + return rectUpdate; +} + +bool wxWindowBase::DoIsExposed(int x, int y) const +{ + return m_updateRegion.Contains(x, y) != wxOutRegion; +} + +bool wxWindowBase::DoIsExposed(int x, int y, int w, int h) const +{ + return m_updateRegion.Contains(x, y, w, h) != wxOutRegion; +} + +void wxWindowBase::ClearBackground() +{ + // wxGTK uses its own version, no need to add never used code +#ifndef __WXGTK__ + wxClientDC dc((wxWindow *)this); + wxBrush brush(GetBackgroundColour(), wxSOLID); + dc.SetBackground(brush); + dc.Clear(); +#endif // __WXGTK__ +} + +// ---------------------------------------------------------------------------- +// find child window by id or name +// ---------------------------------------------------------------------------- + +wxWindow *wxWindowBase::FindWindow(long id) const +{ + if ( id == m_windowId ) + return (wxWindow *)this; + + wxWindowBase *res = (wxWindow *)NULL; + wxWindowList::compatibility_iterator node; + for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() ) + { + wxWindowBase *child = node->GetData(); + res = child->FindWindow( id ); + } + + return (wxWindow *)res; +} + +wxWindow *wxWindowBase::FindWindow(const wxString& name) const +{ + if ( name == m_windowName ) + return (wxWindow *)this; + + wxWindowBase *res = (wxWindow *)NULL; + wxWindowList::compatibility_iterator node; + for ( node = m_children.GetFirst(); node && !res; node = node->GetNext() ) + { + wxWindow *child = node->GetData(); + res = child->FindWindow(name); + } + + return (wxWindow *)res; +} + + +// find any window by id or name or label: If parent is non-NULL, look through +// children for a label or title matching the specified string. If NULL, look +// through all top-level windows. +// +// to avoid duplicating code we reuse the same helper function but with +// different comparators + +typedef bool (*wxFindWindowCmp)(const wxWindow *win, + const wxString& label, long id); + +static +bool wxFindWindowCmpLabels(const wxWindow *win, const wxString& label, + long WXUNUSED(id)) +{ + return win->GetLabel() == label; +} + +static +bool wxFindWindowCmpNames(const wxWindow *win, const wxString& label, + long WXUNUSED(id)) +{ + return win->GetName() == label; +} + +static +bool wxFindWindowCmpIds(const wxWindow *win, const wxString& WXUNUSED(label), + long id) +{ + return win->GetId() == id; +} + +// recursive helper for the FindWindowByXXX() functions +static +wxWindow *wxFindWindowRecursively(const wxWindow *parent, + const wxString& label, + long id, + wxFindWindowCmp cmp) +{ + if ( parent ) + { + // see if this is the one we're looking for + if ( (*cmp)(parent, label, id) ) + return (wxWindow *)parent; + + // It wasn't, so check all its children + for ( wxWindowList::compatibility_iterator node = parent->GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + // recursively check each child + wxWindow *win = (wxWindow *)node->GetData(); + wxWindow *retwin = wxFindWindowRecursively(win, label, id, cmp); + if (retwin) + return retwin; + } + } + + // Not found + return NULL; +} + +// helper for FindWindowByXXX() +static +wxWindow *wxFindWindowHelper(const wxWindow *parent, + const wxString& label, + long id, + wxFindWindowCmp cmp) +{ + if ( parent ) + { + // just check parent and all its children + return wxFindWindowRecursively(parent, label, id, cmp); + } + + // start at very top of wx's windows + for ( wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst(); + node; + node = node->GetNext() ) + { + // recursively check each window & its children + wxWindow *win = node->GetData(); + wxWindow *retwin = wxFindWindowRecursively(win, label, id, cmp); + if (retwin) + return retwin; + } + + return NULL; +} + +/* static */ +wxWindow * +wxWindowBase::FindWindowByLabel(const wxString& title, const wxWindow *parent) +{ + return wxFindWindowHelper(parent, title, 0, wxFindWindowCmpLabels); +} + +/* static */ +wxWindow * +wxWindowBase::FindWindowByName(const wxString& title, const wxWindow *parent) +{ + wxWindow *win = wxFindWindowHelper(parent, title, 0, wxFindWindowCmpNames); + + if ( !win ) + { + // fall back to the label + win = FindWindowByLabel(title, parent); + } + + return win; +} + +/* static */ +wxWindow * +wxWindowBase::FindWindowById( long id, const wxWindow* parent ) +{ + return wxFindWindowHelper(parent, wxEmptyString, id, wxFindWindowCmpIds); +} + +// ---------------------------------------------------------------------------- +// dialog oriented functions +// ---------------------------------------------------------------------------- + +void wxWindowBase::MakeModal(bool modal) +{ + // Disable all other windows + if ( IsTopLevel() ) + { + wxWindowList::compatibility_iterator node = wxTopLevelWindows.GetFirst(); + while (node) + { + wxWindow *win = node->GetData(); + if (win != this) + win->Enable(!modal); + + node = node->GetNext(); + } + } +} + +bool wxWindowBase::Validate() +{ +#if wxUSE_VALIDATORS + bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0; + + wxWindowList::compatibility_iterator node; + for ( node = m_children.GetFirst(); node; node = node->GetNext() ) + { + wxWindowBase *child = node->GetData(); + wxValidator *validator = child->GetValidator(); + if ( validator && !validator->Validate((wxWindow *)this) ) + { + return false; + } + + if ( recurse && !child->Validate() ) + { + return false; + } + } +#endif // wxUSE_VALIDATORS + + return true; +} + +bool wxWindowBase::TransferDataToWindow() +{ +#if wxUSE_VALIDATORS + bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0; + + wxWindowList::compatibility_iterator node; + for ( node = m_children.GetFirst(); node; node = node->GetNext() ) + { + wxWindowBase *child = node->GetData(); + wxValidator *validator = child->GetValidator(); + if ( validator && !validator->TransferToWindow() ) + { + wxLogWarning(_("Could not transfer data to window")); +#if wxUSE_LOG + wxLog::FlushActive(); +#endif // wxUSE_LOG + + return false; + } + + if ( recurse ) + { + if ( !child->TransferDataToWindow() ) + { + // warning already given + return false; + } + } + } +#endif // wxUSE_VALIDATORS + + return true; +} + +bool wxWindowBase::TransferDataFromWindow() +{ +#if wxUSE_VALIDATORS + bool recurse = (GetExtraStyle() & wxWS_EX_VALIDATE_RECURSIVELY) != 0; + + wxWindowList::compatibility_iterator node; + for ( node = m_children.GetFirst(); node; node = node->GetNext() ) + { + wxWindow *child = node->GetData(); + wxValidator *validator = child->GetValidator(); + if ( validator && !validator->TransferFromWindow() ) + { + // nop warning here because the application is supposed to give + // one itself - we don't know here what might have gone wrongly + + return false; + } + + if ( recurse ) + { + if ( !child->TransferDataFromWindow() ) + { + // warning already given + return false; + } + } + } +#endif // wxUSE_VALIDATORS + + return true; +} + +void wxWindowBase::InitDialog() +{ + wxInitDialogEvent event(GetId()); + event.SetEventObject( this ); + GetEventHandler()->ProcessEvent(event); +} + +// ---------------------------------------------------------------------------- +// context-sensitive help support +// ---------------------------------------------------------------------------- + +#if wxUSE_HELP + +// associate this help text with this window +void wxWindowBase::SetHelpText(const wxString& text) +{ + wxHelpProvider *helpProvider = wxHelpProvider::Get(); + if ( helpProvider ) + { + helpProvider->AddHelp(this, text); + } +} + +// associate this help text with all windows with the same id as this +// one +void wxWindowBase::SetHelpTextForId(const wxString& text) +{ + wxHelpProvider *helpProvider = wxHelpProvider::Get(); + if ( helpProvider ) + { + helpProvider->AddHelp(GetId(), text); + } +} + +// get the help string associated with this window (may be empty) +// default implementation forwards calls to the help provider +wxString +wxWindowBase::GetHelpTextAtPoint(const wxPoint & WXUNUSED(pt), + wxHelpEvent::Origin WXUNUSED(origin)) const +{ + wxString text; + wxHelpProvider *helpProvider = wxHelpProvider::Get(); + if ( helpProvider ) + { + text = helpProvider->GetHelp(this); + } + + return text; +} + +// show help for this window +void wxWindowBase::OnHelp(wxHelpEvent& event) +{ + wxHelpProvider *helpProvider = wxHelpProvider::Get(); + if ( helpProvider ) + { + wxPoint pos = event.GetPosition(); + const wxHelpEvent::Origin origin = event.GetOrigin(); + if ( origin == wxHelpEvent::Origin_Keyboard ) + { + // if the help event was generated from keyboard it shouldn't + // appear at the mouse position (which is still the only position + // associated with help event) if the mouse is far away, although + // we still do use the mouse position if it's over the window + // because we suppose the user looks approximately at the mouse + // already and so it would be more convenient than showing tooltip + // at some arbitrary position which can be quite far from it + const wxRect rectClient = GetClientRect(); + if ( !rectClient.Contains(ScreenToClient(pos)) ) + { + // position help slightly under and to the right of this window + pos = ClientToScreen(wxPoint( + 2*GetCharWidth(), + rectClient.height + GetCharHeight() + )); + } + } + + if ( helpProvider->ShowHelpAtPoint(this, pos, origin) ) + { + // skip the event.Skip() below + return; + } + } + + event.Skip(); +} + +#endif // wxUSE_HELP + +// ---------------------------------------------------------------------------- +// tooltips +// ---------------------------------------------------------------------------- + +#if wxUSE_TOOLTIPS + +void wxWindowBase::SetToolTip( const wxString &tip ) +{ + // don't create the new tooltip if we already have one + if ( m_tooltip ) + { + m_tooltip->SetTip( tip ); + } + else + { + SetToolTip( new wxToolTip( tip ) ); + } + + // setting empty tooltip text does not remove the tooltip any more - use + // SetToolTip((wxToolTip *)NULL) for this +} + +void wxWindowBase::DoSetToolTip(wxToolTip *tooltip) +{ + if ( m_tooltip != tooltip ) + { + if ( m_tooltip ) + delete m_tooltip; + + m_tooltip = tooltip; + } +} + +#endif // wxUSE_TOOLTIPS + +// ---------------------------------------------------------------------------- +// constraints and sizers +// ---------------------------------------------------------------------------- + +#if wxUSE_CONSTRAINTS + +void wxWindowBase::SetConstraints( wxLayoutConstraints *constraints ) +{ + if ( m_constraints ) + { + UnsetConstraints(m_constraints); + delete m_constraints; + } + m_constraints = constraints; + if ( m_constraints ) + { + // Make sure other windows know they're part of a 'meaningful relationship' + if ( m_constraints->left.GetOtherWindow() && (m_constraints->left.GetOtherWindow() != this) ) + m_constraints->left.GetOtherWindow()->AddConstraintReference(this); + if ( m_constraints->top.GetOtherWindow() && (m_constraints->top.GetOtherWindow() != this) ) + m_constraints->top.GetOtherWindow()->AddConstraintReference(this); + if ( m_constraints->right.GetOtherWindow() && (m_constraints->right.GetOtherWindow() != this) ) + m_constraints->right.GetOtherWindow()->AddConstraintReference(this); + if ( m_constraints->bottom.GetOtherWindow() && (m_constraints->bottom.GetOtherWindow() != this) ) + m_constraints->bottom.GetOtherWindow()->AddConstraintReference(this); + if ( m_constraints->width.GetOtherWindow() && (m_constraints->width.GetOtherWindow() != this) ) + m_constraints->width.GetOtherWindow()->AddConstraintReference(this); + if ( m_constraints->height.GetOtherWindow() && (m_constraints->height.GetOtherWindow() != this) ) + m_constraints->height.GetOtherWindow()->AddConstraintReference(this); + if ( m_constraints->centreX.GetOtherWindow() && (m_constraints->centreX.GetOtherWindow() != this) ) + m_constraints->centreX.GetOtherWindow()->AddConstraintReference(this); + if ( m_constraints->centreY.GetOtherWindow() && (m_constraints->centreY.GetOtherWindow() != this) ) + m_constraints->centreY.GetOtherWindow()->AddConstraintReference(this); + } +} + +// This removes any dangling pointers to this window in other windows' +// constraintsInvolvedIn lists. +void wxWindowBase::UnsetConstraints(wxLayoutConstraints *c) +{ + if ( c ) + { + if ( c->left.GetOtherWindow() && (c->top.GetOtherWindow() != this) ) + c->left.GetOtherWindow()->RemoveConstraintReference(this); + if ( c->top.GetOtherWindow() && (c->top.GetOtherWindow() != this) ) + c->top.GetOtherWindow()->RemoveConstraintReference(this); + if ( c->right.GetOtherWindow() && (c->right.GetOtherWindow() != this) ) + c->right.GetOtherWindow()->RemoveConstraintReference(this); + if ( c->bottom.GetOtherWindow() && (c->bottom.GetOtherWindow() != this) ) + c->bottom.GetOtherWindow()->RemoveConstraintReference(this); + if ( c->width.GetOtherWindow() && (c->width.GetOtherWindow() != this) ) + c->width.GetOtherWindow()->RemoveConstraintReference(this); + if ( c->height.GetOtherWindow() && (c->height.GetOtherWindow() != this) ) + c->height.GetOtherWindow()->RemoveConstraintReference(this); + if ( c->centreX.GetOtherWindow() && (c->centreX.GetOtherWindow() != this) ) + c->centreX.GetOtherWindow()->RemoveConstraintReference(this); + if ( c->centreY.GetOtherWindow() && (c->centreY.GetOtherWindow() != this) ) + c->centreY.GetOtherWindow()->RemoveConstraintReference(this); + } +} + +// Back-pointer to other windows we're involved with, so if we delete this +// window, we must delete any constraints we're involved with. +void wxWindowBase::AddConstraintReference(wxWindowBase *otherWin) +{ + if ( !m_constraintsInvolvedIn ) + m_constraintsInvolvedIn = new wxWindowList; + if ( !m_constraintsInvolvedIn->Find((wxWindow *)otherWin) ) + m_constraintsInvolvedIn->Append((wxWindow *)otherWin); +} + +// REMOVE back-pointer to other windows we're involved with. +void wxWindowBase::RemoveConstraintReference(wxWindowBase *otherWin) +{ + if ( m_constraintsInvolvedIn ) + m_constraintsInvolvedIn->DeleteObject((wxWindow *)otherWin); +} + +// Reset any constraints that mention this window +void wxWindowBase::DeleteRelatedConstraints() +{ + if ( m_constraintsInvolvedIn ) + { + wxWindowList::compatibility_iterator node = m_constraintsInvolvedIn->GetFirst(); + while (node) + { + wxWindow *win = node->GetData(); + wxLayoutConstraints *constr = win->GetConstraints(); + + // Reset any constraints involving this window + if ( constr ) + { + constr->left.ResetIfWin(this); + constr->top.ResetIfWin(this); + constr->right.ResetIfWin(this); + constr->bottom.ResetIfWin(this); + constr->width.ResetIfWin(this); + constr->height.ResetIfWin(this); + constr->centreX.ResetIfWin(this); + constr->centreY.ResetIfWin(this); + } + + wxWindowList::compatibility_iterator next = node->GetNext(); + m_constraintsInvolvedIn->Erase(node); + node = next; + } + + delete m_constraintsInvolvedIn; + m_constraintsInvolvedIn = (wxWindowList *) NULL; + } +} + +#endif // wxUSE_CONSTRAINTS + +void wxWindowBase::SetSizer(wxSizer *sizer, bool deleteOld) +{ + if ( sizer == m_windowSizer) + return; + + if ( m_windowSizer ) + { + m_windowSizer->SetContainingWindow(NULL); + + if ( deleteOld ) + delete m_windowSizer; + } + + m_windowSizer = sizer; + if ( m_windowSizer ) + { + m_windowSizer->SetContainingWindow((wxWindow *)this); + } + + SetAutoLayout(m_windowSizer != NULL); +} + +void wxWindowBase::SetSizerAndFit(wxSizer *sizer, bool deleteOld) +{ + SetSizer( sizer, deleteOld ); + sizer->SetSizeHints( (wxWindow*) this ); +} + + +void wxWindowBase::SetContainingSizer(wxSizer* sizer) +{ + // adding a window to a sizer twice is going to result in fatal and + // hard to debug problems later because when deleting the second + // associated wxSizerItem we're going to dereference a dangling + // pointer; so try to detect this as early as possible + wxASSERT_MSG( !sizer || m_containingSizer != sizer, + _T("Adding a window to the same sizer twice?") ); + + m_containingSizer = sizer; +} + +#if wxUSE_CONSTRAINTS + +void wxWindowBase::SatisfyConstraints() +{ + wxLayoutConstraints *constr = GetConstraints(); + bool wasOk = constr && constr->AreSatisfied(); + + ResetConstraints(); // Mark all constraints as unevaluated + + int noChanges = 1; + + // if we're a top level panel (i.e. our parent is frame/dialog), our + // own constraints will never be satisfied any more unless we do it + // here + if ( wasOk ) + { + while ( noChanges > 0 ) + { + LayoutPhase1(&noChanges); + } + } + + LayoutPhase2(&noChanges); +} + +#endif // wxUSE_CONSTRAINTS + +bool wxWindowBase::Layout() +{ + // If there is a sizer, use it instead of the constraints + if ( GetSizer() ) + { + int w = 0, h = 0; + GetVirtualSize(&w, &h); + GetSizer()->SetDimension( 0, 0, w, h ); + } +#if wxUSE_CONSTRAINTS + else + { + SatisfyConstraints(); // Find the right constraints values + SetConstraintSizes(); // Recursively set the real window sizes + } +#endif + + return true; +} + +#if wxUSE_CONSTRAINTS + +// first phase of the constraints evaluation: set our own constraints +bool wxWindowBase::LayoutPhase1(int *noChanges) +{ + wxLayoutConstraints *constr = GetConstraints(); + + return !constr || constr->SatisfyConstraints(this, noChanges); +} + +// second phase: set the constraints for our children +bool wxWindowBase::LayoutPhase2(int *noChanges) +{ + *noChanges = 0; + + // Layout children + DoPhase(1); + + // Layout grand children + DoPhase(2); + + return true; +} + +// Do a phase of evaluating child constraints +bool wxWindowBase::DoPhase(int phase) +{ + // the list containing the children for which the constraints are already + // set correctly + wxWindowList succeeded; + + // the max number of iterations we loop before concluding that we can't set + // the constraints + static const int maxIterations = 500; + + for ( int noIterations = 0; noIterations < maxIterations; noIterations++ ) + { + int noChanges = 0; + + // loop over all children setting their constraints + for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + node; + node = node->GetNext() ) + { + wxWindow *child = node->GetData(); + if ( child->IsTopLevel() ) + { + // top level children are not inside our client area + continue; + } + + if ( !child->GetConstraints() || succeeded.Find(child) ) + { + // this one is either already ok or nothing we can do about it + continue; + } + + int tempNoChanges = 0; + bool success = phase == 1 ? child->LayoutPhase1(&tempNoChanges) + : child->LayoutPhase2(&tempNoChanges); + noChanges += tempNoChanges; + + if ( success ) + { + succeeded.Append(child); + } + } + + if ( !noChanges ) + { + // constraints are set + break; + } + } + + return true; +} + +void wxWindowBase::ResetConstraints() +{ + wxLayoutConstraints *constr = GetConstraints(); + if ( constr ) + { + constr->left.SetDone(false); + constr->top.SetDone(false); + constr->right.SetDone(false); + constr->bottom.SetDone(false); + constr->width.SetDone(false); + constr->height.SetDone(false); + constr->centreX.SetDone(false); + constr->centreY.SetDone(false); + } + + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + while (node) + { + wxWindow *win = node->GetData(); + if ( !win->IsTopLevel() ) + win->ResetConstraints(); + node = node->GetNext(); + } +} + +// Need to distinguish between setting the 'fake' size for windows and sizers, +// and setting the real values. +void wxWindowBase::SetConstraintSizes(bool recurse) +{ + wxLayoutConstraints *constr = GetConstraints(); + if ( constr && constr->AreSatisfied() ) + { + int x = constr->left.GetValue(); + int y = constr->top.GetValue(); + int w = constr->width.GetValue(); + int h = constr->height.GetValue(); + + if ( (constr->width.GetRelationship() != wxAsIs ) || + (constr->height.GetRelationship() != wxAsIs) ) + { + SetSize(x, y, w, h); + } + else + { + // If we don't want to resize this window, just move it... + Move(x, y); + } + } + else if ( constr ) + { + wxLogDebug(wxT("Constraints not satisfied for %s named '%s'."), + GetClassInfo()->GetClassName(), + GetName().c_str()); + } + + if ( recurse ) + { + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + while (node) + { + wxWindow *win = node->GetData(); + if ( !win->IsTopLevel() && win->GetConstraints() ) + win->SetConstraintSizes(); + node = node->GetNext(); + } + } +} + +// Only set the size/position of the constraint (if any) +void wxWindowBase::SetSizeConstraint(int x, int y, int w, int h) +{ + wxLayoutConstraints *constr = GetConstraints(); + if ( constr ) + { + if ( x != wxDefaultCoord ) + { + constr->left.SetValue(x); + constr->left.SetDone(true); + } + if ( y != wxDefaultCoord ) + { + constr->top.SetValue(y); + constr->top.SetDone(true); + } + if ( w != wxDefaultCoord ) + { + constr->width.SetValue(w); + constr->width.SetDone(true); + } + if ( h != wxDefaultCoord ) + { + constr->height.SetValue(h); + constr->height.SetDone(true); + } + } +} + +void wxWindowBase::MoveConstraint(int x, int y) +{ + wxLayoutConstraints *constr = GetConstraints(); + if ( constr ) + { + if ( x != wxDefaultCoord ) + { + constr->left.SetValue(x); + constr->left.SetDone(true); + } + if ( y != wxDefaultCoord ) + { + constr->top.SetValue(y); + constr->top.SetDone(true); + } + } +} + +void wxWindowBase::GetSizeConstraint(int *w, int *h) const +{ + wxLayoutConstraints *constr = GetConstraints(); + if ( constr ) + { + *w = constr->width.GetValue(); + *h = constr->height.GetValue(); + } + else + GetSize(w, h); +} + +void wxWindowBase::GetClientSizeConstraint(int *w, int *h) const +{ + wxLayoutConstraints *constr = GetConstraints(); + if ( constr ) + { + *w = constr->width.GetValue(); + *h = constr->height.GetValue(); + } + else + GetClientSize(w, h); +} + +void wxWindowBase::GetPositionConstraint(int *x, int *y) const +{ + wxLayoutConstraints *constr = GetConstraints(); + if ( constr ) + { + *x = constr->left.GetValue(); + *y = constr->top.GetValue(); + } + else + GetPosition(x, y); +} + +#endif // wxUSE_CONSTRAINTS + +void wxWindowBase::AdjustForParentClientOrigin(int& x, int& y, int sizeFlags) const +{ + // don't do it for the dialogs/frames - they float independently of their + // parent + if ( !IsTopLevel() ) + { + wxWindow *parent = GetParent(); + if ( !(sizeFlags & wxSIZE_NO_ADJUSTMENTS) && parent ) + { + wxPoint pt(parent->GetClientAreaOrigin()); + x += pt.x; + y += pt.y; + } + } +} + +// ---------------------------------------------------------------------------- +// Update UI processing +// ---------------------------------------------------------------------------- + +void wxWindowBase::UpdateWindowUI(long flags) +{ + wxUpdateUIEvent event(GetId()); + event.SetEventObject(this); + + if ( GetEventHandler()->ProcessEvent(event) ) + { + DoUpdateWindowUI(event); + } + + if (flags & wxUPDATE_UI_RECURSE) + { + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + while (node) + { + wxWindow* child = (wxWindow*) node->GetData(); + child->UpdateWindowUI(flags); + node = node->GetNext(); + } + } +} + +// do the window-specific processing after processing the update event +void wxWindowBase::DoUpdateWindowUI(wxUpdateUIEvent& event) +{ + if ( event.GetSetEnabled() ) + Enable(event.GetEnabled()); + + if ( event.GetSetShown() ) + Show(event.GetShown()); +} + +// ---------------------------------------------------------------------------- +// dialog units translations +// ---------------------------------------------------------------------------- + +wxPoint wxWindowBase::ConvertPixelsToDialog(const wxPoint& pt) +{ + int charWidth = GetCharWidth(); + int charHeight = GetCharHeight(); + wxPoint pt2 = wxDefaultPosition; + if (pt.x != wxDefaultCoord) + pt2.x = (int) ((pt.x * 4) / charWidth); + if (pt.y != wxDefaultCoord) + pt2.y = (int) ((pt.y * 8) / charHeight); + + return pt2; +} + +wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt) +{ + int charWidth = GetCharWidth(); + int charHeight = GetCharHeight(); + wxPoint pt2 = wxDefaultPosition; + if (pt.x != wxDefaultCoord) + pt2.x = (int) ((pt.x * charWidth) / 4); + if (pt.y != wxDefaultCoord) + pt2.y = (int) ((pt.y * charHeight) / 8); + + return pt2; +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +// propagate the colour change event to the subwindows +void wxWindowBase::OnSysColourChanged(wxSysColourChangedEvent& event) +{ + wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); + while ( node ) + { + // Only propagate to non-top-level windows + wxWindow *win = node->GetData(); + if ( !win->IsTopLevel() ) + { + wxSysColourChangedEvent event2; + event.SetEventObject(win); + win->GetEventHandler()->ProcessEvent(event2); + } + + node = node->GetNext(); + } + + Refresh(); +} + +// the default action is to populate dialog with data when it's created, +// and nudge the UI into displaying itself correctly in case +// we've turned the wxUpdateUIEvents frequency down low. +void wxWindowBase::OnInitDialog( wxInitDialogEvent &WXUNUSED(event) ) +{ + TransferDataToWindow(); + + // Update the UI at this point + UpdateWindowUI(wxUPDATE_UI_RECURSE); +} + +// methods for drawing the sizers in a visible way +#ifdef __WXDEBUG__ + +static void DrawSizers(wxWindowBase *win); + +static void DrawBorder(wxWindowBase *win, const wxRect& rect, bool fill = false) +{ + wxClientDC dc((wxWindow *)win); + dc.SetPen(*wxRED_PEN); + dc.SetBrush(fill ? wxBrush(*wxRED, wxCROSSDIAG_HATCH): *wxTRANSPARENT_BRUSH); + dc.DrawRectangle(rect.Deflate(1, 1)); +} + +static void DrawSizer(wxWindowBase *win, wxSizer *sizer) +{ + const wxSizerItemList& items = sizer->GetChildren(); + for ( wxSizerItemList::const_iterator i = items.begin(), + end = items.end(); + i != end; + ++i ) + { + wxSizerItem *item = *i; + if ( item->IsSizer() ) + { + DrawBorder(win, item->GetRect().Deflate(2)); + DrawSizer(win, item->GetSizer()); + } + else if ( item->IsSpacer() ) + { + DrawBorder(win, item->GetRect().Deflate(2), true); + } + else if ( item->IsWindow() ) + { + DrawSizers(item->GetWindow()); + } + } +} + +static void DrawSizers(wxWindowBase *win) +{ + wxSizer *sizer = win->GetSizer(); + if ( sizer ) + { + DrawBorder(win, win->GetClientSize()); + DrawSizer(win, sizer); + } + else // no sizer, still recurse into the children + { + const wxWindowList& children = win->GetChildren(); + for ( wxWindowList::const_iterator i = children.begin(), + end = children.end(); + i != end; + ++i ) + { + DrawSizers(*i); + } + } +} + +#endif // __WXDEBUG__ + +// process special middle clicks +void wxWindowBase::OnMiddleClick( wxMouseEvent& event ) +{ + if ( event.ControlDown() && event.AltDown() ) + { +#ifdef __WXDEBUG__ + // Ctrl-Alt-Shift-mclick makes the sizers visible in debug builds + if ( event.ShiftDown() ) + { + DrawSizers(this); + return; + } +#endif // __WXDEBUG__ + +#if wxUSE_MSGDLG + // don't translate these strings, they're for diagnostics purposes only + wxString msg; + msg.Printf(_T("wxWidgets Library (%s port)\n") + _T("Version %d.%d.%d%s%s, compiled at %s %s\n") + _T("Runtime version of toolkit used is %d.%d.%s\n") + _T("Copyright (c) 1995-2010 wxWidgets team"), + wxPlatformInfo::Get().GetPortIdName().c_str(), + wxMAJOR_VERSION, + wxMINOR_VERSION, + wxRELEASE_NUMBER, +#if wxUSE_UNICODE + L" (Unicode)", +#else + wxEmptyString, +#endif +#ifdef __WXDEBUG__ + _T(" Debug build"), +#else + wxEmptyString, +#endif + __TDATE__, + __TTIME__, + wxPlatformInfo::Get().GetToolkitMajorVersion(), + wxPlatformInfo::Get().GetToolkitMinorVersion(), +#ifdef __WXGTK__ + wxString::Format(_T("\nThe compile-time GTK+ version is %d.%d.%d."), GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION).c_str() +#else + wxEmptyString +#endif + ); + + wxMessageBox(msg, _T("wxWidgets information"), + wxICON_INFORMATION | wxOK, + (wxWindow *)this); + } + else +#endif // wxUSE_MSGDLG + { + event.Skip(); + } +} + +// ---------------------------------------------------------------------------- +// accessibility +// ---------------------------------------------------------------------------- + +#if wxUSE_ACCESSIBILITY +void wxWindowBase::SetAccessible(wxAccessible* accessible) +{ + if (m_accessible && (accessible != m_accessible)) + delete m_accessible; + m_accessible = accessible; + if (m_accessible) + m_accessible->SetWindow((wxWindow*) this); +} + +// Returns the accessible object, creating if necessary. +wxAccessible* wxWindowBase::GetOrCreateAccessible() +{ + if (!m_accessible) + m_accessible = CreateAccessible(); + return m_accessible; +} + +// Override to create a specific accessible object. +wxAccessible* wxWindowBase::CreateAccessible() +{ + return new wxWindowAccessible((wxWindow*) this); +} + +#endif + +// ---------------------------------------------------------------------------- +// list classes implementation +// ---------------------------------------------------------------------------- + +#if wxUSE_STL + +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wxWindowList) + +#else // !wxUSE_STL + +void wxWindowListNode::DeleteData() +{ + delete (wxWindow *)GetData(); +} + +#endif // wxUSE_STL/!wxUSE_STL + +// ---------------------------------------------------------------------------- +// borders +// ---------------------------------------------------------------------------- + +wxBorder wxWindowBase::GetBorder(long flags) const +{ + wxBorder border = (wxBorder)(flags & wxBORDER_MASK); + if ( border == wxBORDER_DEFAULT ) + { + border = GetDefaultBorder(); + } + + return border; +} + +wxBorder wxWindowBase::GetDefaultBorder() const +{ + return wxBORDER_NONE; +} + +// ---------------------------------------------------------------------------- +// hit testing +// ---------------------------------------------------------------------------- + +wxHitTest wxWindowBase::DoHitTest(wxCoord x, wxCoord y) const +{ + // here we just check if the point is inside the window or not + + // check the top and left border first + bool outside = x < 0 || y < 0; + if ( !outside ) + { + // check the right and bottom borders too + wxSize size = GetSize(); + outside = x >= size.x || y >= size.y; + } + + return outside ? wxHT_WINDOW_OUTSIDE : wxHT_WINDOW_INSIDE; +} + +// ---------------------------------------------------------------------------- +// mouse capture +// ---------------------------------------------------------------------------- + +struct WXDLLEXPORT wxWindowNext +{ + wxWindow *win; + wxWindowNext *next; +} *wxWindowBase::ms_winCaptureNext = NULL; +wxWindow *wxWindowBase::ms_winCaptureCurrent = NULL; +bool wxWindowBase::ms_winCaptureChanging = false; + +void wxWindowBase::CaptureMouse() +{ + wxLogTrace(_T("mousecapture"), _T("CaptureMouse(%p)"), wx_static_cast(void*, this)); + + wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive CaptureMouse call?") ); + + ms_winCaptureChanging = true; + + wxWindow *winOld = GetCapture(); + if ( winOld ) + { + ((wxWindowBase*) winOld)->DoReleaseMouse(); + + // save it on stack + wxWindowNext *item = new wxWindowNext; + item->win = winOld; + item->next = ms_winCaptureNext; + ms_winCaptureNext = item; + } + //else: no mouse capture to save + + DoCaptureMouse(); + ms_winCaptureCurrent = (wxWindow*)this; + + ms_winCaptureChanging = false; +} + +void wxWindowBase::ReleaseMouse() +{ + wxLogTrace(_T("mousecapture"), _T("ReleaseMouse(%p)"), wx_static_cast(void*, this)); + + wxASSERT_MSG( !ms_winCaptureChanging, _T("recursive ReleaseMouse call?") ); + + wxASSERT_MSG( GetCapture() == this, wxT("attempt to release mouse, but this window hasn't captured it") ); + + ms_winCaptureChanging = true; + + DoReleaseMouse(); + ms_winCaptureCurrent = NULL; + + if ( ms_winCaptureNext ) + { + ((wxWindowBase*)ms_winCaptureNext->win)->DoCaptureMouse(); + ms_winCaptureCurrent = ms_winCaptureNext->win; + + wxWindowNext *item = ms_winCaptureNext; + ms_winCaptureNext = item->next; + delete item; + } + //else: stack is empty, no previous capture + + ms_winCaptureChanging = false; + + wxLogTrace(_T("mousecapture"), + (const wxChar *) _T("After ReleaseMouse() mouse is captured by %p"), + wx_static_cast(void*, GetCapture())); +} + +static void DoNotifyWindowAboutCaptureLost(wxWindow *win) +{ + wxMouseCaptureLostEvent event(win->GetId()); + event.SetEventObject(win); + if ( !win->GetEventHandler()->ProcessEvent(event) ) + { + // windows must handle this event, otherwise the app wouldn't behave + // correctly if it loses capture unexpectedly; see the discussion here: + // http://sourceforge.net/tracker/index.php?func=detail&aid=1153662&group_id=9863&atid=109863 + // http://article.gmane.org/gmane.comp.lib.wxwidgets.devel/82376 + wxFAIL_MSG( _T("window that captured the mouse didn't process wxEVT_MOUSE_CAPTURE_LOST") ); + } +} + +/* static */ +void wxWindowBase::NotifyCaptureLost() +{ + // don't do anything if capture lost was expected, i.e. resulted from + // a wx call to ReleaseMouse or CaptureMouse: + if ( ms_winCaptureChanging ) + return; + + // if the capture was lost unexpectedly, notify every window that has + // capture (on stack or current) about it and clear the stack: + + if ( ms_winCaptureCurrent ) + { + DoNotifyWindowAboutCaptureLost(ms_winCaptureCurrent); + ms_winCaptureCurrent = NULL; + } + + while ( ms_winCaptureNext ) + { + wxWindowNext *item = ms_winCaptureNext; + ms_winCaptureNext = item->next; + + DoNotifyWindowAboutCaptureLost(item->win); + + delete item; + } +} + +#if wxUSE_HOTKEY + +bool +wxWindowBase::RegisterHotKey(int WXUNUSED(hotkeyId), + int WXUNUSED(modifiers), + int WXUNUSED(keycode)) +{ + // not implemented + return false; +} + +bool wxWindowBase::UnregisterHotKey(int WXUNUSED(hotkeyId)) +{ + // not implemented + return false; +} + +#endif // wxUSE_HOTKEY + +// ---------------------------------------------------------------------------- +// event processing +// ---------------------------------------------------------------------------- + +bool wxWindowBase::TryValidator(wxEvent& wxVALIDATOR_PARAM(event)) +{ +#if wxUSE_VALIDATORS + // Can only use the validator of the window which + // is receiving the event + if ( event.GetEventObject() == this ) + { + wxValidator *validator = GetValidator(); + if ( validator && validator->ProcessEvent(event) ) + { + return true; + } + } +#endif // wxUSE_VALIDATORS + + return false; +} + +bool wxWindowBase::TryParent(wxEvent& event) +{ + // carry on up the parent-child hierarchy if the propagation count hasn't + // reached zero yet + if ( event.ShouldPropagate() ) + { + // honour the requests to stop propagation at this window: this is + // used by the dialogs, for example, to prevent processing the events + // from the dialog controls in the parent frame which rarely, if ever, + // makes sense + if ( !(GetExtraStyle() & wxWS_EX_BLOCK_EVENTS) ) + { + wxWindow *parent = GetParent(); + if ( parent && !parent->IsBeingDeleted() ) + { + wxPropagateOnce propagateOnce(event); + + return parent->GetEventHandler()->ProcessEvent(event); + } + } + } + + return wxEvtHandler::TryParent(event); +} + +// ---------------------------------------------------------------------------- +// window relationships +// ---------------------------------------------------------------------------- + +wxWindow *wxWindowBase::DoGetSibling(MoveKind order) const +{ + wxCHECK_MSG( GetParent(), NULL, + _T("GetPrev/NextSibling() don't work for TLWs!") ); + + wxWindowList& siblings = GetParent()->GetChildren(); + wxWindowList::compatibility_iterator i = siblings.Find((wxWindow *)this); + wxCHECK_MSG( i, NULL, _T("window not a child of its parent?") ); + + if ( order == MoveBefore ) + i = i->GetPrevious(); + else // MoveAfter + i = i->GetNext(); + + return i ? i->GetData() : NULL; +} + +// ---------------------------------------------------------------------------- +// keyboard navigation +// ---------------------------------------------------------------------------- + +// Navigates in the specified direction. +bool wxWindowBase::Navigate(int flags) +{ + wxNavigationKeyEvent eventNav; + eventNav.SetFlags(flags); + eventNav.SetEventObject(this); + if ( GetParent()->GetEventHandler()->ProcessEvent(eventNav) ) + { + return true; + } + return false; +} + +void wxWindowBase::DoMoveInTabOrder(wxWindow *win, MoveKind move) +{ + // check that we're not a top level window + wxCHECK_RET( GetParent(), + _T("MoveBefore/AfterInTabOrder() don't work for TLWs!") ); + + // detect the special case when we have nothing to do anyhow and when the + // code below wouldn't work + if ( win == this ) + return; + + // find the target window in the siblings list + wxWindowList& siblings = GetParent()->GetChildren(); + wxWindowList::compatibility_iterator i = siblings.Find(win); + wxCHECK_RET( i, _T("MoveBefore/AfterInTabOrder(): win is not a sibling") ); + + // unfortunately, when wxUSE_STL == 1 DetachNode() is not implemented so we + // can't just move the node around + wxWindow *self = (wxWindow *)this; + siblings.DeleteObject(self); + if ( move == MoveAfter ) + { + i = i->GetNext(); + } + + if ( i ) + { + siblings.Insert(i, self); + } + else // MoveAfter and win was the last sibling + { + siblings.Append(self); + } +} + +// ---------------------------------------------------------------------------- +// focus handling +// ---------------------------------------------------------------------------- + +/*static*/ wxWindow* wxWindowBase::FindFocus() +{ + wxWindowBase *win = DoFindFocus(); + return win ? win->GetMainWindowOfCompositeControl() : NULL; +} + +// ---------------------------------------------------------------------------- +// drag and drop +// ---------------------------------------------------------------------------- + +#if wxUSE_DRAG_AND_DROP && !defined(__WXMSW__) + +class wxDragAcceptFilesImplTarget : public wxFileDropTarget +{ +public: + wxDragAcceptFilesImplTarget(wxWindowBase *win) : m_win(win) {} + + virtual bool OnDropFiles(wxCoord x, wxCoord y, + const wxArrayString& filenames) + { + wxDropFilesEvent event(wxEVT_DROP_FILES, + filenames.size(), + wxCArrayString(filenames).Release()); + event.SetEventObject(m_win); + event.m_pos.x = x; + event.m_pos.y = y; + + return m_win->GetEventHandler()->ProcessEvent(event); + } + +private: + wxWindowBase * const m_win; + + DECLARE_NO_COPY_CLASS(wxDragAcceptFilesImplTarget) +}; + + +// Generic version of DragAcceptFiles(). It works by installing a simple +// wxFileDropTarget-to-EVT_DROP_FILES adaptor and therefore cannot be used +// together with explicit SetDropTarget() calls. +void wxWindowBase::DragAcceptFiles(bool accept) +{ + if ( accept ) + { + wxASSERT_MSG( !GetDropTarget(), + _T("cannot use DragAcceptFiles() and SetDropTarget() together") ); + SetDropTarget(new wxDragAcceptFilesImplTarget(this)); + } + else + { + SetDropTarget(NULL); + } +} + +#endif // wxUSE_DRAG_AND_DROP && !defined(__WXMSW__) + +// ---------------------------------------------------------------------------- +// global functions +// ---------------------------------------------------------------------------- + +wxWindow* wxGetTopLevelParent(wxWindow *win) +{ + while ( win && !win->IsTopLevel() ) + win = win->GetParent(); + + return win; +} + +#if wxUSE_ACCESSIBILITY +// ---------------------------------------------------------------------------- +// accessible object for windows +// ---------------------------------------------------------------------------- + +// Can return either a child object, or an integer +// representing the child element, starting from 1. +wxAccStatus wxWindowAccessible::HitTest(const wxPoint& WXUNUSED(pt), int* WXUNUSED(childId), wxAccessible** WXUNUSED(childObject)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} + +// Returns the rectangle for this object (id = 0) or a child element (id > 0). +wxAccStatus wxWindowAccessible::GetLocation(wxRect& rect, int elementId) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + wxWindow* win = NULL; + if (elementId == 0) + { + win = GetWindow(); + } + else + { + if (elementId <= (int) GetWindow()->GetChildren().GetCount()) + { + win = GetWindow()->GetChildren().Item(elementId-1)->GetData(); + } + else + return wxACC_FAIL; + } + if (win) + { + rect = win->GetRect(); + if (win->GetParent() && !win->IsKindOf(CLASSINFO(wxTopLevelWindow))) + rect.SetPosition(win->GetParent()->ClientToScreen(rect.GetPosition())); + return wxACC_OK; + } + + return wxACC_NOT_IMPLEMENTED; +} + +// Navigates from fromId to toId/toObject. +wxAccStatus wxWindowAccessible::Navigate(wxNavDir navDir, int fromId, + int* WXUNUSED(toId), wxAccessible** toObject) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + switch (navDir) + { + case wxNAVDIR_FIRSTCHILD: + { + if (GetWindow()->GetChildren().GetCount() == 0) + return wxACC_FALSE; + wxWindow* childWindow = (wxWindow*) GetWindow()->GetChildren().GetFirst()->GetData(); + *toObject = childWindow->GetOrCreateAccessible(); + + return wxACC_OK; + } + case wxNAVDIR_LASTCHILD: + { + if (GetWindow()->GetChildren().GetCount() == 0) + return wxACC_FALSE; + wxWindow* childWindow = (wxWindow*) GetWindow()->GetChildren().GetLast()->GetData(); + *toObject = childWindow->GetOrCreateAccessible(); + + return wxACC_OK; + } + case wxNAVDIR_RIGHT: + case wxNAVDIR_DOWN: + case wxNAVDIR_NEXT: + { + wxWindowList::compatibility_iterator node = + wxWindowList::compatibility_iterator(); + if (fromId == 0) + { + // Can't navigate to sibling of this window + // if we're a top-level window. + if (!GetWindow()->GetParent()) + return wxACC_NOT_IMPLEMENTED; + + node = GetWindow()->GetParent()->GetChildren().Find(GetWindow()); + } + else + { + if (fromId <= (int) GetWindow()->GetChildren().GetCount()) + node = GetWindow()->GetChildren().Item(fromId-1); + } + + if (node && node->GetNext()) + { + wxWindow* nextWindow = node->GetNext()->GetData(); + *toObject = nextWindow->GetOrCreateAccessible(); + return wxACC_OK; + } + else + return wxACC_FALSE; + } + case wxNAVDIR_LEFT: + case wxNAVDIR_UP: + case wxNAVDIR_PREVIOUS: + { + wxWindowList::compatibility_iterator node = + wxWindowList::compatibility_iterator(); + if (fromId == 0) + { + // Can't navigate to sibling of this window + // if we're a top-level window. + if (!GetWindow()->GetParent()) + return wxACC_NOT_IMPLEMENTED; + + node = GetWindow()->GetParent()->GetChildren().Find(GetWindow()); + } + else + { + if (fromId <= (int) GetWindow()->GetChildren().GetCount()) + node = GetWindow()->GetChildren().Item(fromId-1); + } + + if (node && node->GetPrevious()) + { + wxWindow* previousWindow = node->GetPrevious()->GetData(); + *toObject = previousWindow->GetOrCreateAccessible(); + return wxACC_OK; + } + else + return wxACC_FALSE; + } + } + + return wxACC_NOT_IMPLEMENTED; +} + +// Gets the name of the specified object. +wxAccStatus wxWindowAccessible::GetName(int childId, wxString* name) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + wxString title; + + // If a child, leave wxWidgets to call the function on the actual + // child object. + if (childId > 0) + return wxACC_NOT_IMPLEMENTED; + + // This will eventually be replaced by specialised + // accessible classes, one for each kind of wxWidgets + // control or window. +#if wxUSE_BUTTON + if (GetWindow()->IsKindOf(CLASSINFO(wxButton))) + title = ((wxButton*) GetWindow())->GetLabel(); + else +#endif + title = GetWindow()->GetName(); + + if (!title.empty()) + { + *name = title; + return wxACC_OK; + } + else + return wxACC_NOT_IMPLEMENTED; +} + +// Gets the number of children. +wxAccStatus wxWindowAccessible::GetChildCount(int* childId) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + *childId = (int) GetWindow()->GetChildren().GetCount(); + return wxACC_OK; +} + +// Gets the specified child (starting from 1). +// If *child is NULL and return value is wxACC_OK, +// this means that the child is a simple element and +// not an accessible object. +wxAccStatus wxWindowAccessible::GetChild(int childId, wxAccessible** child) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + if (childId == 0) + { + *child = this; + return wxACC_OK; + } + + if (childId > (int) GetWindow()->GetChildren().GetCount()) + return wxACC_FAIL; + + wxWindow* childWindow = GetWindow()->GetChildren().Item(childId-1)->GetData(); + *child = childWindow->GetOrCreateAccessible(); + if (*child) + return wxACC_OK; + else + return wxACC_FAIL; +} + +// Gets the parent, or NULL. +wxAccStatus wxWindowAccessible::GetParent(wxAccessible** parent) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + wxWindow* parentWindow = GetWindow()->GetParent(); + if (!parentWindow) + { + *parent = NULL; + return wxACC_OK; + } + else + { + *parent = parentWindow->GetOrCreateAccessible(); + if (*parent) + return wxACC_OK; + else + return wxACC_FAIL; + } +} + +// Performs the default action. childId is 0 (the action for this object) +// or > 0 (the action for a child). +// Return wxACC_NOT_SUPPORTED if there is no default action for this +// window (e.g. an edit control). +wxAccStatus wxWindowAccessible::DoDefaultAction(int WXUNUSED(childId)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} + +// Gets the default action for this object (0) or > 0 (the action for a child). +// Return wxACC_OK even if there is no action. actionName is the action, or the empty +// string if there is no action. +// The retrieved string describes the action that is performed on an object, +// not what the object does as a result. For example, a toolbar button that prints +// a document has a default action of "Press" rather than "Prints the current document." +wxAccStatus wxWindowAccessible::GetDefaultAction(int WXUNUSED(childId), wxString* WXUNUSED(actionName)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} + +// Returns the description for this object or a child. +wxAccStatus wxWindowAccessible::GetDescription(int WXUNUSED(childId), wxString* description) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + wxString ht(GetWindow()->GetHelpTextAtPoint(wxDefaultPosition, wxHelpEvent::Origin_Keyboard)); + if (!ht.empty()) + { + *description = ht; + return wxACC_OK; + } + return wxACC_NOT_IMPLEMENTED; +} + +// Returns help text for this object or a child, similar to tooltip text. +wxAccStatus wxWindowAccessible::GetHelpText(int WXUNUSED(childId), wxString* helpText) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + wxString ht(GetWindow()->GetHelpTextAtPoint(wxDefaultPosition, wxHelpEvent::Origin_Keyboard)); + if (!ht.empty()) + { + *helpText = ht; + return wxACC_OK; + } + return wxACC_NOT_IMPLEMENTED; +} + +// Returns the keyboard shortcut for this object or child. +// Return e.g. ALT+K +wxAccStatus wxWindowAccessible::GetKeyboardShortcut(int WXUNUSED(childId), wxString* WXUNUSED(shortcut)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} + +// Returns a role constant. +wxAccStatus wxWindowAccessible::GetRole(int childId, wxAccRole* role) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + // If a child, leave wxWidgets to call the function on the actual + // child object. + if (childId > 0) + return wxACC_NOT_IMPLEMENTED; + + if (GetWindow()->IsKindOf(CLASSINFO(wxControl))) + return wxACC_NOT_IMPLEMENTED; +#if wxUSE_STATUSBAR + if (GetWindow()->IsKindOf(CLASSINFO(wxStatusBar))) + return wxACC_NOT_IMPLEMENTED; +#endif +#if wxUSE_TOOLBAR + if (GetWindow()->IsKindOf(CLASSINFO(wxToolBar))) + return wxACC_NOT_IMPLEMENTED; +#endif + + //*role = wxROLE_SYSTEM_CLIENT; + *role = wxROLE_SYSTEM_CLIENT; + return wxACC_OK; + + #if 0 + return wxACC_NOT_IMPLEMENTED; + #endif +} + +// Returns a state constant. +wxAccStatus wxWindowAccessible::GetState(int childId, long* state) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + // If a child, leave wxWidgets to call the function on the actual + // child object. + if (childId > 0) + return wxACC_NOT_IMPLEMENTED; + + if (GetWindow()->IsKindOf(CLASSINFO(wxControl))) + return wxACC_NOT_IMPLEMENTED; + +#if wxUSE_STATUSBAR + if (GetWindow()->IsKindOf(CLASSINFO(wxStatusBar))) + return wxACC_NOT_IMPLEMENTED; +#endif +#if wxUSE_TOOLBAR + if (GetWindow()->IsKindOf(CLASSINFO(wxToolBar))) + return wxACC_NOT_IMPLEMENTED; +#endif + + *state = 0; + return wxACC_OK; + + #if 0 + return wxACC_NOT_IMPLEMENTED; + #endif +} + +// Returns a localized string representing the value for the object +// or child. +wxAccStatus wxWindowAccessible::GetValue(int WXUNUSED(childId), wxString* WXUNUSED(strValue)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} + +// Selects the object or child. +wxAccStatus wxWindowAccessible::Select(int WXUNUSED(childId), wxAccSelectionFlags WXUNUSED(selectFlags)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} + +// Gets the window with the keyboard focus. +// If childId is 0 and child is NULL, no object in +// this subhierarchy has the focus. +// If this object has the focus, child should be 'this'. +wxAccStatus wxWindowAccessible::GetFocus(int* WXUNUSED(childId), wxAccessible** WXUNUSED(child)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} + +#if wxUSE_VARIANT +// Gets a variant representing the selected children +// of this object. +// Acceptable values: +// - a null variant (IsNull() returns true) +// - a list variant (GetType() == wxT("list") +// - an integer representing the selected child element, +// or 0 if this object is selected (GetType() == wxT("long") +// - a "void*" pointer to a wxAccessible child object +wxAccStatus wxWindowAccessible::GetSelections(wxVariant* WXUNUSED(selections)) +{ + wxASSERT( GetWindow() != NULL ); + if (!GetWindow()) + return wxACC_FAIL; + + return wxACC_NOT_IMPLEMENTED; +} +#endif // wxUSE_VARIANT + +#endif // wxUSE_ACCESSIBILITY + +// ---------------------------------------------------------------------------- +// RTL support +// ---------------------------------------------------------------------------- + +wxCoord +wxWindowBase::AdjustForLayoutDirection(wxCoord x, + wxCoord width, + wxCoord widthTotal) const +{ + if ( GetLayoutDirection() == wxLayout_RightToLeft ) + { + x = widthTotal - x - width; + } + + return x; +} + diff --git a/Source/3rd Party/wx/src/common/wxchar.cpp b/Source/3rd Party/wx/src/common/wxchar.cpp new file mode 100644 index 000000000..068a1a09e --- /dev/null +++ b/Source/3rd Party/wx/src/common/wxchar.cpp @@ -0,0 +1,2293 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/wxchar.cpp +// Purpose: wxChar implementation +// Author: Ove Kaven +// Modified by: Ron Lee, Francesco Montorsi +// Created: 09/04/99 +// RCS-ID: $Id: wxchar.cpp 58994 2009-02-18 15:49:09Z FM $ +// Copyright: (c) wxWidgets copyright +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// =========================================================================== +// headers, declarations, constants +// =========================================================================== + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#include "wx/wxchar.h" + +#define _ISOC9X_SOURCE 1 // to get vsscanf() +#define _BSD_SOURCE 1 // to still get strdup() + +#include +#include +#include + +#ifndef __WXWINCE__ + #include + #include +#else + #include "wx/msw/wince/time.h" +#endif + +#ifndef WX_PRECOMP + #include "wx/string.h" + #include "wx/hash.h" + #include "wx/utils.h" // for wxMin and wxMax + #include "wx/log.h" +#endif + +#if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H) + #include + #include + #include + #include +#endif + +#if defined(__MWERKS__) && __MSL__ >= 0x6000 +namespace std {} +using namespace std ; +#endif + +#if wxUSE_WCHAR_T +size_t WXDLLEXPORT wxMB2WC(wchar_t *buf, const char *psz, size_t n) +{ + // assume that we have mbsrtowcs() too if we have wcsrtombs() +#ifdef HAVE_WCSRTOMBS + mbstate_t mbstate; + memset(&mbstate, 0, sizeof(mbstate_t)); +#endif + + if (buf) { + if (!n || !*psz) { + if (n) *buf = wxT('\0'); + return 0; + } +#ifdef HAVE_WCSRTOMBS + return mbsrtowcs(buf, &psz, n, &mbstate); +#else + return wxMbstowcs(buf, psz, n); +#endif + } + + // note that we rely on common (and required by Unix98 but unfortunately not + // C99) extension which allows to call mbs(r)towcs() with NULL output pointer + // to just get the size of the needed buffer -- this is needed as otherwise + // we have no idea about how much space we need and if the CRT doesn't + // support it (the only currently known example being Metrowerks, see + // wx/wxchar.h) we don't use its mbstowcs() at all +#ifdef HAVE_WCSRTOMBS + return mbsrtowcs((wchar_t *) NULL, &psz, 0, &mbstate); +#else + return wxMbstowcs((wchar_t *) NULL, psz, 0); +#endif +} + +size_t WXDLLEXPORT wxWC2MB(char *buf, const wchar_t *pwz, size_t n) +{ +#ifdef HAVE_WCSRTOMBS + mbstate_t mbstate; + memset(&mbstate, 0, sizeof(mbstate_t)); +#endif + + if (buf) { + if (!n || !*pwz) { + // glibc2.1 chokes on null input + if (n) *buf = '\0'; + return 0; + } +#ifdef HAVE_WCSRTOMBS + return wcsrtombs(buf, &pwz, n, &mbstate); +#else + return wxWcstombs(buf, pwz, n); +#endif + } + +#ifdef HAVE_WCSRTOMBS + return wcsrtombs((char *) NULL, &pwz, 0, &mbstate); +#else + return wxWcstombs((char *) NULL, pwz, 0); +#endif +} +#endif // wxUSE_WCHAR_T + +bool WXDLLEXPORT wxOKlibc() +{ +#if wxUSE_WCHAR_T && defined(__UNIX__) && defined(__GLIBC__) && !defined(__WINE__) + // glibc 2.0 uses UTF-8 even when it shouldn't + wchar_t res = 0; + if ((MB_CUR_MAX == 2) && + (wxMB2WC(&res, "\xdd\xa5", 1) == 1) && + (res==0x765)) { + // this is UTF-8 allright, check whether that's what we want + char *cur_locale = setlocale(LC_CTYPE, NULL); + if ((strlen(cur_locale) < 4) || + (strcasecmp(cur_locale + strlen(cur_locale) - 4, "utf8")) || + (strcasecmp(cur_locale + strlen(cur_locale) - 5, "utf-8"))) { + // nope, don't use libc conversion + return false; + } + } +#endif + return true; +} + +// ============================================================================ +// printf() functions business +// ============================================================================ + +// special test mode: define all functions below even if we don't really need +// them to be able to test them +#ifdef wxTEST_PRINTF + #undef wxFprintf + #undef wxPrintf + #undef wxSprintf + #undef wxVfprintf + #undef wxVsprintf + #undef wxVprintf + #undef wxVsnprintf_ + #undef wxSnprintf_ + + #define wxNEED_WPRINTF + + int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr ); +#endif + +// ---------------------------------------------------------------------------- +// implement [v]snprintf() if the system doesn't provide a safe one +// or if the system's one does not support positional parameters +// (very useful for i18n purposes) +// ---------------------------------------------------------------------------- + +#if !defined(wxVsnprintf_) + +#if !wxUSE_WXVSNPRINTF + #error wxUSE_WXVSNPRINTF must be 1 if our wxVsnprintf_ is used +#endif + +// wxUSE_STRUTILS says our wxVsnprintf_ implementation to use or not to +// use wxStrlen and wxStrncpy functions over one-char processing loops. +// +// Some benchmarking revealed that wxUSE_STRUTILS == 1 has the following +// effects: +// -> on Windows: +// when in ANSI mode, this setting does not change almost anything +// when in Unicode mode, it gives ~ 50% of slowdown ! +// -> on Linux: +// both in ANSI and Unicode mode it gives ~ 60% of speedup ! +// +#if defined(WIN32) && wxUSE_UNICODE +#define wxUSE_STRUTILS 0 +#else +#define wxUSE_STRUTILS 1 +#endif + +// some limits of our implementation +#define wxMAX_SVNPRINTF_ARGUMENTS 64 +#define wxMAX_SVNPRINTF_FLAGBUFFER_LEN 32 +#define wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN 512 + +// prefer snprintf over sprintf +#if defined(__VISUALC__) || \ + (defined(__BORLANDC__) && __BORLANDC__ >= 0x540) + #define system_sprintf(buff, max, flags, data) \ + ::_snprintf(buff, max, flags, data) +#elif defined(HAVE_SNPRINTF) + #define system_sprintf(buff, max, flags, data) \ + ::snprintf(buff, max, flags, data) +#else // NB: at least sprintf() should always be available + // since 'max' is not used in this case, wxVsnprintf() should always + // ensure that 'buff' is big enough for all common needs + // (see wxMAX_SVNPRINTF_FLAGBUFFER_LEN and wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN) + #define system_sprintf(buff, max, flags, data) \ + ::sprintf(buff, flags, data) + + #define SYSTEM_SPRINTF_IS_UNSAFE +#endif + +// the conversion specifiers accepted by wxVsnprintf_ +enum wxPrintfArgType { + wxPAT_INVALID = -1, + + wxPAT_INT, // %d, %i, %o, %u, %x, %X + wxPAT_LONGINT, // %ld, etc +#ifdef wxLongLong_t + wxPAT_LONGLONGINT, // %Ld, etc +#endif + wxPAT_SIZET, // %Zd, etc + + wxPAT_DOUBLE, // %e, %E, %f, %g, %G + wxPAT_LONGDOUBLE, // %le, etc + + wxPAT_POINTER, // %p + + wxPAT_CHAR, // %hc (in ANSI mode: %c, too) + wxPAT_WCHAR, // %lc (in Unicode mode: %c, too) + + wxPAT_PCHAR, // %s (related to a char *) + wxPAT_PWCHAR, // %s (related to a wchar_t *) + + wxPAT_NINT, // %n + wxPAT_NSHORTINT, // %hn + wxPAT_NLONGINT // %ln +}; + +// an argument passed to wxVsnprintf_ +typedef union { + int pad_int; // %d, %i, %o, %u, %x, %X + long int pad_longint; // %ld, etc +#ifdef wxLongLong_t + wxLongLong_t pad_longlongint; // %Ld, etc +#endif + size_t pad_sizet; // %Zd, etc + + double pad_double; // %e, %E, %f, %g, %G + long double pad_longdouble; // %le, etc + + void *pad_pointer; // %p + + char pad_char; // %hc (in ANSI mode: %c, too) + wchar_t pad_wchar; // %lc (in Unicode mode: %c, too) + + char *pad_pchar; // %s (related to a char *) + wchar_t *pad_pwchar; // %s (related to a wchar_t *) + + int *pad_nint; // %n + short int *pad_nshortint; // %hn + long int *pad_nlongint; // %ln +} wxPrintfArg; + + +// Contains parsed data relative to a conversion specifier given to +// wxVsnprintf_ and parsed from the format string +// NOTE: in C++ there is almost no difference between struct & classes thus +// there is no performance gain by using a struct here... +class wxPrintfConvSpec +{ +public: + + // the position of the argument relative to this conversion specifier + size_t m_pos; + + // the type of this conversion specifier + wxPrintfArgType m_type; + + // the minimum and maximum width + // when one of this var is set to -1 it means: use the following argument + // in the stack as minimum/maximum width for this conversion specifier + int m_nMinWidth, m_nMaxWidth; + + // does the argument need to the be aligned to left ? + bool m_bAlignLeft; + + // pointer to the '%' of this conversion specifier in the format string + // NOTE: this points somewhere in the string given to the Parse() function - + // it's task of the caller ensure that memory is still valid ! + const wxChar *m_pArgPos; + + // pointer to the last character of this conversion specifier in the + // format string + // NOTE: this points somewhere in the string given to the Parse() function - + // it's task of the caller ensure that memory is still valid ! + const wxChar *m_pArgEnd; + + // a little buffer where formatting flags like #+\.hlqLZ are stored by Parse() + // for use in Process() + // NB: even if this buffer is used only for numeric conversion specifiers and + // thus could be safely declared as a char[] buffer, we want it to be wxChar + // so that in Unicode builds we can avoid to convert its contents to Unicode + // chars when copying it in user's buffer. + char m_szFlags[wxMAX_SVNPRINTF_FLAGBUFFER_LEN]; + + +public: + + // we don't declare this as a constructor otherwise it would be called + // automatically and we don't want this: to be optimized, wxVsnprintf_ + // calls this function only on really-used instances of this class. + void Init(); + + // Parses the first conversion specifier in the given string, which must + // begin with a '%'. Returns false if the first '%' does not introduce a + // (valid) conversion specifier and thus should be ignored. + bool Parse(const wxChar *format); + + // Process this conversion specifier and puts the result in the given + // buffer. Returns the number of characters written in 'buf' or -1 if + // there's not enough space. + int Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t written); + + // Loads the argument of this conversion specifier from given va_list. + bool LoadArg(wxPrintfArg *p, va_list &argptr); + +private: + // An helper function of LoadArg() which is used to handle the '*' flag + void ReplaceAsteriskWith(int w); +}; + +void wxPrintfConvSpec::Init() +{ + m_nMinWidth = 0; + m_nMaxWidth = 0xFFFF; + m_pos = 0; + m_bAlignLeft = false; + m_pArgPos = m_pArgEnd = NULL; + m_type = wxPAT_INVALID; + + // this character will never be removed from m_szFlags array and + // is important when calling sprintf() in wxPrintfConvSpec::Process() ! + m_szFlags[0] = '%'; +} + +bool wxPrintfConvSpec::Parse(const wxChar *format) +{ + bool done = false; + + // temporary parse data + size_t flagofs = 1; + bool in_prec, // true if we found the dot in some previous iteration + prec_dot; // true if the dot has been already added to m_szFlags + int ilen = 0; + + m_bAlignLeft = in_prec = prec_dot = false; + m_pArgPos = m_pArgEnd = format; + do + { +#define CHECK_PREC \ + if (in_prec && !prec_dot) \ + { \ + m_szFlags[flagofs++] = '.'; \ + prec_dot = true; \ + } + + // what follows '%'? + const wxChar ch = *(++m_pArgEnd); + switch ( ch ) + { + case wxT('\0'): + return false; // not really an argument + + case wxT('%'): + return false; // not really an argument + + case wxT('#'): + case wxT('0'): + case wxT(' '): + case wxT('+'): + case wxT('\''): + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + break; + + case wxT('-'): + CHECK_PREC + m_bAlignLeft = true; + m_szFlags[flagofs++] = char(ch); + break; + + case wxT('.'): + CHECK_PREC + in_prec = true; + prec_dot = false; + m_nMaxWidth = 0; + // dot will be auto-added to m_szFlags if non-negative + // number follows + break; + + case wxT('h'): + ilen = -1; + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + break; + + case wxT('l'): + // NB: it's safe to use flagofs-1 as flagofs always start from 1 + if (m_szFlags[flagofs-1] == 'l') // 'll' modifier is the same as 'L' or 'q' + ilen = 2; + else + ilen = 1; + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + break; + + case wxT('q'): + case wxT('L'): + ilen = 2; + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + break; +#ifdef __WXMSW__ + // under Windows we support the special '%I64' notation as longlong + // integer conversion specifier for MSVC compatibility + // (it behaves exactly as '%lli' or '%Li' or '%qi') + case wxT('I'): + if (*(m_pArgEnd+1) != wxT('6') || + *(m_pArgEnd+2) != wxT('4')) + return false; // bad format + + m_pArgEnd++; + m_pArgEnd++; + + ilen = 2; + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + m_szFlags[flagofs++] = '6'; + m_szFlags[flagofs++] = '4'; + break; +#endif // __WXMSW__ + + case wxT('Z'): + ilen = 3; + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + break; + + case wxT('*'): + if (in_prec) + { + CHECK_PREC + + // tell Process() to use the next argument + // in the stack as maxwidth... + m_nMaxWidth = -1; + } + else + { + // tell Process() to use the next argument + // in the stack as minwidth... + m_nMinWidth = -1; + } + + // save the * in our formatting buffer... + // will be replaced later by Process() + m_szFlags[flagofs++] = char(ch); + break; + + case wxT('1'): case wxT('2'): case wxT('3'): + case wxT('4'): case wxT('5'): case wxT('6'): + case wxT('7'): case wxT('8'): case wxT('9'): + { + int len = 0; + CHECK_PREC + while ( (*m_pArgEnd >= wxT('0')) && + (*m_pArgEnd <= wxT('9')) ) + { + m_szFlags[flagofs++] = char(*m_pArgEnd); + len = len*10 + (*m_pArgEnd - wxT('0')); + m_pArgEnd++; + } + + if (in_prec) + m_nMaxWidth = len; + else + m_nMinWidth = len; + + m_pArgEnd--; // the main loop pre-increments n again + } + break; + + case wxT('$'): // a positional parameter (e.g. %2$s) ? + { + if (m_nMinWidth <= 0) + break; // ignore this formatting flag as no + // numbers are preceding it + + // remove from m_szFlags all digits previously added + do { + flagofs--; + } while (m_szFlags[flagofs] >= '1' && + m_szFlags[flagofs] <= '9'); + + // re-adjust the offset making it point to the + // next free char of m_szFlags + flagofs++; + + m_pos = m_nMinWidth; + m_nMinWidth = 0; + } + break; + + case wxT('d'): + case wxT('i'): + case wxT('o'): + case wxT('u'): + case wxT('x'): + case wxT('X'): + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + m_szFlags[flagofs] = '\0'; + if (ilen == 0) + m_type = wxPAT_INT; + else if (ilen == -1) + // NB: 'short int' value passed through '...' + // is promoted to 'int', so we have to get + // an int from stack even if we need a short + m_type = wxPAT_INT; + else if (ilen == 1) + m_type = wxPAT_LONGINT; + else if (ilen == 2) +#ifdef wxLongLong_t + m_type = wxPAT_LONGLONGINT; +#else // !wxLongLong_t + m_type = wxPAT_LONGINT; +#endif // wxLongLong_t/!wxLongLong_t + else if (ilen == 3) + m_type = wxPAT_SIZET; + done = true; + break; + + case wxT('e'): + case wxT('E'): + case wxT('f'): + case wxT('g'): + case wxT('G'): + CHECK_PREC + m_szFlags[flagofs++] = char(ch); + m_szFlags[flagofs] = '\0'; + if (ilen == 2) + m_type = wxPAT_LONGDOUBLE; + else + m_type = wxPAT_DOUBLE; + done = true; + break; + + case wxT('p'): + m_type = wxPAT_POINTER; + m_szFlags[flagofs++] = char(ch); + m_szFlags[flagofs] = '\0'; + done = true; + break; + + case wxT('c'): + m_szFlags[flagofs++] = char(ch); + m_szFlags[flagofs] = '\0'; + if (ilen == -1) + { + // in Unicode mode %hc == ANSI character + // and in ANSI mode, %hc == %c == ANSI... + m_type = wxPAT_CHAR; + } + else if (ilen == 1) + { + // in ANSI mode %lc == Unicode character + // and in Unicode mode, %lc == %c == Unicode... + m_type = wxPAT_WCHAR; + } + else + { +#if wxUSE_UNICODE + // in Unicode mode, %c == Unicode character + m_type = wxPAT_WCHAR; +#else + // in ANSI mode, %c == ANSI character + m_type = wxPAT_CHAR; +#endif + } + done = true; + break; + + case wxT('s'): + m_szFlags[flagofs++] = char(ch); + m_szFlags[flagofs] = '\0'; + if (ilen == -1) + { + // Unicode mode wx extension: we'll let %hs mean non-Unicode + // strings (when in ANSI mode, %s == %hs == ANSI string) + m_type = wxPAT_PCHAR; + } + else if (ilen == 1) + { + // in Unicode mode, %ls == %s == Unicode string + // in ANSI mode, %ls == Unicode string + m_type = wxPAT_PWCHAR; + } + else + { +#if wxUSE_UNICODE + m_type = wxPAT_PWCHAR; +#else + m_type = wxPAT_PCHAR; +#endif + } + done = true; + break; + + case wxT('n'): + m_szFlags[flagofs++] = char(ch); + m_szFlags[flagofs] = '\0'; + if (ilen == 0) + m_type = wxPAT_NINT; + else if (ilen == -1) + m_type = wxPAT_NSHORTINT; + else if (ilen >= 1) + m_type = wxPAT_NLONGINT; + done = true; + break; + + default: + // bad format, don't consider this an argument; + // leave it unchanged + return false; + } + + if (flagofs == wxMAX_SVNPRINTF_FLAGBUFFER_LEN) + { + wxLogDebug(wxT("Too many flags specified for a single conversion specifier!")); + return false; + } + } + while (!done); + + return true; // parsing was successful +} + + +void wxPrintfConvSpec::ReplaceAsteriskWith(int width) +{ + char temp[wxMAX_SVNPRINTF_FLAGBUFFER_LEN]; + + // find the first * in our flag buffer + char *pwidth = strchr(m_szFlags, '*'); + wxCHECK_RET(pwidth, _T("field width must be specified")); + + // save what follows the * (the +1 is to skip the asterisk itself!) + strcpy(temp, pwidth+1); + if (width < 0) + { + pwidth[0] = wxT('-'); + pwidth++; + } + + // replace * with the actual integer given as width +#ifndef SYSTEM_SPRINTF_IS_UNSAFE + int maxlen = (m_szFlags + wxMAX_SVNPRINTF_FLAGBUFFER_LEN - pwidth) / + sizeof(*m_szFlags); +#endif + int offset = system_sprintf(pwidth, maxlen, "%d", abs(width)); + + // restore after the expanded * what was following it + strcpy(pwidth+offset, temp); +} + +bool wxPrintfConvSpec::LoadArg(wxPrintfArg *p, va_list &argptr) +{ + // was the '*' width/precision specifier used ? + if (m_nMaxWidth == -1) + { + // take the maxwidth specifier from the stack + m_nMaxWidth = va_arg(argptr, int); + if (m_nMaxWidth < 0) + m_nMaxWidth = 0; + else + ReplaceAsteriskWith(m_nMaxWidth); + } + + if (m_nMinWidth == -1) + { + // take the minwidth specifier from the stack + m_nMinWidth = va_arg(argptr, int); + + ReplaceAsteriskWith(m_nMinWidth); + if (m_nMinWidth < 0) + { + m_bAlignLeft = !m_bAlignLeft; + m_nMinWidth = -m_nMinWidth; + } + } + + switch (m_type) { + case wxPAT_INT: + p->pad_int = va_arg(argptr, int); + break; + case wxPAT_LONGINT: + p->pad_longint = va_arg(argptr, long int); + break; +#ifdef wxLongLong_t + case wxPAT_LONGLONGINT: + p->pad_longlongint = va_arg(argptr, wxLongLong_t); + break; +#endif // wxLongLong_t + case wxPAT_SIZET: + p->pad_sizet = va_arg(argptr, size_t); + break; + case wxPAT_DOUBLE: + p->pad_double = va_arg(argptr, double); + break; + case wxPAT_LONGDOUBLE: + p->pad_longdouble = va_arg(argptr, long double); + break; + case wxPAT_POINTER: + p->pad_pointer = va_arg(argptr, void *); + break; + + case wxPAT_CHAR: + p->pad_char = (char)va_arg(argptr, int); // char is promoted to int when passed through '...' + break; + case wxPAT_WCHAR: + p->pad_wchar = (wchar_t)va_arg(argptr, int); // char is promoted to int when passed through '...' + break; + + case wxPAT_PCHAR: + p->pad_pchar = va_arg(argptr, char *); + break; + case wxPAT_PWCHAR: + p->pad_pwchar = va_arg(argptr, wchar_t *); + break; + + case wxPAT_NINT: + p->pad_nint = va_arg(argptr, int *); + break; + case wxPAT_NSHORTINT: + p->pad_nshortint = va_arg(argptr, short int *); + break; + case wxPAT_NLONGINT: + p->pad_nlongint = va_arg(argptr, long int *); + break; + + case wxPAT_INVALID: + default: + return false; + } + + return true; // loading was successful +} + +int wxPrintfConvSpec::Process(wxChar *buf, size_t lenMax, wxPrintfArg *p, size_t written) +{ + // buffer to avoid dynamic memory allocation each time for small strings; + // note that this buffer is used only to hold results of number formatting, + // %s directly writes user's string in buf, without using szScratch + char szScratch[wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN]; + size_t lenScratch = 0, lenCur = 0; + +#define APPEND_CH(ch) \ + { \ + if ( lenCur == lenMax ) \ + return -1; \ + \ + buf[lenCur++] = ch; \ + } + +#define APPEND_STR(s) \ + { \ + for ( const wxChar *p = s; *p; p++ ) \ + { \ + APPEND_CH(*p); \ + } \ + } + + switch ( m_type ) + { + case wxPAT_INT: + lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_int); + break; + + case wxPAT_LONGINT: + lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longint); + break; + +#ifdef wxLongLong_t + case wxPAT_LONGLONGINT: + lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longlongint); + break; +#endif // SIZEOF_LONG_LONG + + case wxPAT_SIZET: + lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_sizet); + break; + + case wxPAT_LONGDOUBLE: + lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_longdouble); + break; + + case wxPAT_DOUBLE: + lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_double); + break; + + case wxPAT_POINTER: + lenScratch = system_sprintf(szScratch, wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN, m_szFlags, p->pad_pointer); + break; + + case wxPAT_CHAR: + case wxPAT_WCHAR: + { + wxChar val = +#if wxUSE_UNICODE + p->pad_wchar; + + if (m_type == wxPAT_CHAR) + { + // user passed a character explicitely indicated as ANSI... + const char buf[2] = { p->pad_char, 0 }; + val = wxString(buf, wxConvLibc)[0u]; + + //wprintf(L"converting ANSI=>Unicode"); // for debug + } +#else + p->pad_char; + +#if wxUSE_WCHAR_T + if (m_type == wxPAT_WCHAR) + { + // user passed a character explicitely indicated as Unicode... + const wchar_t buf[2] = { p->pad_wchar, 0 }; + val = wxString(buf, wxConvLibc)[0u]; + + //printf("converting Unicode=>ANSI"); // for debug + } +#endif +#endif + + size_t i; + + if (!m_bAlignLeft) + for (i = 1; i < (size_t)m_nMinWidth; i++) + APPEND_CH(_T(' ')); + + APPEND_CH(val); + + if (m_bAlignLeft) + for (i = 1; i < (size_t)m_nMinWidth; i++) + APPEND_CH(_T(' ')); + } + break; + + case wxPAT_PCHAR: + case wxPAT_PWCHAR: + { + wxString s; + const wxChar *val = +#if wxUSE_UNICODE + p->pad_pwchar; + + if (m_type == wxPAT_PCHAR) + { + // user passed a string explicitely indicated as ANSI... + val = s = wxString(p->pad_pchar, wxConvLibc); + + //wprintf(L"converting ANSI=>Unicode"); // for debug + } +#else + p->pad_pchar; + +#if wxUSE_WCHAR_T + if (m_type == wxPAT_PWCHAR) + { + // user passed a string explicitely indicated as Unicode... + val = s = wxString(p->pad_pwchar, wxConvLibc); + + //printf("converting Unicode=>ANSI"); // for debug + } +#endif +#endif + int len; + + if (val) + { +#if wxUSE_STRUTILS + // at this point we are sure that m_nMaxWidth is positive or null + // (see top of wxPrintfConvSpec::LoadArg) + len = wxMin((unsigned int)m_nMaxWidth, wxStrlen(val)); +#else + for ( len = 0; val[len] && (len < m_nMaxWidth); len++ ) + ; +#endif + } + else if (m_nMaxWidth >= 6) + { + val = wxT("(null)"); + len = 6; + } + else + { + val = wxEmptyString; + len = 0; + } + + int i; + + if (!m_bAlignLeft) + { + for (i = len; i < m_nMinWidth; i++) + APPEND_CH(_T(' ')); + } + +#if wxUSE_STRUTILS + len = wxMin((unsigned int)len, lenMax-lenCur); + wxStrncpy(buf+lenCur, val, len); + lenCur += len; +#else + for (i = 0; i < len; i++) + APPEND_CH(val[i]); +#endif + + if (m_bAlignLeft) + { + for (i = len; i < m_nMinWidth; i++) + APPEND_CH(_T(' ')); + } + } + break; + + case wxPAT_NINT: + *p->pad_nint = written; + break; + + case wxPAT_NSHORTINT: + *p->pad_nshortint = (short int)written; + break; + + case wxPAT_NLONGINT: + *p->pad_nlongint = written; + break; + + case wxPAT_INVALID: + default: + return -1; + } + + // if we used system's sprintf() then we now need to append the s_szScratch + // buffer to the given one... + switch (m_type) + { + case wxPAT_INT: + case wxPAT_LONGINT: +#ifdef wxLongLong_t + case wxPAT_LONGLONGINT: +#endif + case wxPAT_SIZET: + case wxPAT_LONGDOUBLE: + case wxPAT_DOUBLE: + case wxPAT_POINTER: + wxASSERT(lenScratch < wxMAX_SVNPRINTF_SCRATCHBUFFER_LEN); +#if !wxUSE_UNICODE + { + if (lenMax < lenScratch) + { + // fill output buffer and then return -1 + wxStrncpy(buf, szScratch, lenMax); + return -1; + } + wxStrncpy(buf, szScratch, lenScratch); + lenCur += lenScratch; + } +#else + { + // Copy the char scratch to the wide output. This requires + // conversion, but we can optimise by making use of the fact + // that we are formatting numbers, this should mean only 7-bit + // ascii characters are involved. + wxChar *bufptr = buf; + const wxChar *bufend = buf + lenMax; + const char *scratchptr = szScratch; + + // Simply copy each char to a wxChar, stopping on the first + // null or non-ascii byte. Checking '(signed char)*scratchptr + // > 0' is an extra optimisation over '*scratchptr != 0 && + // isascii(*scratchptr)', though it assumes signed char is + // 8-bit 2 complement. + while ((signed char)*scratchptr > 0 && bufptr != bufend) + *bufptr++ = *scratchptr++; + + if (bufptr == bufend) + return -1; + + lenCur += bufptr - buf; + + // check if the loop stopped on a non-ascii char, if yes then + // fall back to wxMB2WX + if (*scratchptr) + { + size_t len = wxMB2WX(bufptr, scratchptr, bufend - bufptr); + + if (len && len != (size_t)(-1)) + if (bufptr[len - 1]) + return -1; + else + lenCur += len; + } + } +#endif + break; + + default: + break; // all other cases were completed previously + } + + return lenCur; +} + +// Copy chars from source to dest converting '%%' to '%'. Takes at most maxIn +// chars from source and write at most outMax chars to dest, returns the +// number of chars actually written. Does not treat null specially. +// +static int wxCopyStrWithPercents( + size_t maxOut, + wxChar *dest, + size_t maxIn, + const wxChar *source) +{ + size_t written = 0; + + if (maxIn == 0) + return 0; + + size_t i; + for ( i = 0; i < maxIn-1 && written < maxOut; source++, i++) + { + dest[written++] = *source; + if (*(source+1) == wxT('%')) + { + // skip this additional '%' character + source++; + i++; + } + } + + if (i < maxIn && written < maxOut) + // copy last character inconditionally + dest[written++] = *source; + + return written; +} + +int WXDLLEXPORT wxVsnprintf_(wxChar *buf, size_t lenMax, + const wxChar *format, va_list argptr) +{ + // useful for debugging, to understand if we are really using this function + // rather than the system implementation +#if 0 + wprintf(L"Using wxVsnprintf_\n"); +#endif + + // required memory: + wxPrintfConvSpec arg[wxMAX_SVNPRINTF_ARGUMENTS]; + wxPrintfArg argdata[wxMAX_SVNPRINTF_ARGUMENTS]; + wxPrintfConvSpec *pspec[wxMAX_SVNPRINTF_ARGUMENTS] = { NULL }; + + size_t i; + + // number of characters in the buffer so far, must be less than lenMax + size_t lenCur = 0; + + size_t nargs = 0; + const wxChar *toparse = format; + + // parse the format string + bool posarg_present = false, nonposarg_present = false; + for (; *toparse != wxT('\0'); toparse++) + { + if (*toparse == wxT('%') ) + { + arg[nargs].Init(); + + // let's see if this is a (valid) conversion specifier... + if (arg[nargs].Parse(toparse)) + { + // ...yes it is + wxPrintfConvSpec *current = &arg[nargs]; + + // make toparse point to the end of this specifier + toparse = current->m_pArgEnd; + + if (current->m_pos > 0) + { + // the positionals start from number 1... adjust the index + current->m_pos--; + posarg_present = true; + } + else + { + // not a positional argument... + current->m_pos = nargs; + nonposarg_present = true; + } + + // this conversion specifier is tied to the pos-th argument... + pspec[current->m_pos] = current; + nargs++; + + if (nargs == wxMAX_SVNPRINTF_ARGUMENTS) + { + wxLogDebug(wxT("A single call to wxVsnprintf() has more than %d arguments; ") + wxT("ignoring all remaining arguments."), wxMAX_SVNPRINTF_ARGUMENTS); + break; // cannot handle any additional conv spec + } + } + else + { + // it's safe to look in the next character of toparse as at worst + // we'll hit its \0 + if (*(toparse+1) == wxT('%')) + toparse++; // the Parse() returned false because we've found a %% + } + } + } + + if (posarg_present && nonposarg_present) + { + buf[0] = 0; + return -1; // format strings with both positional and + } // non-positional conversion specifier are unsupported !! + + // on platforms where va_list is an array type, it is necessary to make a + // copy to be able to pass it to LoadArg as a reference. + bool ok = true; + va_list ap; + wxVaCopy(ap, argptr); + + // now load arguments from stack + for (i=0; i < nargs && ok; i++) + { + // !pspec[i] means that the user forgot a positional parameter (e.g. %$1s %$3s); + // LoadArg == false means that wxPrintfConvSpec::Parse failed to set the + // conversion specifier 'type' to a valid value... + ok = pspec[i] && pspec[i]->LoadArg(&argdata[i], ap); + } + + va_end(ap); + + // something failed while loading arguments from the variable list... + // (e.g. the user repeated twice the same positional argument) + if (!ok) + { + buf[0] = 0; + return -1; + } + + // finally, process each conversion specifier with its own argument + toparse = format; + for (i=0; i < nargs; i++) + { + // copy in the output buffer the portion of the format string between + // last specifier and the current one + size_t tocopy = ( arg[i].m_pArgPos - toparse ); + + lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur, + tocopy, toparse); + if (lenCur == lenMax) + { + buf[lenMax - 1] = 0; + return lenMax+1; // not enough space in the output buffer ! + } + + // process this specifier directly in the output buffer + int n = arg[i].Process(buf+lenCur, lenMax - lenCur, &argdata[arg[i].m_pos], lenCur); + if (n == -1) + { + buf[lenMax-1] = wxT('\0'); // be sure to always NUL-terminate the string + return lenMax+1; // not enough space in the output buffer ! + } + lenCur += n; + + // the +1 is because wxPrintfConvSpec::m_pArgEnd points to the last character + // of the format specifier, but we are not interested to it... + toparse = arg[i].m_pArgEnd + 1; + } + + // copy portion of the format string after last specifier + // NOTE: toparse is pointing to the character just after the last processed + // conversion specifier + // NOTE2: the +1 is because we want to copy also the '\0' + size_t tocopy = wxStrlen(format) + 1 - ( toparse - format ) ; + + lenCur += wxCopyStrWithPercents(lenMax - lenCur, buf + lenCur, + tocopy, toparse) - 1; + if (buf[lenCur]) + { + buf[lenCur] = 0; + return lenMax+1; // not enough space in the output buffer ! + } + + // Don't do: + // wxASSERT(lenCur == wxStrlen(buf)); + // in fact if we embedded NULLs in the output buffer (using %c with a '\0') + // such check would fail + + return lenCur; +} + +#undef APPEND_CH +#undef APPEND_STR +#undef CHECK_PREC + +#else // wxVsnprintf_ is defined + +#if wxUSE_WXVSNPRINTF + #error wxUSE_WXVSNPRINTF must be 0 if our wxVsnprintf_ is not used +#endif + +#endif // !wxVsnprintf_ + +#if !defined(wxSnprintf_) +int WXDLLEXPORT wxSnprintf_(wxChar *buf, size_t len, const wxChar *format, ...) +{ + va_list argptr; + va_start(argptr, format); + + int iLen = wxVsnprintf_(buf, len, format, argptr); + + va_end(argptr); + + return iLen; +} +#endif // wxSnprintf_ + +#if defined(__DMC__) + /* Digital Mars adds count to _stprintf (C99) so convert */ + #if wxUSE_UNICODE + int wxSprintf (wchar_t * __RESTRICT s, const wchar_t * __RESTRICT format, ... ) + { + va_list arglist; + + va_start( arglist, format ); + int iLen = swprintf ( s, -1, format, arglist ); + va_end( arglist ); + return iLen ; + } + + #endif // wxUSE_UNICODE + +#endif //__DMC__ + +#if defined(__MINGW32__) && ( defined(_STLPORT_VERSION) && _STLPORT_VERSION >= 0x510 ) + /* MinGW with STLPort 5.1 has clashing defines for _stprintf so use swprintf */ + /* STLPort 5.1 defines standard (C99) vswprintf() and swprintf() that takes count. */ + int wxSprintf (wchar_t * s, const wchar_t * format, ... ) + { + va_list arglist; + + va_start( arglist, format ); + int iLen = swprintf ( s, -1, format, arglist ); + va_end( arglist ); + return iLen ; + } +#endif // MINGW32 _STLPORT_VERSION >= 0x510 + +// ---------------------------------------------------------------------------- +// implement the standard IO functions for wide char if libc doesn't have them +// ---------------------------------------------------------------------------- + +#ifdef wxNEED_FPUTS +int wxFputs(const wchar_t *ws, FILE *stream) +{ + wxCharBuffer buf(wxConvLibc.cWC2MB(ws)); + if ( !buf ) + return -1; + + // counting the number of wide characters written isn't worth the trouble, + // simply distinguish between ok and error + return fputs(buf, stream) == -1 ? -1 : 0; +} +#endif // wxNEED_FPUTS + +#ifdef wxNEED_PUTS +int wxPuts(const wxChar *ws) +{ + int rc = wxFputs(ws, stdout); + if ( rc != -1 ) + { + if ( wxFputs(L"\n", stdout) == -1 ) + return -1; + + rc++; + } + + return rc; +} +#endif // wxNEED_PUTS + +#ifdef wxNEED_PUTC +int /* not wint_t */ wxPutc(wchar_t wc, FILE *stream) +{ + wchar_t ws[2] = { wc, L'\0' }; + + return wxFputs(ws, stream); +} +#endif // wxNEED_PUTC + +// NB: we only implement va_list functions here, the ones taking ... are +// defined below for wxNEED_PRINTF_CONVERSION case anyhow and we reuse +// the definitions there to avoid duplicating them here +#ifdef wxNEED_WPRINTF + +// TODO: implement the scanf() functions +int vwscanf(const wxChar *format, va_list argptr) +{ + wxFAIL_MSG( _T("TODO") ); + + return -1; +} + +int vswscanf(const wxChar *ws, const wxChar *format, va_list argptr) +{ + // The best we can do without proper Unicode support in glibc is to + // convert the strings into MB representation and run ANSI version + // of the function. This doesn't work with %c and %s because of difference + // in size of char and wchar_t, though. + + wxCHECK_MSG( wxStrstr(format, _T("%s")) == NULL, -1, + _T("incomplete vswscanf implementation doesn't allow %s") ); + wxCHECK_MSG( wxStrstr(format, _T("%c")) == NULL, -1, + _T("incomplete vswscanf implementation doesn't allow %c") ); + + va_list argcopy; + wxVaCopy(argcopy, argptr); + return vsscanf(wxConvLibc.cWX2MB(ws), wxConvLibc.cWX2MB(format), argcopy); +} + +int vfwscanf(FILE *stream, const wxChar *format, va_list argptr) +{ + wxFAIL_MSG( _T("TODO") ); + + return -1; +} + +#define vswprintf wxVsnprintf_ + +int vfwprintf(FILE *stream, const wxChar *format, va_list argptr) +{ + wxString s; + int rc = s.PrintfV(format, argptr); + + if ( rc != -1 ) + { + // we can't do much better without Unicode support in libc... + if ( fprintf(stream, "%s", (const char*)s.mb_str() ) == -1 ) + return -1; + } + + return rc; +} + +int vwprintf(const wxChar *format, va_list argptr) +{ + return wxVfprintf(stdout, format, argptr); +} + +#endif // wxNEED_WPRINTF + +#ifdef wxNEED_PRINTF_CONVERSION + +// ---------------------------------------------------------------------------- +// wxFormatConverter: class doing the "%s" -> "%ls" conversion +// ---------------------------------------------------------------------------- + +/* + Here are the gory details. We want to follow the Windows/MS conventions, + that is to have + + In ANSI mode: + + format specifier results in + ----------------------------------- + %c, %hc, %hC char + %lc, %C, %lC wchar_t + + In Unicode mode: + + format specifier results in + ----------------------------------- + %hc, %C, %hC char + %c, %lc, %lC wchar_t + + + while on POSIX systems we have %C identical to %lc and %c always means char + (in any mode) while %lc always means wchar_t, + + So to use native functions in order to get our semantics we must do the + following translations in Unicode mode (nothing to do in ANSI mode): + + wxWidgets specifier POSIX specifier + ---------------------------------------- + + %hc, %C, %hC %c + %c %lc + + + And, of course, the same should be done for %s as well. +*/ + +class wxFormatConverter +{ +public: + wxFormatConverter(const wxChar *format); + + // notice that we only translated the string if m_fmtOrig == NULL (as set + // by CopyAllBefore()), otherwise we should simply use the original format + operator const wxChar *() const + { return m_fmtOrig ? m_fmtOrig : m_fmt.c_str(); } + +private: + // copy another character to the translated format: this function does the + // copy if we are translating but doesn't do anything at all if we don't, + // so we don't create the translated format string at all unless we really + // need to (i.e. InsertFmtChar() is called) + wxChar CopyFmtChar(wxChar ch) + { + if ( !m_fmtOrig ) + { + // we're translating, do copy + m_fmt += ch; + } + else + { + // simply increase the count which should be copied by + // CopyAllBefore() later if needed + m_nCopied++; + } + + return ch; + } + + // insert an extra character + void InsertFmtChar(wxChar ch) + { + if ( m_fmtOrig ) + { + // so far we haven't translated anything yet + CopyAllBefore(); + } + + m_fmt += ch; + } + + void CopyAllBefore() + { + wxASSERT_MSG( m_fmtOrig && m_fmt.empty(), _T("logic error") ); + + m_fmt = wxString(m_fmtOrig, m_nCopied); + + // we won't need it any longer + m_fmtOrig = NULL; + } + + static bool IsFlagChar(wxChar ch) + { + return ch == _T('-') || ch == _T('+') || + ch == _T('0') || ch == _T(' ') || ch == _T('#'); + } + + void SkipDigits(const wxChar **ptpc) + { + while ( **ptpc >= _T('0') && **ptpc <= _T('9') ) + CopyFmtChar(*(*ptpc)++); + } + + // the translated format + wxString m_fmt; + + // the original format + const wxChar *m_fmtOrig; + + // the number of characters already copied + size_t m_nCopied; +}; + +wxFormatConverter::wxFormatConverter(const wxChar *format) +{ + m_fmtOrig = format; + m_nCopied = 0; + + while ( *format ) + { + if ( CopyFmtChar(*format++) == _T('%') ) + { + // skip any flags + while ( IsFlagChar(*format) ) + CopyFmtChar(*format++); + + // and possible width + if ( *format == _T('*') ) + CopyFmtChar(*format++); + else + SkipDigits(&format); + + // precision? + if ( *format == _T('.') ) + { + CopyFmtChar(*format++); + if ( *format == _T('*') ) + CopyFmtChar(*format++); + else + SkipDigits(&format); + } + + // next we can have a size modifier + enum + { + Default, + Short, + Long + } size; + + switch ( *format ) + { + case _T('h'): + size = Short; + format++; + break; + + case _T('l'): + // "ll" has a different meaning! + if ( format[1] != _T('l') ) + { + size = Long; + format++; + break; + } + //else: fall through + + default: + size = Default; + } + + // and finally we should have the type + switch ( *format ) + { + case _T('C'): + case _T('S'): + // %C and %hC -> %c and %lC -> %lc + if ( size == Long ) + CopyFmtChar(_T('l')); + + InsertFmtChar(*format++ == _T('C') ? _T('c') : _T('s')); + break; + + case _T('c'): + case _T('s'): + // %c -> %lc but %hc stays %hc and %lc is still %lc + if ( size == Default) + InsertFmtChar(_T('l')); + // fall through + + default: + // nothing special to do + if ( size != Default ) + CopyFmtChar(*(format - 1)); + CopyFmtChar(*format++); + } + } + } +} + +#else // !wxNEED_PRINTF_CONVERSION + // no conversion necessary + #define wxFormatConverter(x) (x) +#endif // wxNEED_PRINTF_CONVERSION/!wxNEED_PRINTF_CONVERSION + +#ifdef __WXDEBUG__ +// For testing the format converter +wxString wxConvertFormat(const wxChar *format) +{ + return wxString(wxFormatConverter(format)); +} +#endif + +// ---------------------------------------------------------------------------- +// wxPrintf(), wxScanf() and relatives +// ---------------------------------------------------------------------------- + +#if defined(wxNEED_PRINTF_CONVERSION) || defined(wxNEED_WPRINTF) + +int wxScanf( const wxChar *format, ... ) +{ + va_list argptr; + va_start(argptr, format); + + int ret = vwscanf(wxFormatConverter(format), argptr ); + + va_end(argptr); + + return ret; +} + +int wxSscanf( const wxChar *str, const wxChar *format, ... ) +{ + va_list argptr; + va_start(argptr, format); + + int ret = vswscanf( str, wxFormatConverter(format), argptr ); + + va_end(argptr); + + return ret; +} + +int wxFscanf( FILE *stream, const wxChar *format, ... ) +{ + va_list argptr; + va_start(argptr, format); + int ret = vfwscanf(stream, wxFormatConverter(format), argptr); + + va_end(argptr); + + return ret; +} + +int wxPrintf( const wxChar *format, ... ) +{ + va_list argptr; + va_start(argptr, format); + + int ret = vwprintf( wxFormatConverter(format), argptr ); + + va_end(argptr); + + return ret; +} + +#ifndef wxSnprintf +int wxSnprintf( wxChar *str, size_t size, const wxChar *format, ... ) +{ + va_list argptr; + va_start(argptr, format); + + int ret = vswprintf( str, size, wxFormatConverter(format), argptr ); + + // VsnprintfTestCase reveals that glibc's implementation of vswprintf + // doesn't nul terminate on truncation. + str[size - 1] = 0; + + va_end(argptr); + + return ret; +} +#endif // wxSnprintf + +int wxSprintf( wxChar *str, const wxChar *format, ... ) +{ + va_list argptr; + va_start(argptr, format); + + // note that wxString::FormatV() uses wxVsnprintf(), not wxSprintf(), so + // it's safe to implement this one in terms of it + wxString s(wxString::FormatV(format, argptr)); + wxStrcpy(str, s); + + va_end(argptr); + + return s.length(); +} + +int wxFprintf( FILE *stream, const wxChar *format, ... ) +{ + va_list argptr; + va_start( argptr, format ); + + int ret = vfwprintf( stream, wxFormatConverter(format), argptr ); + + va_end(argptr); + + return ret; +} + +int wxVsscanf( const wxChar *str, const wxChar *format, va_list argptr ) +{ + return vswscanf( str, wxFormatConverter(format), argptr ); +} + +int wxVfprintf( FILE *stream, const wxChar *format, va_list argptr ) +{ + return vfwprintf( stream, wxFormatConverter(format), argptr ); +} + +int wxVprintf( const wxChar *format, va_list argptr ) +{ + return vwprintf( wxFormatConverter(format), argptr ); +} + +#ifndef wxVsnprintf +int wxVsnprintf( wxChar *str, size_t size, const wxChar *format, va_list argptr ) +{ + return vswprintf( str, size, wxFormatConverter(format), argptr ); +} +#endif // wxVsnprintf + +int wxVsprintf( wxChar *str, const wxChar *format, va_list argptr ) +{ + // same as for wxSprintf() + return vswprintf(str, INT_MAX / 4, wxFormatConverter(format), argptr); +} + +#endif // wxNEED_PRINTF_CONVERSION + +#if wxUSE_WCHAR_T + +// ---------------------------------------------------------------------------- +// ctype.h stuff (currently unused) +// ---------------------------------------------------------------------------- + +#if defined(__WIN32__) && defined(wxNEED_WX_CTYPE_H) +inline WORD wxMSW_ctype(wxChar ch) +{ + WORD ret; + GetStringTypeEx(LOCALE_USER_DEFAULT, CT_CTYPE1, &ch, 1, &ret); + return ret; +} + +WXDLLEXPORT int wxIsalnum(wxChar ch) { return IsCharAlphaNumeric(ch); } +WXDLLEXPORT int wxIsalpha(wxChar ch) { return IsCharAlpha(ch); } +WXDLLEXPORT int wxIscntrl(wxChar ch) { return wxMSW_ctype(ch) & C1_CNTRL; } +WXDLLEXPORT int wxIsdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_DIGIT; } +WXDLLEXPORT int wxIsgraph(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_PUNCT|C1_ALPHA); } +WXDLLEXPORT int wxIslower(wxChar ch) { return IsCharLower(ch); } +WXDLLEXPORT int wxIsprint(wxChar ch) { return wxMSW_ctype(ch) & (C1_DIGIT|C1_SPACE|C1_PUNCT|C1_ALPHA); } +WXDLLEXPORT int wxIspunct(wxChar ch) { return wxMSW_ctype(ch) & C1_PUNCT; } +WXDLLEXPORT int wxIsspace(wxChar ch) { return wxMSW_ctype(ch) & C1_SPACE; } +WXDLLEXPORT int wxIsupper(wxChar ch) { return IsCharUpper(ch); } +WXDLLEXPORT int wxIsxdigit(wxChar ch) { return wxMSW_ctype(ch) & C1_XDIGIT; } +WXDLLEXPORT int wxTolower(wxChar ch) { return (wxChar)CharLower((LPTSTR)(ch)); } +WXDLLEXPORT int wxToupper(wxChar ch) { return (wxChar)CharUpper((LPTSTR)(ch)); } +#endif + +#ifdef wxNEED_WX_MBSTOWCS + +WXDLLEXPORT size_t wxMbstowcs (wchar_t * out, const char * in, size_t outlen) +{ + if (!out) + { + size_t outsize = 0; + while(*in++) + outsize++; + return outsize; + } + + const char* origin = in; + + while (outlen-- && *in) + { + *out++ = (wchar_t) *in++; + } + + *out = '\0'; + + return in - origin; +} + +WXDLLEXPORT size_t wxWcstombs (char * out, const wchar_t * in, size_t outlen) +{ + if (!out) + { + size_t outsize = 0; + while(*in++) + outsize++; + return outsize; + } + + const wchar_t* origin = in; + + while (outlen-- && *in) + { + *out++ = (char) *in++; + } + + *out = '\0'; + + return in - origin; +} + +#endif // wxNEED_WX_MBSTOWCS + +#if defined(wxNEED_WX_CTYPE_H) + +#include + +#define cfalnumset CFCharacterSetGetPredefined(kCFCharacterSetAlphaNumeric) +#define cfalphaset CFCharacterSetGetPredefined(kCFCharacterSetLetter) +#define cfcntrlset CFCharacterSetGetPredefined(kCFCharacterSetControl) +#define cfdigitset CFCharacterSetGetPredefined(kCFCharacterSetDecimalDigit) +//CFCharacterSetRef cfgraphset = kCFCharacterSetControl && !' ' +#define cflowerset CFCharacterSetGetPredefined(kCFCharacterSetLowercaseLetter) +//CFCharacterSetRef cfprintset = !kCFCharacterSetControl +#define cfpunctset CFCharacterSetGetPredefined(kCFCharacterSetPunctuation) +#define cfspaceset CFCharacterSetGetPredefined(kCFCharacterSetWhitespaceAndNewline) +#define cfupperset CFCharacterSetGetPredefined(kCFCharacterSetUppercaseLetter) + +WXDLLEXPORT int wxIsalnum(wxChar ch) { return CFCharacterSetIsCharacterMember(cfalnumset, ch); } +WXDLLEXPORT int wxIsalpha(wxChar ch) { return CFCharacterSetIsCharacterMember(cfalphaset, ch); } +WXDLLEXPORT int wxIscntrl(wxChar ch) { return CFCharacterSetIsCharacterMember(cfcntrlset, ch); } +WXDLLEXPORT int wxIsdigit(wxChar ch) { return CFCharacterSetIsCharacterMember(cfdigitset, ch); } +WXDLLEXPORT int wxIsgraph(wxChar ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch) && ch != ' '; } +WXDLLEXPORT int wxIslower(wxChar ch) { return CFCharacterSetIsCharacterMember(cflowerset, ch); } +WXDLLEXPORT int wxIsprint(wxChar ch) { return !CFCharacterSetIsCharacterMember(cfcntrlset, ch); } +WXDLLEXPORT int wxIspunct(wxChar ch) { return CFCharacterSetIsCharacterMember(cfpunctset, ch); } +WXDLLEXPORT int wxIsspace(wxChar ch) { return CFCharacterSetIsCharacterMember(cfspaceset, ch); } +WXDLLEXPORT int wxIsupper(wxChar ch) { return CFCharacterSetIsCharacterMember(cfupperset, ch); } +WXDLLEXPORT int wxIsxdigit(wxChar ch) { return wxIsdigit(ch) || (ch>='a' && ch<='f') || (ch>='A' && ch<='F'); } +WXDLLEXPORT int wxTolower(wxChar ch) { return (wxChar)tolower((char)(ch)); } +WXDLLEXPORT int wxToupper(wxChar ch) { return (wxChar)toupper((char)(ch)); } + +#endif // wxNEED_WX_CTYPE_H + +#ifndef wxStrdupA + +WXDLLEXPORT char *wxStrdupA(const char *s) +{ + return strcpy((char *)malloc(strlen(s) + 1), s); +} + +#endif // wxStrdupA + +#ifndef wxStrdupW + +WXDLLEXPORT wchar_t * wxStrdupW(const wchar_t *pwz) +{ + size_t size = (wxWcslen(pwz) + 1) * sizeof(wchar_t); + wchar_t *ret = (wchar_t *) malloc(size); + memcpy(ret, pwz, size); + return ret; +} + +#endif // wxStrdupW + +#ifndef wxStricmp +int WXDLLEXPORT wxStricmp(const wxChar *psz1, const wxChar *psz2) +{ + register wxChar c1, c2; + do { + c1 = wxTolower(*psz1++); + c2 = wxTolower(*psz2++); + } while ( c1 && (c1 == c2) ); + return c1 - c2; +} +#endif + +#ifndef wxStricmp +int WXDLLEXPORT wxStrnicmp(const wxChar *s1, const wxChar *s2, size_t n) +{ + // initialize the variables just to suppress stupid gcc warning + register wxChar c1 = 0, c2 = 0; + while (n && ((c1 = wxTolower(*s1)) == (c2 = wxTolower(*s2)) ) && c1) n--, s1++, s2++; + if (n) { + if (c1 < c2) return -1; + if (c1 > c2) return 1; + } + return 0; +} +#endif + +#ifndef wxSetlocale +WXDLLEXPORT wxWCharBuffer wxSetlocale(int category, const wxChar *locale) +{ + char *localeOld = setlocale(category, wxConvLibc.cWX2MB(locale)); + + return wxWCharBuffer(wxConvLibc.cMB2WC(localeOld)); +} +#endif + +#if wxUSE_WCHAR_T && !defined(HAVE_WCSLEN) +WXDLLEXPORT size_t wxWcslen(const wchar_t *s) +{ + size_t n = 0; + while ( *s++ ) + n++; + + return n; +} +#endif + +// ---------------------------------------------------------------------------- +// string.h functions +// ---------------------------------------------------------------------------- + +#ifdef wxNEED_WX_STRING_H + +// RN: These need to be c externed for the regex lib +#ifdef __cplusplus +extern "C" { +#endif + +WXDLLEXPORT wxChar * wxStrcat(wxChar *dest, const wxChar *src) +{ + wxChar *ret = dest; + while (*dest) dest++; + while ((*dest++ = *src++)); + return ret; +} + +WXDLLEXPORT const wxChar * wxStrchr(const wxChar *s, wxChar c) +{ + // be careful here as the terminating NUL makes part of the string + while ( *s != c ) + { + if ( !*s++ ) + return NULL; + } + + return s; +} + +WXDLLEXPORT int wxStrcmp(const wxChar *s1, const wxChar *s2) +{ + while ((*s1 == *s2) && *s1) s1++, s2++; + if ((wxUChar)*s1 < (wxUChar)*s2) return -1; + if ((wxUChar)*s1 > (wxUChar)*s2) return 1; + return 0; +} + +WXDLLEXPORT wxChar * wxStrcpy(wxChar *dest, const wxChar *src) +{ + wxChar *ret = dest; + while ((*dest++ = *src++)); + return ret; +} + +WXDLLEXPORT size_t wxStrlen_(const wxChar *s) +{ + size_t n = 0; + while ( *s++ ) + n++; + + return n; +} + + +WXDLLEXPORT wxChar * wxStrncat(wxChar *dest, const wxChar *src, size_t n) +{ + wxChar *ret = dest; + while (*dest) dest++; + while (n && (*dest++ = *src++)) n--; + return ret; +} + +WXDLLEXPORT int wxStrncmp(const wxChar *s1, const wxChar *s2, size_t n) +{ + while (n && (*s1 == *s2) && *s1) n--, s1++, s2++; + if (n) { + if ((wxUChar)*s1 < (wxUChar)*s2) return -1; + if ((wxUChar)*s1 > (wxUChar)*s2) return 1; + } + return 0; +} + +WXDLLEXPORT wxChar * wxStrncpy(wxChar *dest, const wxChar *src, size_t n) +{ + wxChar *ret = dest; + while (n && (*dest++ = *src++)) n--; + while (n) *dest++=0, n--; // the docs specify padding with zeroes + return ret; +} + +WXDLLEXPORT const wxChar * wxStrpbrk(const wxChar *s, const wxChar *accept) +{ + while (*s && !wxStrchr(accept, *s)) + s++; + + return *s ? s : NULL; +} + +WXDLLEXPORT const wxChar * wxStrrchr(const wxChar *s, wxChar c) +{ + const wxChar *ret = NULL; + do + { + if ( *s == c ) + ret = s; + s++; + } + while ( *s ); + + return ret; +} + +WXDLLEXPORT size_t wxStrspn(const wxChar *s, const wxChar *accept) +{ + size_t len = 0; + while (wxStrchr(accept, *s++)) len++; + return len; +} + +WXDLLEXPORT const wxChar *wxStrstr(const wxChar *haystack, const wxChar *needle) +{ + wxASSERT_MSG( needle != NULL, _T("NULL argument in wxStrstr") ); + + // VZ: this is not exactly the most efficient string search algorithm... + + const size_t len = wxStrlen(needle); + + while ( const wxChar *fnd = wxStrchr(haystack, *needle) ) + { + if ( !wxStrncmp(fnd, needle, len) ) + return fnd; + + haystack = fnd + 1; + } + + return NULL; +} + +#ifdef __cplusplus +} +#endif + +WXDLLEXPORT double wxStrtod(const wxChar *nptr, wxChar **endptr) +{ + const wxChar decSep( +#if wxUSE_INTL + wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER)[0] +#else + _T('.') +#endif + ); + const wxChar *start = nptr; + + while (wxIsspace(*nptr)) nptr++; + if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++; + while (wxIsdigit(*nptr)) nptr++; + if (*nptr == decSep) { + nptr++; + while (wxIsdigit(*nptr)) nptr++; + } + if (*nptr == wxT('E') || *nptr == wxT('e')) { + nptr++; + if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++; + while (wxIsdigit(*nptr)) nptr++; + } + + wxString data(start, nptr-start); + const wxWX2MBbuf dat = data.mb_str(wxConvLibc); + char *rdat = wxMBSTRINGCAST dat; + double ret = strtod(dat, &rdat); + + if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat)); + + return ret; +} + +WXDLLEXPORT long int wxStrtol(const wxChar *nptr, wxChar **endptr, int base) +{ + const wxChar *start = nptr; + + while (wxIsspace(*nptr)) nptr++; + if (*nptr == wxT('+') || *nptr == wxT('-')) nptr++; + if (((base == 0) || (base == 16)) && + (nptr[0] == wxT('0') && nptr[1] == wxT('x'))) { + nptr += 2; + base = 16; + } + else if ((base == 0) && (nptr[0] == wxT('0'))) base = 8; + else if (base == 0) base = 10; + + while ((wxIsdigit(*nptr) && (*nptr - wxT('0') < base)) || + (wxIsalpha(*nptr) && (wxToupper(*nptr) - wxT('A') + 10 < base))) nptr++; + + wxString data(start, nptr-start); + wxWX2MBbuf dat = data.mb_str(wxConvLibc); + char *rdat = wxMBSTRINGCAST dat; + long int ret = strtol(dat, &rdat, base); + + if (endptr) *endptr = (wxChar *)(start + (rdat - (const char *)dat)); + + return ret; +} + +WXDLLEXPORT unsigned long int wxStrtoul(const wxChar *nptr, wxChar **endptr, int base) +{ + return (unsigned long int) wxStrtol(nptr, endptr, base); +} + +#endif // wxNEED_WX_STRING_H + +#ifdef wxNEED_WX_STDIO_H +WXDLLEXPORT FILE * wxFopen(const wxChar *path, const wxChar *mode) +{ + char mode_buffer[10]; + for (size_t i = 0; i < wxStrlen(mode)+1; i++) + mode_buffer[i] = (char) mode[i]; + + return fopen( wxConvFile.cWX2MB(path), mode_buffer ); +} + +WXDLLEXPORT FILE * wxFreopen(const wxChar *path, const wxChar *mode, FILE *stream) +{ + char mode_buffer[10]; + for (size_t i = 0; i < wxStrlen(mode)+1; i++) + mode_buffer[i] = (char) mode[i]; + + return freopen( wxConvFile.cWX2MB(path), mode_buffer, stream ); +} + +WXDLLEXPORT int wxRemove(const wxChar *path) +{ + return remove( wxConvFile.cWX2MB(path) ); +} + +WXDLLEXPORT int wxRename(const wxChar *oldpath, const wxChar *newpath) +{ + return rename( wxConvFile.cWX2MB(oldpath), wxConvFile.cWX2MB(newpath) ); +} +#endif + +#ifndef wxAtof +double WXDLLEXPORT wxAtof(const wxChar *psz) +{ +#ifdef __WXWINCE__ + double d; + wxString str(psz); + if (str.ToDouble(& d)) + return d; + + return 0.0; +#else + return atof(wxConvLibc.cWX2MB(psz)); +#endif +} +#endif + +#ifdef wxNEED_WX_STDLIB_H +int WXDLLEXPORT wxAtoi(const wxChar *psz) +{ + return atoi(wxConvLibc.cWX2MB(psz)); +} + +long WXDLLEXPORT wxAtol(const wxChar *psz) +{ + return atol(wxConvLibc.cWX2MB(psz)); +} + +wxChar * WXDLLEXPORT wxGetenv(const wxChar *name) +{ +#if wxUSE_UNICODE + // NB: buffer returned by getenv() is allowed to be overwritten next + // time getenv() is called, so it is OK to use static string + // buffer to hold the data. + static wxWCharBuffer value((wxChar*)NULL); + value = wxConvLibc.cMB2WX(getenv(wxConvLibc.cWX2MB(name))); + return value.data(); +#else + return getenv(name); +#endif +} +#endif // wxNEED_WX_STDLIB_H + +#ifdef wxNEED_WXSYSTEM +int WXDLLEXPORT wxSystem(const wxChar *psz) +{ + return system(wxConvLibc.cWX2MB(psz)); +} +#endif // wxNEED_WXSYSTEM + +#ifdef wxNEED_WX_TIME_H +WXDLLEXPORT size_t +wxStrftime(wxChar *s, size_t maxsize, const wxChar *fmt, const struct tm *tm) +{ + if ( !maxsize ) + return 0; + + wxCharBuffer buf(maxsize); + + wxCharBuffer bufFmt(wxConvLibc.cWX2MB(fmt)); + if ( !bufFmt ) + return 0; + + size_t ret = strftime(buf.data(), maxsize, bufFmt, tm); + if ( !ret ) + return 0; + + wxWCharBuffer wbuf = wxConvLibc.cMB2WX(buf); + if ( !wbuf ) + return 0; + + wxStrncpy(s, wbuf, maxsize); + return wxStrlen(s); +} +#endif // wxNEED_WX_TIME_H + +#ifndef wxCtime +WXDLLEXPORT wxChar *wxCtime(const time_t *timep) +{ + // normally the string is 26 chars but give one more in case some broken + // DOS compiler decides to use "\r\n" instead of "\n" at the end + static wxChar buf[27]; + + // ctime() is guaranteed to return a string containing only ASCII + // characters, as its format is always the same for any locale + wxStrncpy(buf, wxString::FromAscii(ctime(timep)), WXSIZEOF(buf)); + buf[WXSIZEOF(buf) - 1] = _T('\0'); + + return buf; +} +#endif // wxCtime + +#endif // wxUSE_WCHAR_T + +// ---------------------------------------------------------------------------- +// functions which we may need even if !wxUSE_WCHAR_T +// ---------------------------------------------------------------------------- + +#ifndef wxStrtok + +WXDLLEXPORT wxChar * wxStrtok(wxChar *psz, const wxChar *delim, wxChar **save_ptr) +{ + if (!psz) + { + psz = *save_ptr; + if ( !psz ) + return NULL; + } + + psz += wxStrspn(psz, delim); + if (!*psz) + { + *save_ptr = (wxChar *)NULL; + return (wxChar *)NULL; + } + + wxChar *ret = psz; + psz = wxStrpbrk(psz, delim); + if (!psz) + { + *save_ptr = (wxChar*)NULL; + } + else + { + *psz = wxT('\0'); + *save_ptr = psz + 1; + } + + return ret; +} + +#endif // wxStrtok + +// ---------------------------------------------------------------------------- +// missing C RTL functions +// ---------------------------------------------------------------------------- + +#ifdef wxNEED_STRDUP + +char *strdup(const char *s) +{ + char *dest = (char*) malloc( strlen( s ) + 1 ) ; + if ( dest ) + strcpy( dest , s ) ; + return dest ; +} +#endif // wxNEED_STRDUP + +#if defined(__WXWINCE__) && (_WIN32_WCE <= 211) + +void *calloc( size_t num, size_t size ) +{ + void** ptr = (void **)malloc(num * size); + memset( ptr, 0, num * size); + return ptr; +} + +#endif // __WXWINCE__ <= 211 + +#ifdef __WXWINCE__ + +int wxRemove(const wxChar *path) +{ + return ::DeleteFile(path) == 0; +} + +#endif diff --git a/Source/3rd Party/wx/src/common/xpmdecod.cpp b/Source/3rd Party/wx/src/common/xpmdecod.cpp index 2a5a8ef1a..3b01094c6 100644 --- a/Source/3rd Party/wx/src/common/xpmdecod.cpp +++ b/Source/3rd Party/wx/src/common/xpmdecod.cpp @@ -1,833 +1,833 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/xpmdecod.cpp -// Purpose: wxXPMDecoder -// Author: John Cristy, Vaclav Slavik -// RCS-ID: $Id: xpmdecod.cpp 54948 2008-08-03 10:54:33Z VZ $ -// Copyright: (c) John Cristy, Vaclav Slavik -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -/* - -This file is partially based on source code of ImageMagick by John Cristy. Its -license is as follows: - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% % -% % -% % -% X X PPPP M M % -% X X P P MM MM % -% X PPPP M M M % -% X X P M M % -% X X P M M % -% % -% % -% Read/Write ImageMagick Image Format. % -% % -% % -% Software Design % -% John Cristy % -% July 1992 % -% % -% % -% Copyright (C) 2001 ImageMagick Studio, a non-profit organization dedicated % -% to making software imaging solutions freely available. % -% % -% Permission is hereby granted, free of charge, to any person obtaining a % -% copy of this software and associated documentation files ("ImageMagick"), % -% to deal in ImageMagick without restriction, including without limitation % -% the rights to use, copy, modify, merge, publish, distribute, sublicense, % -% and/or sell copies of ImageMagick, and to permit persons to whom the % -% ImageMagick is furnished to do so, subject to the following conditions: % -% % -% The above copyright notice and this permission notice shall be included in % -% all copies or substantial portions of ImageMagick. % -% % -% The software is provided "as is", without warranty of any kind, express or % -% implied, including but not limited to the warranties of merchantability, % -% fitness for a particular purpose and noninfringement. In no event shall % -% ImageMagick Studio be liable for any claim, damages or other liability, % -% whether in an action of contract, tort or otherwise, arising from, out of % -% or in connection with ImageMagick or the use or other dealings in % -% ImageMagick. % -% % -% Except as contained in this notice, the name of the ImageMagick Studio % -% shall not be used in advertising or otherwise to promote the sale, use or % -% other dealings in ImageMagick without prior written authorization from the % -% ImageMagick Studio. % -% % -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% -% -*/ - -/* - * Also contains some pieces from libxpm and its modification for win32 by - * HeDu : - * - * Copyright (C) 1989-95 GROUPE BULL - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to - * deal in the Software without restriction, including without limitation the - * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - * sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN - * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - * Except as contained in this notice, the name of GROUPE BULL shall not be - * used in advertising or otherwise to promote the sale, use or other dealings - * in this Software without prior written authorization from GROUPE BULL. - */ - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_IMAGE && wxUSE_XPM - -#include "wx/xpmdecod.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" - #include "wx/hashmap.h" - #include "wx/stream.h" - #include "wx/image.h" - #include "wx/palette.h" -#endif - -#include -#include - -#if wxUSE_STREAMS -bool wxXPMDecoder::CanRead(wxInputStream& stream) -{ - unsigned char buf[9]; - - if ( !stream.Read(buf, WXSIZEOF(buf)) ) - return false; - - stream.SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent); - - return memcmp(buf, "/* XPM */", WXSIZEOF(buf)) == 0; -} - -wxImage wxXPMDecoder::ReadFile(wxInputStream& stream) -{ - size_t length = stream.GetSize(); - wxCHECK_MSG( length != 0, wxNullImage, - wxT("Cannot read XPM from stream of unknown size") ); - - // use a smart buffer to be sure to free memory even when we return on - // error - wxCharBuffer buffer(length); - - char *xpm_buffer = (char *)buffer.data(); - if ( stream.Read(xpm_buffer, length).GetLastError() == wxSTREAM_READ_ERROR ) - return wxNullImage; - xpm_buffer[length] = '\0'; - - /* - * Remove comments from the file: - */ - char *p, *q; - for (p = xpm_buffer; *p != '\0'; p++) - { - if ( (*p == '"') || (*p == '\'') ) - { - if (*p == '"') - { - for (p++; *p != '\0'; p++) - if ( (*p == '"') && (*(p - 1) != '\\') ) - break; - } - else // *p == '\'' - { - for (p++; *p != '\0'; p++) - if ( (*p == '\'') && (*(p - 1) != '\\') ) - break; - } - if (*p == '\0') - break; - continue; - } - if ( (*p != '/') || (*(p + 1) != '*') ) - continue; - for (q = p + 2; *q != '\0'; q++) - { - if ( (*q == '*') && (*(q + 1) == '/') ) - break; - } - - // memmove allows overlaps (unlike strcpy): - size_t cpylen = strlen(q + 2) + 1; - memmove(p, q + 2, cpylen); - } - - /* - * Remove unquoted characters: - */ - size_t i = 0; - for (p = xpm_buffer; *p != '\0'; p++) - { - if ( *p != '"' ) - continue; - for (q = p + 1; *q != '\0'; q++) - if (*q == '"') - break; - strncpy(xpm_buffer + i, p + 1, q - p - 1); - i += q - p - 1; - xpm_buffer[i++] = '\n'; - p = q + 1; - } - xpm_buffer[i] = '\0'; - - /* - * Create array of lines and convert \n's to \0's: - */ - const char **xpm_lines; - size_t lines_cnt = 0; - size_t line; - - for (p = xpm_buffer; *p != '\0'; p++) - { - if ( *p == '\n' ) - lines_cnt++; - } - - if ( !lines_cnt ) - { - // this doesn't really look an XPM image - return wxNullImage; - } - - xpm_lines = new const char*[lines_cnt + 1]; - xpm_lines[0] = xpm_buffer; - line = 1; - for (p = xpm_buffer; (*p != '\0') && (line < lines_cnt); p++) - { - if ( *p == '\n' ) - { - xpm_lines[line] = p + 1; - *p = '\0'; - line++; - } - } - - xpm_lines[lines_cnt] = NULL; - - /* - * Read the image: - */ - wxImage img = ReadData(xpm_lines); - - delete[] xpm_lines; - - return img; -} -#endif // wxUSE_STREAMS - - -/*****************************************************************************\ -* rgbtab.h * -* * -* A hard coded rgb.txt. To keep it short I removed all colornames with * -* trailing numbers, Blue3 etc, except the GrayXX. Sorry Grey-lovers I prefer * -* Gray ;-). But Grey is recognized on lookups, only on save Gray will be * -* used, maybe you want to do some substitue there too. * -* * -* To save memory the RGBs are coded in one long value, as done by the RGB * -* macro. * -* * -* Developed by HeDu 3/94 (hedu@cul-ipn.uni-kiel.de) * -\*****************************************************************************/ - - -typedef struct -{ - const char *name; - wxUint32 rgb; -} rgbRecord; - -#define myRGB(r,g,b) ((wxUint32)r<<16|(wxUint32)g<<8|(wxUint32)b) - -static rgbRecord theRGBRecords[] = -{ - {"aliceblue", myRGB(240, 248, 255)}, - {"antiquewhite", myRGB(250, 235, 215)}, - {"aquamarine", myRGB(50, 191, 193)}, - {"azure", myRGB(240, 255, 255)}, - {"beige", myRGB(245, 245, 220)}, - {"bisque", myRGB(255, 228, 196)}, - {"black", myRGB(0, 0, 0)}, - {"blanchedalmond", myRGB(255, 235, 205)}, - {"blue", myRGB(0, 0, 255)}, - {"blueviolet", myRGB(138, 43, 226)}, - {"brown", myRGB(165, 42, 42)}, - {"burlywood", myRGB(222, 184, 135)}, - {"cadetblue", myRGB(95, 146, 158)}, - {"chartreuse", myRGB(127, 255, 0)}, - {"chocolate", myRGB(210, 105, 30)}, - {"coral", myRGB(255, 114, 86)}, - {"cornflowerblue", myRGB(34, 34, 152)}, - {"cornsilk", myRGB(255, 248, 220)}, - {"cyan", myRGB(0, 255, 255)}, - {"darkgoldenrod", myRGB(184, 134, 11)}, - {"darkgreen", myRGB(0, 86, 45)}, - {"darkkhaki", myRGB(189, 183, 107)}, - {"darkolivegreen", myRGB(85, 86, 47)}, - {"darkorange", myRGB(255, 140, 0)}, - {"darkorchid", myRGB(139, 32, 139)}, - {"darksalmon", myRGB(233, 150, 122)}, - {"darkseagreen", myRGB(143, 188, 143)}, - {"darkslateblue", myRGB(56, 75, 102)}, - {"darkslategray", myRGB(47, 79, 79)}, - {"darkturquoise", myRGB(0, 166, 166)}, - {"darkviolet", myRGB(148, 0, 211)}, - {"deeppink", myRGB(255, 20, 147)}, - {"deepskyblue", myRGB(0, 191, 255)}, - {"dimgray", myRGB(84, 84, 84)}, - {"dodgerblue", myRGB(30, 144, 255)}, - {"firebrick", myRGB(142, 35, 35)}, - {"floralwhite", myRGB(255, 250, 240)}, - {"forestgreen", myRGB(80, 159, 105)}, - {"gainsboro", myRGB(220, 220, 220)}, - {"ghostwhite", myRGB(248, 248, 255)}, - {"gold", myRGB(218, 170, 0)}, - {"goldenrod", myRGB(239, 223, 132)}, - {"gray", myRGB(126, 126, 126)}, - {"gray0", myRGB(0, 0, 0)}, - {"gray1", myRGB(3, 3, 3)}, - {"gray10", myRGB(26, 26, 26)}, - {"gray100", myRGB(255, 255, 255)}, - {"gray11", myRGB(28, 28, 28)}, - {"gray12", myRGB(31, 31, 31)}, - {"gray13", myRGB(33, 33, 33)}, - {"gray14", myRGB(36, 36, 36)}, - {"gray15", myRGB(38, 38, 38)}, - {"gray16", myRGB(41, 41, 41)}, - {"gray17", myRGB(43, 43, 43)}, - {"gray18", myRGB(46, 46, 46)}, - {"gray19", myRGB(48, 48, 48)}, - {"gray2", myRGB(5, 5, 5)}, - {"gray20", myRGB(51, 51, 51)}, - {"gray21", myRGB(54, 54, 54)}, - {"gray22", myRGB(56, 56, 56)}, - {"gray23", myRGB(59, 59, 59)}, - {"gray24", myRGB(61, 61, 61)}, - {"gray25", myRGB(64, 64, 64)}, - {"gray26", myRGB(66, 66, 66)}, - {"gray27", myRGB(69, 69, 69)}, - {"gray28", myRGB(71, 71, 71)}, - {"gray29", myRGB(74, 74, 74)}, - {"gray3", myRGB(8, 8, 8)}, - {"gray30", myRGB(77, 77, 77)}, - {"gray31", myRGB(79, 79, 79)}, - {"gray32", myRGB(82, 82, 82)}, - {"gray33", myRGB(84, 84, 84)}, - {"gray34", myRGB(87, 87, 87)}, - {"gray35", myRGB(89, 89, 89)}, - {"gray36", myRGB(92, 92, 92)}, - {"gray37", myRGB(94, 94, 94)}, - {"gray38", myRGB(97, 97, 97)}, - {"gray39", myRGB(99, 99, 99)}, - {"gray4", myRGB(10, 10, 10)}, - {"gray40", myRGB(102, 102, 102)}, - {"gray41", myRGB(105, 105, 105)}, - {"gray42", myRGB(107, 107, 107)}, - {"gray43", myRGB(110, 110, 110)}, - {"gray44", myRGB(112, 112, 112)}, - {"gray45", myRGB(115, 115, 115)}, - {"gray46", myRGB(117, 117, 117)}, - {"gray47", myRGB(120, 120, 120)}, - {"gray48", myRGB(122, 122, 122)}, - {"gray49", myRGB(125, 125, 125)}, - {"gray5", myRGB(13, 13, 13)}, - {"gray50", myRGB(127, 127, 127)}, - {"gray51", myRGB(130, 130, 130)}, - {"gray52", myRGB(133, 133, 133)}, - {"gray53", myRGB(135, 135, 135)}, - {"gray54", myRGB(138, 138, 138)}, - {"gray55", myRGB(140, 140, 140)}, - {"gray56", myRGB(143, 143, 143)}, - {"gray57", myRGB(145, 145, 145)}, - {"gray58", myRGB(148, 148, 148)}, - {"gray59", myRGB(150, 150, 150)}, - {"gray6", myRGB(15, 15, 15)}, - {"gray60", myRGB(153, 153, 153)}, - {"gray61", myRGB(156, 156, 156)}, - {"gray62", myRGB(158, 158, 158)}, - {"gray63", myRGB(161, 161, 161)}, - {"gray64", myRGB(163, 163, 163)}, - {"gray65", myRGB(166, 166, 166)}, - {"gray66", myRGB(168, 168, 168)}, - {"gray67", myRGB(171, 171, 171)}, - {"gray68", myRGB(173, 173, 173)}, - {"gray69", myRGB(176, 176, 176)}, - {"gray7", myRGB(18, 18, 18)}, - {"gray70", myRGB(179, 179, 179)}, - {"gray71", myRGB(181, 181, 181)}, - {"gray72", myRGB(184, 184, 184)}, - {"gray73", myRGB(186, 186, 186)}, - {"gray74", myRGB(189, 189, 189)}, - {"gray75", myRGB(191, 191, 191)}, - {"gray76", myRGB(194, 194, 194)}, - {"gray77", myRGB(196, 196, 196)}, - {"gray78", myRGB(199, 199, 199)}, - {"gray79", myRGB(201, 201, 201)}, - {"gray8", myRGB(20, 20, 20)}, - {"gray80", myRGB(204, 204, 204)}, - {"gray81", myRGB(207, 207, 207)}, - {"gray82", myRGB(209, 209, 209)}, - {"gray83", myRGB(212, 212, 212)}, - {"gray84", myRGB(214, 214, 214)}, - {"gray85", myRGB(217, 217, 217)}, - {"gray86", myRGB(219, 219, 219)}, - {"gray87", myRGB(222, 222, 222)}, - {"gray88", myRGB(224, 224, 224)}, - {"gray89", myRGB(227, 227, 227)}, - {"gray9", myRGB(23, 23, 23)}, - {"gray90", myRGB(229, 229, 229)}, - {"gray91", myRGB(232, 232, 232)}, - {"gray92", myRGB(235, 235, 235)}, - {"gray93", myRGB(237, 237, 237)}, - {"gray94", myRGB(240, 240, 240)}, - {"gray95", myRGB(242, 242, 242)}, - {"gray96", myRGB(245, 245, 245)}, - {"gray97", myRGB(247, 247, 247)}, - {"gray98", myRGB(250, 250, 250)}, - {"gray99", myRGB(252, 252, 252)}, - {"green", myRGB(0, 255, 0)}, - {"greenyellow", myRGB(173, 255, 47)}, - {"honeydew", myRGB(240, 255, 240)}, - {"hotpink", myRGB(255, 105, 180)}, - {"indianred", myRGB(107, 57, 57)}, - {"ivory", myRGB(255, 255, 240)}, - {"khaki", myRGB(179, 179, 126)}, - {"lavender", myRGB(230, 230, 250)}, - {"lavenderblush", myRGB(255, 240, 245)}, - {"lawngreen", myRGB(124, 252, 0)}, - {"lemonchiffon", myRGB(255, 250, 205)}, - {"lightblue", myRGB(176, 226, 255)}, - {"lightcoral", myRGB(240, 128, 128)}, - {"lightcyan", myRGB(224, 255, 255)}, - {"lightgoldenrod", myRGB(238, 221, 130)}, - {"lightgoldenrodyellow", myRGB(250, 250, 210)}, - {"lightgray", myRGB(168, 168, 168)}, - {"lightpink", myRGB(255, 182, 193)}, - {"lightsalmon", myRGB(255, 160, 122)}, - {"lightseagreen", myRGB(32, 178, 170)}, - {"lightskyblue", myRGB(135, 206, 250)}, - {"lightslateblue", myRGB(132, 112, 255)}, - {"lightslategray", myRGB(119, 136, 153)}, - {"lightsteelblue", myRGB(124, 152, 211)}, - {"lightyellow", myRGB(255, 255, 224)}, - {"limegreen", myRGB(0, 175, 20)}, - {"linen", myRGB(250, 240, 230)}, - {"magenta", myRGB(255, 0, 255)}, - {"maroon", myRGB(143, 0, 82)}, - {"mediumaquamarine", myRGB(0, 147, 143)}, - {"mediumblue", myRGB(50, 50, 204)}, - {"mediumforestgreen", myRGB(50, 129, 75)}, - {"mediumgoldenrod", myRGB(209, 193, 102)}, - {"mediumorchid", myRGB(189, 82, 189)}, - {"mediumpurple", myRGB(147, 112, 219)}, - {"mediumseagreen", myRGB(52, 119, 102)}, - {"mediumslateblue", myRGB(106, 106, 141)}, - {"mediumspringgreen", myRGB(35, 142, 35)}, - {"mediumturquoise", myRGB(0, 210, 210)}, - {"mediumvioletred", myRGB(213, 32, 121)}, - {"midnightblue", myRGB(47, 47, 100)}, - {"mintcream", myRGB(245, 255, 250)}, - {"mistyrose", myRGB(255, 228, 225)}, - {"moccasin", myRGB(255, 228, 181)}, - {"navajowhite", myRGB(255, 222, 173)}, - {"navy", myRGB(35, 35, 117)}, - {"navyblue", myRGB(35, 35, 117)}, - {"oldlace", myRGB(253, 245, 230)}, - {"olivedrab", myRGB(107, 142, 35)}, - {"orange", myRGB(255, 135, 0)}, - {"orangered", myRGB(255, 69, 0)}, - {"orchid", myRGB(239, 132, 239)}, - {"palegoldenrod", myRGB(238, 232, 170)}, - {"palegreen", myRGB(115, 222, 120)}, - {"paleturquoise", myRGB(175, 238, 238)}, - {"palevioletred", myRGB(219, 112, 147)}, - {"papayawhip", myRGB(255, 239, 213)}, - {"peachpuff", myRGB(255, 218, 185)}, - {"peru", myRGB(205, 133, 63)}, - {"pink", myRGB(255, 181, 197)}, - {"plum", myRGB(197, 72, 155)}, - {"powderblue", myRGB(176, 224, 230)}, - {"purple", myRGB(160, 32, 240)}, - {"red", myRGB(255, 0, 0)}, - {"rosybrown", myRGB(188, 143, 143)}, - {"royalblue", myRGB(65, 105, 225)}, - {"saddlebrown", myRGB(139, 69, 19)}, - {"salmon", myRGB(233, 150, 122)}, - {"sandybrown", myRGB(244, 164, 96)}, - {"seagreen", myRGB(82, 149, 132)}, - {"seashell", myRGB(255, 245, 238)}, - {"sienna", myRGB(150, 82, 45)}, - {"silver", myRGB(192, 192, 192)}, - {"skyblue", myRGB(114, 159, 255)}, - {"slateblue", myRGB(126, 136, 171)}, - {"slategray", myRGB(112, 128, 144)}, - {"snow", myRGB(255, 250, 250)}, - {"springgreen", myRGB(65, 172, 65)}, - {"steelblue", myRGB(84, 112, 170)}, - {"tan", myRGB(222, 184, 135)}, - {"thistle", myRGB(216, 191, 216)}, - {"tomato", myRGB(255, 99, 71)}, - {"transparent", myRGB(0, 0, 1)}, - {"turquoise", myRGB(25, 204, 223)}, - {"violet", myRGB(156, 62, 206)}, - {"violetred", myRGB(243, 62, 150)}, - {"wheat", myRGB(245, 222, 179)}, - {"white", myRGB(255, 255, 255)}, - {"whitesmoke", myRGB(245, 245, 245)}, - {"yellow", myRGB(255, 255, 0)}, - {"yellowgreen", myRGB(50, 216, 56)}, - {NULL, myRGB(0, 0, 0)} -}; -static int numTheRGBRecords = 235; - -static unsigned char ParseHexadecimal(char digit1, char digit2) -{ - unsigned char i1, i2; - - if (digit1 >= 'a') - i1 = (unsigned char)(digit1 - 'a' + 0x0A); - else if (digit1 >= 'A') - i1 = (unsigned char)(digit1 - 'A' + 0x0A); - else - i1 = (unsigned char)(digit1 - '0'); - if (digit2 >= 'a') - i2 = (unsigned char)(digit2 - 'a' + 0x0A); - else if (digit2 >= 'A') - i2 = (unsigned char)(digit2 - 'A' + 0x0A); - else - i2 = (unsigned char)(digit2 - '0'); - return (unsigned char)(0x10 * i1 + i2); -} - -static bool GetRGBFromName(const char *inname, bool *isNone, - unsigned char *r, unsigned char*g, unsigned char *b) -{ - int left, right, middle; - int cmp; - wxUint32 rgbVal; - char *name; - char *grey, *p; - - // Neither #rrggbb nor #rrrrggggbbbb are in database, we parse them directly - size_t inname_len = strlen(inname); - if ( *inname == '#' && (inname_len == 7 || inname_len == 13)) - { - size_t ofs = (inname_len == 7) ? 2 : 4; - *r = ParseHexadecimal(inname[1], inname[2]); - *g = ParseHexadecimal(inname[1*ofs+1], inname[1*ofs+2]); - *b = ParseHexadecimal(inname[2*ofs+1], inname[2*ofs+2]); - *isNone = false; - return true; - } - - name = wxStrdupA(inname); - - // theRGBRecords[] has no names with spaces, and no grey, but a - // lot of gray... - - // so first extract ' ' - while ((p = strchr(name, ' ')) != NULL) - { - while (*(p)) // till eof of string - { - *p = *(p + 1); // copy to the left - p++; - } - } - // fold to lower case - p = name; - while (*p) - { - *p = (char)tolower(*p); - p++; - } - - // substitute Grey with Gray, else rgbtab.h would have more than 100 - // 'duplicate' entries - if ( (grey = strstr(name, "grey")) != NULL ) - grey[2] = 'a'; - - // check for special 'none' colour: - bool found; - if ( strcmp(name, "none") == 0 ) - { - *isNone = true; - found = true; - } - else // not "None" - { - found = false; - - // binary search: - left = 0; - right = numTheRGBRecords - 1; - do - { - middle = (left + right) / 2; - cmp = strcmp(name, theRGBRecords[middle].name); - if ( cmp == 0 ) - { - rgbVal = theRGBRecords[middle].rgb; - *r = (unsigned char)((rgbVal >> 16) & 0xFF); - *g = (unsigned char)((rgbVal >> 8) & 0xFF); - *b = (unsigned char)((rgbVal) & 0xFF); - *isNone = false; - found = true; - break; - } - else if ( cmp < 0 ) - { - right = middle - 1; - } - else // cmp > 0 - { - left = middle + 1; - } - } while (left <= right); - } - - free(name); - - return found; -} - -static const char *ParseColor(const char *data) -{ - static const char *targets[] = - {"c ", "g ", "g4 ", "m ", "b ", "s ", NULL}; - - const char *p, *r; - const char *q; - int i; - - for (i = 0; targets[i] != NULL; i++) - { - r = data; - for (q = targets[i]; *r != '\0'; r++) - { - if ( *r != *q ) - continue; - if ( !isspace((int) (*(r - 1))) ) - continue; - p = r; - for (;;) - { - if ( *q == '\0' ) - return p; - if ( *p++ != *q++ ) - break; - } - q = targets[i]; - } - } - return NULL; -} - -struct wxXPMColourMapData -{ - wxXPMColourMapData() { R = G = B = 0; } - unsigned char R,G,B; -}; -WX_DECLARE_STRING_HASH_MAP(wxXPMColourMapData, wxXPMColourMap); - -wxImage wxXPMDecoder::ReadData(const char* const* xpm_data) -{ - wxCHECK_MSG(xpm_data, wxNullImage, wxT("NULL XPM data") ); - - wxImage img; - int count; - unsigned width, height, colors_cnt, chars_per_pixel; - size_t i, j, i_key; - wxChar key[64]; - const char *clr_def; - bool hasMask; - wxXPMColourMap clr_tbl; - wxXPMColourMap::iterator it; - wxString maskKey; - - /* - * Read hints and initialize structures: - */ - - count = sscanf(xpm_data[0], "%u %u %u %u", - &width, &height, &colors_cnt, &chars_per_pixel); - if ( count != 4 || width * height * colors_cnt == 0 ) - { - wxLogError(_("XPM: incorrect header format!")); - return wxNullImage; - } - - // VS: XPM color map this large would be insane, since XPMs are encoded with - // 92 possible values on each position, 92^64 is *way* larger space than - // 8bit RGB... - wxCHECK_MSG(chars_per_pixel < 64, wxNullImage, wxT("XPM colormaps this large not supported.")); - - if ( !img.Create(width, height) ) - return wxNullImage; - - img.SetMask(false); - key[chars_per_pixel] = wxT('\0'); - hasMask = false; - - /* - * Create colour map: - */ - wxXPMColourMapData clr_data; - for (i = 0; i < colors_cnt; i++) - { - const char *xmpColLine = xpm_data[1 + i]; - - // we must have at least " x y" after the colour index, hence +5 - if ( !xmpColLine || strlen(xmpColLine) < chars_per_pixel + 5 ) - { - wxLogError(_("XPM: incorrect colour description in line %d"), - (int)(1 + i)); - return wxNullImage; - } - - for (i_key = 0; i_key < chars_per_pixel; i_key++) - key[i_key] = (wxChar)xmpColLine[i_key]; - clr_def = ParseColor(xmpColLine + chars_per_pixel); - - if ( clr_def == NULL ) - { - wxLogError(_("XPM: malformed colour definition '%s' at line %d!"), - xmpColLine, (int)(1 + i)); - return wxNullImage; - } - - bool isNone = false; - if ( !GetRGBFromName(clr_def, &isNone, - &clr_data.R, &clr_data.G, &clr_data.B) ) - { - wxLogError(_("XPM: malformed colour definition '%s' at line %d!"), - xmpColLine, (int)(1 + i)); - return wxNullImage; - } - - if ( isNone ) - { - img.SetMask(true); - img.SetMaskColour(255, 0, 255); - clr_data.R = - clr_data.B = 255; - clr_data.G = 0; - hasMask = true; - maskKey = key; - } - - clr_tbl[key] = clr_data; - } - - /* - * Modify colour entries with RGB = (255,0,255) to (255,0,254) if - * mask colour is present (so that existing pixels with (255,0,255) - * magenta colour are not incorrectly made transparent): - */ - if (hasMask) - { - for (it = clr_tbl.begin(); it != clr_tbl.end(); ++it) - { - if (it->second.R == 255 && it->second.G == 0 && - it->second.B == 255 && - it->first != maskKey) - { - it->second.B = 254; - } - } - } - - /* - * Parse image data: - */ - - unsigned char *img_data = img.GetData(); - wxXPMColourMap::iterator entry; - wxXPMColourMap::iterator end = clr_tbl.end(); - - for (j = 0; j < height; j++) - { - for (i = 0; i < width; i++, img_data += 3) - { - const char *xpmImgLine = xpm_data[1 + colors_cnt + j]; - if ( !xpmImgLine || strlen(xpmImgLine) < width*chars_per_pixel ) - { - wxLogError(_("XPM: truncated image data at line %d!"), - (int)(1 + colors_cnt + j)); - return wxNullImage; - } - - for (i_key = 0; i_key < chars_per_pixel; i_key++) - { - key[i_key] = (wxChar)xpmImgLine[chars_per_pixel * i + i_key]; - } - - entry = clr_tbl.find(key); - if ( entry == end ) - { - wxLogError(_("XPM: Malformed pixel data!")); - - // better return right now as otherwise we risk to flood the - // user with error messages as something seems to be seriously - // wrong with the file and so we could give this message for - // each remaining pixel if we don't bail out - return wxNullImage; - } - else - { - img_data[0] = entry->second.R; - img_data[1] = entry->second.G; - img_data[2] = entry->second.B; - } - } - } - -#if wxUSE_PALETTE - unsigned char* r = new unsigned char[colors_cnt]; - unsigned char* g = new unsigned char[colors_cnt]; - unsigned char* b = new unsigned char[colors_cnt]; - - for (it = clr_tbl.begin(), i = 0; it != clr_tbl.end(); it++, i++) - { - r[i] = it->second.R; - g[i] = it->second.G; - b[i] = it->second.B; - } - wxASSERT(i == colors_cnt); - img.SetPalette(wxPalette(colors_cnt, r, g, b)); - delete[] r; - delete[] g; - delete[] b; -#endif // wxUSE_PALETTE - - return img; -} - -#endif // wxUSE_IMAGE && wxUSE_XPM +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/xpmdecod.cpp +// Purpose: wxXPMDecoder +// Author: John Cristy, Vaclav Slavik +// RCS-ID: $Id: xpmdecod.cpp 54948 2008-08-03 10:54:33Z VZ $ +// Copyright: (c) John Cristy, Vaclav Slavik +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +/* + +This file is partially based on source code of ImageMagick by John Cristy. Its +license is as follows: + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% % +% % +% % +% X X PPPP M M % +% X X P P MM MM % +% X PPPP M M M % +% X X P M M % +% X X P M M % +% % +% % +% Read/Write ImageMagick Image Format. % +% % +% % +% Software Design % +% John Cristy % +% July 1992 % +% % +% % +% Copyright (C) 2001 ImageMagick Studio, a non-profit organization dedicated % +% to making software imaging solutions freely available. % +% % +% Permission is hereby granted, free of charge, to any person obtaining a % +% copy of this software and associated documentation files ("ImageMagick"), % +% to deal in ImageMagick without restriction, including without limitation % +% the rights to use, copy, modify, merge, publish, distribute, sublicense, % +% and/or sell copies of ImageMagick, and to permit persons to whom the % +% ImageMagick is furnished to do so, subject to the following conditions: % +% % +% The above copyright notice and this permission notice shall be included in % +% all copies or substantial portions of ImageMagick. % +% % +% The software is provided "as is", without warranty of any kind, express or % +% implied, including but not limited to the warranties of merchantability, % +% fitness for a particular purpose and noninfringement. In no event shall % +% ImageMagick Studio be liable for any claim, damages or other liability, % +% whether in an action of contract, tort or otherwise, arising from, out of % +% or in connection with ImageMagick or the use or other dealings in % +% ImageMagick. % +% % +% Except as contained in this notice, the name of the ImageMagick Studio % +% shall not be used in advertising or otherwise to promote the sale, use or % +% other dealings in ImageMagick without prior written authorization from the % +% ImageMagick Studio. % +% % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% +*/ + +/* + * Also contains some pieces from libxpm and its modification for win32 by + * HeDu : + * + * Copyright (C) 1989-95 GROUPE BULL + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * GROUPE BULL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN + * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name of GROUPE BULL shall not be + * used in advertising or otherwise to promote the sale, use or other dealings + * in this Software without prior written authorization from GROUPE BULL. + */ + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_IMAGE && wxUSE_XPM + +#include "wx/xpmdecod.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" + #include "wx/hashmap.h" + #include "wx/stream.h" + #include "wx/image.h" + #include "wx/palette.h" +#endif + +#include +#include + +#if wxUSE_STREAMS +bool wxXPMDecoder::CanRead(wxInputStream& stream) +{ + unsigned char buf[9]; + + if ( !stream.Read(buf, WXSIZEOF(buf)) ) + return false; + + stream.SeekI(-(wxFileOffset)WXSIZEOF(buf), wxFromCurrent); + + return memcmp(buf, "/* XPM */", WXSIZEOF(buf)) == 0; +} + +wxImage wxXPMDecoder::ReadFile(wxInputStream& stream) +{ + size_t length = stream.GetSize(); + wxCHECK_MSG( length != 0, wxNullImage, + wxT("Cannot read XPM from stream of unknown size") ); + + // use a smart buffer to be sure to free memory even when we return on + // error + wxCharBuffer buffer(length); + + char *xpm_buffer = (char *)buffer.data(); + if ( stream.Read(xpm_buffer, length).GetLastError() == wxSTREAM_READ_ERROR ) + return wxNullImage; + xpm_buffer[length] = '\0'; + + /* + * Remove comments from the file: + */ + char *p, *q; + for (p = xpm_buffer; *p != '\0'; p++) + { + if ( (*p == '"') || (*p == '\'') ) + { + if (*p == '"') + { + for (p++; *p != '\0'; p++) + if ( (*p == '"') && (*(p - 1) != '\\') ) + break; + } + else // *p == '\'' + { + for (p++; *p != '\0'; p++) + if ( (*p == '\'') && (*(p - 1) != '\\') ) + break; + } + if (*p == '\0') + break; + continue; + } + if ( (*p != '/') || (*(p + 1) != '*') ) + continue; + for (q = p + 2; *q != '\0'; q++) + { + if ( (*q == '*') && (*(q + 1) == '/') ) + break; + } + + // memmove allows overlaps (unlike strcpy): + size_t cpylen = strlen(q + 2) + 1; + memmove(p, q + 2, cpylen); + } + + /* + * Remove unquoted characters: + */ + size_t i = 0; + for (p = xpm_buffer; *p != '\0'; p++) + { + if ( *p != '"' ) + continue; + for (q = p + 1; *q != '\0'; q++) + if (*q == '"') + break; + strncpy(xpm_buffer + i, p + 1, q - p - 1); + i += q - p - 1; + xpm_buffer[i++] = '\n'; + p = q + 1; + } + xpm_buffer[i] = '\0'; + + /* + * Create array of lines and convert \n's to \0's: + */ + const char **xpm_lines; + size_t lines_cnt = 0; + size_t line; + + for (p = xpm_buffer; *p != '\0'; p++) + { + if ( *p == '\n' ) + lines_cnt++; + } + + if ( !lines_cnt ) + { + // this doesn't really look an XPM image + return wxNullImage; + } + + xpm_lines = new const char*[lines_cnt + 1]; + xpm_lines[0] = xpm_buffer; + line = 1; + for (p = xpm_buffer; (*p != '\0') && (line < lines_cnt); p++) + { + if ( *p == '\n' ) + { + xpm_lines[line] = p + 1; + *p = '\0'; + line++; + } + } + + xpm_lines[lines_cnt] = NULL; + + /* + * Read the image: + */ + wxImage img = ReadData(xpm_lines); + + delete[] xpm_lines; + + return img; +} +#endif // wxUSE_STREAMS + + +/*****************************************************************************\ +* rgbtab.h * +* * +* A hard coded rgb.txt. To keep it short I removed all colornames with * +* trailing numbers, Blue3 etc, except the GrayXX. Sorry Grey-lovers I prefer * +* Gray ;-). But Grey is recognized on lookups, only on save Gray will be * +* used, maybe you want to do some substitue there too. * +* * +* To save memory the RGBs are coded in one long value, as done by the RGB * +* macro. * +* * +* Developed by HeDu 3/94 (hedu@cul-ipn.uni-kiel.de) * +\*****************************************************************************/ + + +typedef struct +{ + const char *name; + wxUint32 rgb; +} rgbRecord; + +#define myRGB(r,g,b) ((wxUint32)r<<16|(wxUint32)g<<8|(wxUint32)b) + +static rgbRecord theRGBRecords[] = +{ + {"aliceblue", myRGB(240, 248, 255)}, + {"antiquewhite", myRGB(250, 235, 215)}, + {"aquamarine", myRGB(50, 191, 193)}, + {"azure", myRGB(240, 255, 255)}, + {"beige", myRGB(245, 245, 220)}, + {"bisque", myRGB(255, 228, 196)}, + {"black", myRGB(0, 0, 0)}, + {"blanchedalmond", myRGB(255, 235, 205)}, + {"blue", myRGB(0, 0, 255)}, + {"blueviolet", myRGB(138, 43, 226)}, + {"brown", myRGB(165, 42, 42)}, + {"burlywood", myRGB(222, 184, 135)}, + {"cadetblue", myRGB(95, 146, 158)}, + {"chartreuse", myRGB(127, 255, 0)}, + {"chocolate", myRGB(210, 105, 30)}, + {"coral", myRGB(255, 114, 86)}, + {"cornflowerblue", myRGB(34, 34, 152)}, + {"cornsilk", myRGB(255, 248, 220)}, + {"cyan", myRGB(0, 255, 255)}, + {"darkgoldenrod", myRGB(184, 134, 11)}, + {"darkgreen", myRGB(0, 86, 45)}, + {"darkkhaki", myRGB(189, 183, 107)}, + {"darkolivegreen", myRGB(85, 86, 47)}, + {"darkorange", myRGB(255, 140, 0)}, + {"darkorchid", myRGB(139, 32, 139)}, + {"darksalmon", myRGB(233, 150, 122)}, + {"darkseagreen", myRGB(143, 188, 143)}, + {"darkslateblue", myRGB(56, 75, 102)}, + {"darkslategray", myRGB(47, 79, 79)}, + {"darkturquoise", myRGB(0, 166, 166)}, + {"darkviolet", myRGB(148, 0, 211)}, + {"deeppink", myRGB(255, 20, 147)}, + {"deepskyblue", myRGB(0, 191, 255)}, + {"dimgray", myRGB(84, 84, 84)}, + {"dodgerblue", myRGB(30, 144, 255)}, + {"firebrick", myRGB(142, 35, 35)}, + {"floralwhite", myRGB(255, 250, 240)}, + {"forestgreen", myRGB(80, 159, 105)}, + {"gainsboro", myRGB(220, 220, 220)}, + {"ghostwhite", myRGB(248, 248, 255)}, + {"gold", myRGB(218, 170, 0)}, + {"goldenrod", myRGB(239, 223, 132)}, + {"gray", myRGB(126, 126, 126)}, + {"gray0", myRGB(0, 0, 0)}, + {"gray1", myRGB(3, 3, 3)}, + {"gray10", myRGB(26, 26, 26)}, + {"gray100", myRGB(255, 255, 255)}, + {"gray11", myRGB(28, 28, 28)}, + {"gray12", myRGB(31, 31, 31)}, + {"gray13", myRGB(33, 33, 33)}, + {"gray14", myRGB(36, 36, 36)}, + {"gray15", myRGB(38, 38, 38)}, + {"gray16", myRGB(41, 41, 41)}, + {"gray17", myRGB(43, 43, 43)}, + {"gray18", myRGB(46, 46, 46)}, + {"gray19", myRGB(48, 48, 48)}, + {"gray2", myRGB(5, 5, 5)}, + {"gray20", myRGB(51, 51, 51)}, + {"gray21", myRGB(54, 54, 54)}, + {"gray22", myRGB(56, 56, 56)}, + {"gray23", myRGB(59, 59, 59)}, + {"gray24", myRGB(61, 61, 61)}, + {"gray25", myRGB(64, 64, 64)}, + {"gray26", myRGB(66, 66, 66)}, + {"gray27", myRGB(69, 69, 69)}, + {"gray28", myRGB(71, 71, 71)}, + {"gray29", myRGB(74, 74, 74)}, + {"gray3", myRGB(8, 8, 8)}, + {"gray30", myRGB(77, 77, 77)}, + {"gray31", myRGB(79, 79, 79)}, + {"gray32", myRGB(82, 82, 82)}, + {"gray33", myRGB(84, 84, 84)}, + {"gray34", myRGB(87, 87, 87)}, + {"gray35", myRGB(89, 89, 89)}, + {"gray36", myRGB(92, 92, 92)}, + {"gray37", myRGB(94, 94, 94)}, + {"gray38", myRGB(97, 97, 97)}, + {"gray39", myRGB(99, 99, 99)}, + {"gray4", myRGB(10, 10, 10)}, + {"gray40", myRGB(102, 102, 102)}, + {"gray41", myRGB(105, 105, 105)}, + {"gray42", myRGB(107, 107, 107)}, + {"gray43", myRGB(110, 110, 110)}, + {"gray44", myRGB(112, 112, 112)}, + {"gray45", myRGB(115, 115, 115)}, + {"gray46", myRGB(117, 117, 117)}, + {"gray47", myRGB(120, 120, 120)}, + {"gray48", myRGB(122, 122, 122)}, + {"gray49", myRGB(125, 125, 125)}, + {"gray5", myRGB(13, 13, 13)}, + {"gray50", myRGB(127, 127, 127)}, + {"gray51", myRGB(130, 130, 130)}, + {"gray52", myRGB(133, 133, 133)}, + {"gray53", myRGB(135, 135, 135)}, + {"gray54", myRGB(138, 138, 138)}, + {"gray55", myRGB(140, 140, 140)}, + {"gray56", myRGB(143, 143, 143)}, + {"gray57", myRGB(145, 145, 145)}, + {"gray58", myRGB(148, 148, 148)}, + {"gray59", myRGB(150, 150, 150)}, + {"gray6", myRGB(15, 15, 15)}, + {"gray60", myRGB(153, 153, 153)}, + {"gray61", myRGB(156, 156, 156)}, + {"gray62", myRGB(158, 158, 158)}, + {"gray63", myRGB(161, 161, 161)}, + {"gray64", myRGB(163, 163, 163)}, + {"gray65", myRGB(166, 166, 166)}, + {"gray66", myRGB(168, 168, 168)}, + {"gray67", myRGB(171, 171, 171)}, + {"gray68", myRGB(173, 173, 173)}, + {"gray69", myRGB(176, 176, 176)}, + {"gray7", myRGB(18, 18, 18)}, + {"gray70", myRGB(179, 179, 179)}, + {"gray71", myRGB(181, 181, 181)}, + {"gray72", myRGB(184, 184, 184)}, + {"gray73", myRGB(186, 186, 186)}, + {"gray74", myRGB(189, 189, 189)}, + {"gray75", myRGB(191, 191, 191)}, + {"gray76", myRGB(194, 194, 194)}, + {"gray77", myRGB(196, 196, 196)}, + {"gray78", myRGB(199, 199, 199)}, + {"gray79", myRGB(201, 201, 201)}, + {"gray8", myRGB(20, 20, 20)}, + {"gray80", myRGB(204, 204, 204)}, + {"gray81", myRGB(207, 207, 207)}, + {"gray82", myRGB(209, 209, 209)}, + {"gray83", myRGB(212, 212, 212)}, + {"gray84", myRGB(214, 214, 214)}, + {"gray85", myRGB(217, 217, 217)}, + {"gray86", myRGB(219, 219, 219)}, + {"gray87", myRGB(222, 222, 222)}, + {"gray88", myRGB(224, 224, 224)}, + {"gray89", myRGB(227, 227, 227)}, + {"gray9", myRGB(23, 23, 23)}, + {"gray90", myRGB(229, 229, 229)}, + {"gray91", myRGB(232, 232, 232)}, + {"gray92", myRGB(235, 235, 235)}, + {"gray93", myRGB(237, 237, 237)}, + {"gray94", myRGB(240, 240, 240)}, + {"gray95", myRGB(242, 242, 242)}, + {"gray96", myRGB(245, 245, 245)}, + {"gray97", myRGB(247, 247, 247)}, + {"gray98", myRGB(250, 250, 250)}, + {"gray99", myRGB(252, 252, 252)}, + {"green", myRGB(0, 255, 0)}, + {"greenyellow", myRGB(173, 255, 47)}, + {"honeydew", myRGB(240, 255, 240)}, + {"hotpink", myRGB(255, 105, 180)}, + {"indianred", myRGB(107, 57, 57)}, + {"ivory", myRGB(255, 255, 240)}, + {"khaki", myRGB(179, 179, 126)}, + {"lavender", myRGB(230, 230, 250)}, + {"lavenderblush", myRGB(255, 240, 245)}, + {"lawngreen", myRGB(124, 252, 0)}, + {"lemonchiffon", myRGB(255, 250, 205)}, + {"lightblue", myRGB(176, 226, 255)}, + {"lightcoral", myRGB(240, 128, 128)}, + {"lightcyan", myRGB(224, 255, 255)}, + {"lightgoldenrod", myRGB(238, 221, 130)}, + {"lightgoldenrodyellow", myRGB(250, 250, 210)}, + {"lightgray", myRGB(168, 168, 168)}, + {"lightpink", myRGB(255, 182, 193)}, + {"lightsalmon", myRGB(255, 160, 122)}, + {"lightseagreen", myRGB(32, 178, 170)}, + {"lightskyblue", myRGB(135, 206, 250)}, + {"lightslateblue", myRGB(132, 112, 255)}, + {"lightslategray", myRGB(119, 136, 153)}, + {"lightsteelblue", myRGB(124, 152, 211)}, + {"lightyellow", myRGB(255, 255, 224)}, + {"limegreen", myRGB(0, 175, 20)}, + {"linen", myRGB(250, 240, 230)}, + {"magenta", myRGB(255, 0, 255)}, + {"maroon", myRGB(143, 0, 82)}, + {"mediumaquamarine", myRGB(0, 147, 143)}, + {"mediumblue", myRGB(50, 50, 204)}, + {"mediumforestgreen", myRGB(50, 129, 75)}, + {"mediumgoldenrod", myRGB(209, 193, 102)}, + {"mediumorchid", myRGB(189, 82, 189)}, + {"mediumpurple", myRGB(147, 112, 219)}, + {"mediumseagreen", myRGB(52, 119, 102)}, + {"mediumslateblue", myRGB(106, 106, 141)}, + {"mediumspringgreen", myRGB(35, 142, 35)}, + {"mediumturquoise", myRGB(0, 210, 210)}, + {"mediumvioletred", myRGB(213, 32, 121)}, + {"midnightblue", myRGB(47, 47, 100)}, + {"mintcream", myRGB(245, 255, 250)}, + {"mistyrose", myRGB(255, 228, 225)}, + {"moccasin", myRGB(255, 228, 181)}, + {"navajowhite", myRGB(255, 222, 173)}, + {"navy", myRGB(35, 35, 117)}, + {"navyblue", myRGB(35, 35, 117)}, + {"oldlace", myRGB(253, 245, 230)}, + {"olivedrab", myRGB(107, 142, 35)}, + {"orange", myRGB(255, 135, 0)}, + {"orangered", myRGB(255, 69, 0)}, + {"orchid", myRGB(239, 132, 239)}, + {"palegoldenrod", myRGB(238, 232, 170)}, + {"palegreen", myRGB(115, 222, 120)}, + {"paleturquoise", myRGB(175, 238, 238)}, + {"palevioletred", myRGB(219, 112, 147)}, + {"papayawhip", myRGB(255, 239, 213)}, + {"peachpuff", myRGB(255, 218, 185)}, + {"peru", myRGB(205, 133, 63)}, + {"pink", myRGB(255, 181, 197)}, + {"plum", myRGB(197, 72, 155)}, + {"powderblue", myRGB(176, 224, 230)}, + {"purple", myRGB(160, 32, 240)}, + {"red", myRGB(255, 0, 0)}, + {"rosybrown", myRGB(188, 143, 143)}, + {"royalblue", myRGB(65, 105, 225)}, + {"saddlebrown", myRGB(139, 69, 19)}, + {"salmon", myRGB(233, 150, 122)}, + {"sandybrown", myRGB(244, 164, 96)}, + {"seagreen", myRGB(82, 149, 132)}, + {"seashell", myRGB(255, 245, 238)}, + {"sienna", myRGB(150, 82, 45)}, + {"silver", myRGB(192, 192, 192)}, + {"skyblue", myRGB(114, 159, 255)}, + {"slateblue", myRGB(126, 136, 171)}, + {"slategray", myRGB(112, 128, 144)}, + {"snow", myRGB(255, 250, 250)}, + {"springgreen", myRGB(65, 172, 65)}, + {"steelblue", myRGB(84, 112, 170)}, + {"tan", myRGB(222, 184, 135)}, + {"thistle", myRGB(216, 191, 216)}, + {"tomato", myRGB(255, 99, 71)}, + {"transparent", myRGB(0, 0, 1)}, + {"turquoise", myRGB(25, 204, 223)}, + {"violet", myRGB(156, 62, 206)}, + {"violetred", myRGB(243, 62, 150)}, + {"wheat", myRGB(245, 222, 179)}, + {"white", myRGB(255, 255, 255)}, + {"whitesmoke", myRGB(245, 245, 245)}, + {"yellow", myRGB(255, 255, 0)}, + {"yellowgreen", myRGB(50, 216, 56)}, + {NULL, myRGB(0, 0, 0)} +}; +static int numTheRGBRecords = 235; + +static unsigned char ParseHexadecimal(char digit1, char digit2) +{ + unsigned char i1, i2; + + if (digit1 >= 'a') + i1 = (unsigned char)(digit1 - 'a' + 0x0A); + else if (digit1 >= 'A') + i1 = (unsigned char)(digit1 - 'A' + 0x0A); + else + i1 = (unsigned char)(digit1 - '0'); + if (digit2 >= 'a') + i2 = (unsigned char)(digit2 - 'a' + 0x0A); + else if (digit2 >= 'A') + i2 = (unsigned char)(digit2 - 'A' + 0x0A); + else + i2 = (unsigned char)(digit2 - '0'); + return (unsigned char)(0x10 * i1 + i2); +} + +static bool GetRGBFromName(const char *inname, bool *isNone, + unsigned char *r, unsigned char*g, unsigned char *b) +{ + int left, right, middle; + int cmp; + wxUint32 rgbVal; + char *name; + char *grey, *p; + + // Neither #rrggbb nor #rrrrggggbbbb are in database, we parse them directly + size_t inname_len = strlen(inname); + if ( *inname == '#' && (inname_len == 7 || inname_len == 13)) + { + size_t ofs = (inname_len == 7) ? 2 : 4; + *r = ParseHexadecimal(inname[1], inname[2]); + *g = ParseHexadecimal(inname[1*ofs+1], inname[1*ofs+2]); + *b = ParseHexadecimal(inname[2*ofs+1], inname[2*ofs+2]); + *isNone = false; + return true; + } + + name = wxStrdupA(inname); + + // theRGBRecords[] has no names with spaces, and no grey, but a + // lot of gray... + + // so first extract ' ' + while ((p = strchr(name, ' ')) != NULL) + { + while (*(p)) // till eof of string + { + *p = *(p + 1); // copy to the left + p++; + } + } + // fold to lower case + p = name; + while (*p) + { + *p = (char)tolower(*p); + p++; + } + + // substitute Grey with Gray, else rgbtab.h would have more than 100 + // 'duplicate' entries + if ( (grey = strstr(name, "grey")) != NULL ) + grey[2] = 'a'; + + // check for special 'none' colour: + bool found; + if ( strcmp(name, "none") == 0 ) + { + *isNone = true; + found = true; + } + else // not "None" + { + found = false; + + // binary search: + left = 0; + right = numTheRGBRecords - 1; + do + { + middle = (left + right) / 2; + cmp = strcmp(name, theRGBRecords[middle].name); + if ( cmp == 0 ) + { + rgbVal = theRGBRecords[middle].rgb; + *r = (unsigned char)((rgbVal >> 16) & 0xFF); + *g = (unsigned char)((rgbVal >> 8) & 0xFF); + *b = (unsigned char)((rgbVal) & 0xFF); + *isNone = false; + found = true; + break; + } + else if ( cmp < 0 ) + { + right = middle - 1; + } + else // cmp > 0 + { + left = middle + 1; + } + } while (left <= right); + } + + free(name); + + return found; +} + +static const char *ParseColor(const char *data) +{ + static const char *targets[] = + {"c ", "g ", "g4 ", "m ", "b ", "s ", NULL}; + + const char *p, *r; + const char *q; + int i; + + for (i = 0; targets[i] != NULL; i++) + { + r = data; + for (q = targets[i]; *r != '\0'; r++) + { + if ( *r != *q ) + continue; + if ( !isspace((int) (*(r - 1))) ) + continue; + p = r; + for (;;) + { + if ( *q == '\0' ) + return p; + if ( *p++ != *q++ ) + break; + } + q = targets[i]; + } + } + return NULL; +} + +struct wxXPMColourMapData +{ + wxXPMColourMapData() { R = G = B = 0; } + unsigned char R,G,B; +}; +WX_DECLARE_STRING_HASH_MAP(wxXPMColourMapData, wxXPMColourMap); + +wxImage wxXPMDecoder::ReadData(const char* const* xpm_data) +{ + wxCHECK_MSG(xpm_data, wxNullImage, wxT("NULL XPM data") ); + + wxImage img; + int count; + unsigned width, height, colors_cnt, chars_per_pixel; + size_t i, j, i_key; + wxChar key[64]; + const char *clr_def; + bool hasMask; + wxXPMColourMap clr_tbl; + wxXPMColourMap::iterator it; + wxString maskKey; + + /* + * Read hints and initialize structures: + */ + + count = sscanf(xpm_data[0], "%u %u %u %u", + &width, &height, &colors_cnt, &chars_per_pixel); + if ( count != 4 || width * height * colors_cnt == 0 ) + { + wxLogError(_("XPM: incorrect header format!")); + return wxNullImage; + } + + // VS: XPM color map this large would be insane, since XPMs are encoded with + // 92 possible values on each position, 92^64 is *way* larger space than + // 8bit RGB... + wxCHECK_MSG(chars_per_pixel < 64, wxNullImage, wxT("XPM colormaps this large not supported.")); + + if ( !img.Create(width, height) ) + return wxNullImage; + + img.SetMask(false); + key[chars_per_pixel] = wxT('\0'); + hasMask = false; + + /* + * Create colour map: + */ + wxXPMColourMapData clr_data; + for (i = 0; i < colors_cnt; i++) + { + const char *xmpColLine = xpm_data[1 + i]; + + // we must have at least " x y" after the colour index, hence +5 + if ( !xmpColLine || strlen(xmpColLine) < chars_per_pixel + 5 ) + { + wxLogError(_("XPM: incorrect colour description in line %d"), + (int)(1 + i)); + return wxNullImage; + } + + for (i_key = 0; i_key < chars_per_pixel; i_key++) + key[i_key] = (wxChar)xmpColLine[i_key]; + clr_def = ParseColor(xmpColLine + chars_per_pixel); + + if ( clr_def == NULL ) + { + wxLogError(_("XPM: malformed colour definition '%s' at line %d!"), + xmpColLine, (int)(1 + i)); + return wxNullImage; + } + + bool isNone = false; + if ( !GetRGBFromName(clr_def, &isNone, + &clr_data.R, &clr_data.G, &clr_data.B) ) + { + wxLogError(_("XPM: malformed colour definition '%s' at line %d!"), + xmpColLine, (int)(1 + i)); + return wxNullImage; + } + + if ( isNone ) + { + img.SetMask(true); + img.SetMaskColour(255, 0, 255); + clr_data.R = + clr_data.B = 255; + clr_data.G = 0; + hasMask = true; + maskKey = key; + } + + clr_tbl[key] = clr_data; + } + + /* + * Modify colour entries with RGB = (255,0,255) to (255,0,254) if + * mask colour is present (so that existing pixels with (255,0,255) + * magenta colour are not incorrectly made transparent): + */ + if (hasMask) + { + for (it = clr_tbl.begin(); it != clr_tbl.end(); ++it) + { + if (it->second.R == 255 && it->second.G == 0 && + it->second.B == 255 && + it->first != maskKey) + { + it->second.B = 254; + } + } + } + + /* + * Parse image data: + */ + + unsigned char *img_data = img.GetData(); + wxXPMColourMap::iterator entry; + wxXPMColourMap::iterator end = clr_tbl.end(); + + for (j = 0; j < height; j++) + { + for (i = 0; i < width; i++, img_data += 3) + { + const char *xpmImgLine = xpm_data[1 + colors_cnt + j]; + if ( !xpmImgLine || strlen(xpmImgLine) < width*chars_per_pixel ) + { + wxLogError(_("XPM: truncated image data at line %d!"), + (int)(1 + colors_cnt + j)); + return wxNullImage; + } + + for (i_key = 0; i_key < chars_per_pixel; i_key++) + { + key[i_key] = (wxChar)xpmImgLine[chars_per_pixel * i + i_key]; + } + + entry = clr_tbl.find(key); + if ( entry == end ) + { + wxLogError(_("XPM: Malformed pixel data!")); + + // better return right now as otherwise we risk to flood the + // user with error messages as something seems to be seriously + // wrong with the file and so we could give this message for + // each remaining pixel if we don't bail out + return wxNullImage; + } + else + { + img_data[0] = entry->second.R; + img_data[1] = entry->second.G; + img_data[2] = entry->second.B; + } + } + } + +#if wxUSE_PALETTE + unsigned char* r = new unsigned char[colors_cnt]; + unsigned char* g = new unsigned char[colors_cnt]; + unsigned char* b = new unsigned char[colors_cnt]; + + for (it = clr_tbl.begin(), i = 0; it != clr_tbl.end(); it++, i++) + { + r[i] = it->second.R; + g[i] = it->second.G; + b[i] = it->second.B; + } + wxASSERT(i == colors_cnt); + img.SetPalette(wxPalette(colors_cnt, r, g, b)); + delete[] r; + delete[] g; + delete[] b; +#endif // wxUSE_PALETTE + + return img; +} + +#endif // wxUSE_IMAGE && wxUSE_XPM diff --git a/Source/3rd Party/wx/src/common/xti.cpp b/Source/3rd Party/wx/src/common/xti.cpp index adbbd07bf..9542896f7 100644 --- a/Source/3rd Party/wx/src/common/xti.cpp +++ b/Source/3rd Party/wx/src/common/xti.cpp @@ -1,767 +1,767 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/xti.cpp -// Purpose: runtime metadata information (extended class info -// Author: Stefan Csomor -// Modified by: -// Created: 27/07/03 -// RCS-ID: $Id: xti.cpp 38857 2006-04-20 07:31:44Z ABX $ -// Copyright: (c) 1997 Julian Smart -// (c) 2003 Stefan Csomor -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_EXTENDED_RTTI - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/list.h" - #include "wx/hash.h" -#endif - -#include "wx/xti.h" -#include "wx/xml/xml.h" -#include "wx/tokenzr.h" -#include - -#include "wx/beforestd.h" -#include -#include -#include -#include "wx/afterstd.h" - -using namespace std ; - -// ---------------------------------------------------------------------------- -// Enum Support -// ---------------------------------------------------------------------------- - -wxEnumData::wxEnumData( wxEnumMemberData* data ) -{ - m_members = data ; - for ( m_count = 0; m_members[m_count].m_name ; m_count++) - {} ; -} - -bool wxEnumData::HasEnumMemberValue(const wxChar *name, int *value) const -{ - int i; - for (i = 0; m_members[i].m_name ; i++ ) - { - if (!wxStrcmp(name, m_members[i].m_name)) - { - if ( value ) - *value = m_members[i].m_value; - return true ; - } - } - return false ; -} - -int wxEnumData::GetEnumMemberValue(const wxChar *name) const -{ - int i; - for (i = 0; m_members[i].m_name ; i++ ) - { - if (!wxStrcmp(name, m_members[i].m_name)) - { - return m_members[i].m_value; - } - } - return 0 ; -} - -const wxChar *wxEnumData::GetEnumMemberName(int value) const -{ - int i; - for (i = 0; m_members[i].m_name ; i++) - if (value == m_members[i].m_value) - return m_members[i].m_name; - - return wxEmptyString ; -} - -int wxEnumData::GetEnumMemberValueByIndex( int idx ) const -{ - // we should cache the count in order to avoid out-of-bounds errors - return m_members[idx].m_value ; -} - -const wxChar * wxEnumData::GetEnumMemberNameByIndex( int idx ) const -{ - // we should cache the count in order to avoid out-of-bounds errors - return m_members[idx].m_name ; -} - -// ---------------------------------------------------------------------------- -// Type Information -// ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- -// value streaming -// ---------------------------------------------------------------------------- - -// streamer specializations -// for all built-in types - -// bool - -template<> void wxStringReadValue(const wxString &s , bool &data ) -{ - int intdata ; - wxSscanf(s, _T("%d"), &intdata ) ; - data = (bool)intdata ; -} - -template<> void wxStringWriteValue(wxString &s , const bool &data ) -{ - s = wxString::Format(_T("%d"), data ) ; -} - -// char - -template<> void wxStringReadValue(const wxString &s , char &data ) -{ - int intdata ; - wxSscanf(s, _T("%d"), &intdata ) ; - data = char(intdata) ; -} - -template<> void wxStringWriteValue(wxString &s , const char &data ) -{ - s = wxString::Format(_T("%d"), data ) ; -} - -// unsigned char - -template<> void wxStringReadValue(const wxString &s , unsigned char &data ) -{ - int intdata ; - wxSscanf(s, _T("%d"), &intdata ) ; - data = (unsigned char)(intdata) ; -} - -template<> void wxStringWriteValue(wxString &s , const unsigned char &data ) -{ - s = wxString::Format(_T("%d"), data ) ; -} - -// int - -template<> void wxStringReadValue(const wxString &s , int &data ) -{ - wxSscanf(s, _T("%d"), &data ) ; -} - -template<> void wxStringWriteValue(wxString &s , const int &data ) -{ - s = wxString::Format(_T("%d"), data ) ; -} - -// unsigned int - -template<> void wxStringReadValue(const wxString &s , unsigned int &data ) -{ - wxSscanf(s, _T("%d"), &data ) ; -} - -template<> void wxStringWriteValue(wxString &s , const unsigned int &data ) -{ - s = wxString::Format(_T("%d"), data ) ; -} - -// long - -template<> void wxStringReadValue(const wxString &s , long &data ) -{ - wxSscanf(s, _T("%ld"), &data ) ; -} - -template<> void wxStringWriteValue(wxString &s , const long &data ) -{ - s = wxString::Format(_T("%ld"), data ) ; -} - -// unsigned long - -template<> void wxStringReadValue(const wxString &s , unsigned long &data ) -{ - wxSscanf(s, _T("%ld"), &data ) ; -} - -template<> void wxStringWriteValue(wxString &s , const unsigned long &data ) -{ - s = wxString::Format(_T("%ld"), data ) ; -} - -// float - -template<> void wxStringReadValue(const wxString &s , float &data ) -{ - wxSscanf(s, _T("%f"), &data ) ; -} - -template<> void wxStringWriteValue(wxString &s , const float &data ) -{ - s = wxString::Format(_T("%f"), data ) ; -} - -// double - -template<> void wxStringReadValue(const wxString &s , double &data ) -{ - wxSscanf(s, _T("%lf"), &data ) ; -} - -template<> void wxStringWriteValue(wxString &s , const double &data ) -{ - s = wxString::Format(_T("%lf"), data ) ; -} - -// wxString - -template<> void wxStringReadValue(const wxString &s , wxString &data ) -{ - data = s ; -} - -template<> void wxStringWriteValue(wxString &s , const wxString &data ) -{ - s = data ; -} - -// built-ins -// - -#if wxUSE_FUNC_TEMPLATE_POINTER -#define wxBUILTIN_TYPE_INFO( element , type ) \ - wxBuiltInTypeInfo s_typeInfo##type(element , &wxToStringConverter , &wxFromStringConverter , typeid(type).name()) ; -#else -#define wxBUILTIN_TYPE_INFO( element , type ) \ - void _toString##element( const wxxVariant& data , wxString &result ) { wxToStringConverter(data, result); } \ - void _fromString##element( const wxString& data , wxxVariant &result ) { wxFromStringConverter(data, result); } \ - wxBuiltInTypeInfo s_typeInfo##type(element , &_toString##element , &_fromString##element , typeid(type).name()) ; -#endif - -typedef unsigned char unsigned_char; -typedef unsigned int unsigned_int; -typedef unsigned long unsigned_long; - -wxBuiltInTypeInfo s_typeInfovoid( wxT_VOID , NULL , NULL , typeid(void).name()); -wxBUILTIN_TYPE_INFO( wxT_BOOL , bool); -wxBUILTIN_TYPE_INFO( wxT_CHAR , char); -wxBUILTIN_TYPE_INFO( wxT_UCHAR , unsigned_char); -wxBUILTIN_TYPE_INFO( wxT_INT , int); -wxBUILTIN_TYPE_INFO( wxT_UINT , unsigned_int); -wxBUILTIN_TYPE_INFO( wxT_LONG , long); -wxBUILTIN_TYPE_INFO( wxT_ULONG , unsigned_long); -wxBUILTIN_TYPE_INFO( wxT_FLOAT , float); -wxBUILTIN_TYPE_INFO( wxT_DOUBLE , double); -wxBUILTIN_TYPE_INFO( wxT_STRING , wxString); - - -// this are compiler induced specialization which are never used anywhere - -wxILLEGAL_TYPE_SPECIALIZATION( char const * ) -wxILLEGAL_TYPE_SPECIALIZATION( char * ) -wxILLEGAL_TYPE_SPECIALIZATION( unsigned char * ) -wxILLEGAL_TYPE_SPECIALIZATION( int * ) -wxILLEGAL_TYPE_SPECIALIZATION( bool * ) -wxILLEGAL_TYPE_SPECIALIZATION( long * ) -wxILLEGAL_TYPE_SPECIALIZATION( wxString * ) - -wxCOLLECTION_TYPE_INFO( wxString , wxArrayString ) ; - -template<> void wxCollectionToVariantArray( wxArrayString const &theArray, wxxVariantArray &value) -{ - wxArrayCollectionToVariantArray( theArray , value ) ; -} - -wxTypeInfoMap *wxTypeInfo::ms_typeTable = NULL ; - -wxTypeInfo *wxTypeInfo::FindType(const wxChar *typeName) -{ - wxTypeInfoMap::iterator iter = ms_typeTable->find(typeName) ; - wxASSERT_MSG( iter != ms_typeTable->end() , wxT("lookup for a non-existent type-info") ) ; - return (wxTypeInfo *)iter->second; -} - -#if wxUSE_UNICODE -wxClassTypeInfo::wxClassTypeInfo( wxTypeKind kind , wxClassInfo* classInfo , converterToString_t to , converterFromString_t from , const char *name) : -wxTypeInfo( kind , to , from , name) -{ wxASSERT_MSG( kind == wxT_OBJECT_PTR || kind == wxT_OBJECT , wxT("Illegal Kind for Enum Type")) ; m_classInfo = classInfo ;} -#endif - -wxClassTypeInfo::wxClassTypeInfo( wxTypeKind kind , wxClassInfo* classInfo , converterToString_t to , converterFromString_t from , const wxString &name) : -wxTypeInfo( kind , to , from , name) -{ wxASSERT_MSG( kind == wxT_OBJECT_PTR || kind == wxT_OBJECT , wxT("Illegal Kind for Enum Type")) ; m_classInfo = classInfo ;} - -wxDelegateTypeInfo::wxDelegateTypeInfo( int eventType , wxClassInfo* eventClass , converterToString_t to , converterFromString_t from ) : -wxTypeInfo ( wxT_DELEGATE , to , from , wxEmptyString ) -{ m_eventClass = eventClass ; m_eventType = eventType ; m_lastEventType = -1 ;} - -wxDelegateTypeInfo::wxDelegateTypeInfo( int eventType , int lastEventType , wxClassInfo* eventClass , converterToString_t to , converterFromString_t from ) : -wxTypeInfo ( wxT_DELEGATE , to , from , wxEmptyString ) -{ m_eventClass = eventClass ; m_eventType = eventType ; m_lastEventType = lastEventType; } - -void wxTypeInfo::Register() -{ - if ( ms_typeTable == NULL ) - ms_typeTable = new wxTypeInfoMap() ; - - if( !m_name.empty() ) - (*ms_typeTable)[m_name] = this ; -} - -void wxTypeInfo::Unregister() -{ - if( !m_name.empty() ) - ms_typeTable->erase(m_name); -} - -// removing header dependancy on string tokenizer - -void wxSetStringToArray( const wxString &s , wxArrayString &array ) -{ - wxStringTokenizer tokenizer(s, wxT("| \t\n"), wxTOKEN_STRTOK); - wxString flag; - array.Clear() ; - while (tokenizer.HasMoreTokens()) - { - array.Add(tokenizer.GetNextToken()) ; - } -} - -// ---------------------------------------------------------------------------- -// wxClassInfo -// ---------------------------------------------------------------------------- - -wxPropertyInfo::~wxPropertyInfo() -{ - if ( this == m_itsClass->m_firstProperty ) - { - m_itsClass->m_firstProperty = m_next; - } - else - { - wxPropertyInfo *info = m_itsClass->m_firstProperty; - while (info) - { - if ( info->m_next == this ) - { - info->m_next = m_next; - break; - } - - info = info->m_next; - } - } -} - -wxHandlerInfo::~wxHandlerInfo() -{ - if ( this == m_itsClass->m_firstHandler ) - { - m_itsClass->m_firstHandler = m_next; - } - else - { - wxHandlerInfo *info = m_itsClass->m_firstHandler; - while (info) - { - if ( info->m_next == this ) - { - info->m_next = m_next; - break; - } - - info = info->m_next; - } - } -} - -const wxPropertyAccessor *wxClassInfo::FindAccessor(const wxChar *PropertyName) const -{ - const wxPropertyInfo* info = FindPropertyInfo( PropertyName ) ; - - if ( info ) - return info->GetAccessor() ; - - return NULL ; -} - -wxPropertyInfo *wxClassInfo::FindPropertyInfoInThisClass (const wxChar *PropertyName) const -{ - wxPropertyInfo* info = m_firstProperty ; - - while( info ) - { - if ( wxStrcmp( info->GetName() , PropertyName ) == 0 ) - return info ; - info = info->GetNext() ; - } - - return 0; -} - -const wxPropertyInfo *wxClassInfo::FindPropertyInfo (const wxChar *PropertyName) const -{ - const wxPropertyInfo* info = FindPropertyInfoInThisClass( PropertyName ) ; - if ( info ) - return info ; - - const wxClassInfo** parents = GetParents() ; - for ( int i = 0 ; parents[i] ; ++ i ) - { - if ( ( info = parents[i]->FindPropertyInfo( PropertyName ) ) != NULL ) - return info ; - } - - return 0; -} - -wxHandlerInfo *wxClassInfo::FindHandlerInfoInThisClass (const wxChar *PropertyName) const -{ - wxHandlerInfo* info = m_firstHandler ; - - while( info ) - { - if ( wxStrcmp( info->GetName() , PropertyName ) == 0 ) - return info ; - info = info->GetNext() ; - } - - return 0; -} - -const wxHandlerInfo *wxClassInfo::FindHandlerInfo (const wxChar *PropertyName) const -{ - const wxHandlerInfo* info = FindHandlerInfoInThisClass( PropertyName ) ; - - if ( info ) - return info ; - - const wxClassInfo** parents = GetParents() ; - for ( int i = 0 ; parents[i] ; ++ i ) - { - if ( ( info = parents[i]->FindHandlerInfo( PropertyName ) ) != NULL ) - return info ; - } - - return 0; -} - -wxObjectStreamingCallback wxClassInfo::GetStreamingCallback() const -{ - if ( m_streamingCallback ) - return m_streamingCallback ; - - wxObjectStreamingCallback retval = NULL ; - const wxClassInfo** parents = GetParents() ; - for ( int i = 0 ; parents[i] && retval == NULL ; ++ i ) - { - retval = parents[i]->GetStreamingCallback() ; - } - return retval ; -} - -bool wxClassInfo::BeforeWriteObject( const wxObject *obj, wxWriter *streamer , wxPersister *persister , wxxVariantArray &metadata) const -{ - wxObjectStreamingCallback sb = GetStreamingCallback() ; - if ( sb ) - return (*sb)(obj , streamer , persister , metadata ) ; - - return true ; -} - -void wxClassInfo::SetProperty(wxObject *object, const wxChar *propertyName, const wxxVariant &value) const -{ - const wxPropertyAccessor *accessor; - - accessor = FindAccessor(propertyName); - wxASSERT(accessor->HasSetter()); - accessor->SetProperty( object , value ) ; -} - -wxxVariant wxClassInfo::GetProperty(wxObject *object, const wxChar *propertyName) const -{ - const wxPropertyAccessor *accessor; - - accessor = FindAccessor(propertyName); - wxASSERT(accessor->HasGetter()); - wxxVariant result ; - accessor->GetProperty(object,result); - return result ; -} - -wxxVariantArray wxClassInfo::GetPropertyCollection(wxObject *object, const wxChar *propertyName) const -{ - const wxPropertyAccessor *accessor; - - accessor = FindAccessor(propertyName); - wxASSERT(accessor->HasGetter()); - wxxVariantArray result ; - accessor->GetPropertyCollection(object,result); - return result ; -} - -void wxClassInfo::AddToPropertyCollection(wxObject *object, const wxChar *propertyName , const wxxVariant& value) const -{ - const wxPropertyAccessor *accessor; - - accessor = FindAccessor(propertyName); - wxASSERT(accessor->HasAdder()); - accessor->AddToPropertyCollection( object , value ) ; -} - -// void wxClassInfo::GetProperties( wxPropertyInfoMap &map ) const -// The map parameter (the name map that is) seems something special -// to MSVC and so we use a other name. -void wxClassInfo::GetProperties( wxPropertyInfoMap &infomap ) const -{ - const wxPropertyInfo *pi = GetFirstProperty() ; - while( pi ) - { - if ( infomap.find( pi->GetName() ) == infomap.end() ) - infomap[pi->GetName()] = (wxPropertyInfo*) pi ; - - pi = pi->GetNext() ; - } - - const wxClassInfo** parents = GetParents() ; - for ( int i = 0 ; parents[i] ; ++ i ) - { - parents[i]->GetProperties( infomap ) ; - } -} - -/* -VARIANT TO OBJECT -*/ - -wxObject* wxxVariant::GetAsObject() -{ - const wxClassTypeInfo *ti = dynamic_cast( m_data->GetTypeInfo() ) ; - if ( ti ) - return ti->GetClassInfo()->VariantToInstance(*this) ; - else - return NULL ; -} - -// ---------------------------------------------------------------------------- -// wxDynamicObject support -// ---------------------------------------------------------------------------- -// -// Dynamic Objects are objects that have a real superclass instance and carry their -// own attributes in a hash map. Like this it is possible to create the objects and -// stream them, as if their class information was already available from compiled data - -struct wxDynamicObject::wxDynamicObjectInternal -{ - wxDynamicObjectInternal() {} - -#if wxUSE_UNICODE - map m_properties ; -#else - map m_properties ; -#endif -} ; - -typedef list< wxDynamicObject* > wxDynamicObjectList ; - -struct wxDynamicClassInfo::wxDynamicClassInfoInternal -{ - wxDynamicObjectList m_dynamicObjects ; -} ; - -// instantiates this object with an instance of its superclass -wxDynamicObject::wxDynamicObject(wxObject* superClassInstance, const wxDynamicClassInfo *info) -{ - m_superClassInstance = superClassInstance ; - m_classInfo = info ; - m_data = new wxDynamicObjectInternal ; -} - -wxDynamicObject::~wxDynamicObject() -{ - dynamic_cast(m_classInfo)->m_data->m_dynamicObjects.remove( this ) ; - delete m_data ; - delete m_superClassInstance ; -} - -void wxDynamicObject::SetProperty (const wxChar *propertyName, const wxxVariant &value) -{ - wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(propertyName),wxT("Accessing Unknown Property in a Dynamic Object") ) ; - m_data->m_properties[propertyName] = value ; -} - -wxxVariant wxDynamicObject::GetProperty (const wxChar *propertyName) const -{ - wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(propertyName),wxT("Accessing Unknown Property in a Dynamic Object") ) ; - return m_data->m_properties[propertyName] ; -} - -void wxDynamicObject::RemoveProperty( const wxChar *propertyName ) -{ - wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(propertyName),wxT("Removing Unknown Property in a Dynamic Object") ) ; - m_data->m_properties.erase( propertyName ) ; -} - -void wxDynamicObject::RenameProperty( const wxChar *oldPropertyName , const wxChar *newPropertyName ) -{ - wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(oldPropertyName),wxT("Renaming Unknown Property in a Dynamic Object") ) ; - wxxVariant value = m_data->m_properties[oldPropertyName] ; - m_data->m_properties.erase( oldPropertyName ) ; - m_data->m_properties[newPropertyName] = value ; -} - - -// ---------------------------------------------------------------------------- -// wxDynamiClassInfo -// ---------------------------------------------------------------------------- - -wxDynamicClassInfo::wxDynamicClassInfo( const wxChar *unitName, const wxChar *className , const wxClassInfo* superClass ) : -wxClassInfo( unitName, className , new const wxClassInfo*[2]) -{ - GetParents()[0] = superClass ; - GetParents()[1] = NULL ; - m_data = new wxDynamicClassInfoInternal ; -} - -wxDynamicClassInfo::~wxDynamicClassInfo() -{ - delete[] GetParents() ; - delete m_data ; -} - -wxObject *wxDynamicClassInfo::AllocateObject() const -{ - wxObject* parent = GetParents()[0]->AllocateObject() ; - wxDynamicObject *obj = new wxDynamicObject( parent , this ) ; - m_data->m_dynamicObjects.push_back( obj ) ; - return obj ; -} - -void wxDynamicClassInfo::Create (wxObject *object, int paramCount, wxxVariant *params) const -{ - wxDynamicObject *dynobj = dynamic_cast< wxDynamicObject *>( object ) ; - wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::Create on an object other than wxDynamicObject") ) ; - GetParents()[0]->Create( dynobj->GetSuperClassInstance() , paramCount , params ) ; -} - -// get number of parameters for constructor -int wxDynamicClassInfo::GetCreateParamCount() const -{ - return GetParents()[0]->GetCreateParamCount() ; -} - -// get i-th constructor parameter -const wxChar* wxDynamicClassInfo::GetCreateParamName(int i) const -{ - return GetParents()[0]->GetCreateParamName( i ) ; -} - -void wxDynamicClassInfo::SetProperty(wxObject *object, const wxChar *propertyName, const wxxVariant &value) const -{ - wxDynamicObject* dynobj = dynamic_cast< wxDynamicObject * >( object ) ; - wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; - if ( FindPropertyInfoInThisClass(propertyName) ) - dynobj->SetProperty( propertyName , value ) ; - else - GetParents()[0]->SetProperty( dynobj->GetSuperClassInstance() , propertyName , value ) ; -} - -wxxVariant wxDynamicClassInfo::GetProperty(wxObject *object, const wxChar *propertyName) const -{ - wxDynamicObject* dynobj = dynamic_cast< wxDynamicObject * >( object ) ; - wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; - if ( FindPropertyInfoInThisClass(propertyName) ) - return dynobj->GetProperty( propertyName ) ; - else - return GetParents()[0]->GetProperty( dynobj->GetSuperClassInstance() , propertyName ) ; -} - -void wxDynamicClassInfo::AddProperty( const wxChar *propertyName , const wxTypeInfo* typeInfo ) -{ - new wxPropertyInfo( m_firstProperty , this , propertyName , typeInfo->GetTypeName() , new wxGenericPropertyAccessor( propertyName ) , wxxVariant() ) ; -} - -void wxDynamicClassInfo::AddHandler( const wxChar *handlerName , wxObjectEventFunction address , const wxClassInfo* eventClassInfo ) -{ - new wxHandlerInfo( m_firstHandler , this , handlerName , address , eventClassInfo ) ; -} - -// removes an existing runtime-property -void wxDynamicClassInfo::RemoveProperty( const wxChar *propertyName ) -{ - for ( wxDynamicObjectList::iterator iter = m_data->m_dynamicObjects.begin() ; iter != m_data->m_dynamicObjects.end() ; ++iter ) - (*iter)->RemoveProperty( propertyName ) ; - delete FindPropertyInfoInThisClass(propertyName) ; -} - -// removes an existing runtime-handler -void wxDynamicClassInfo::RemoveHandler( const wxChar *handlerName ) -{ - delete FindHandlerInfoInThisClass(handlerName) ; -} - -// renames an existing runtime-property -void wxDynamicClassInfo::RenameProperty( const wxChar *oldPropertyName , const wxChar *newPropertyName ) -{ - wxPropertyInfo* pi = FindPropertyInfoInThisClass(oldPropertyName) ; - wxASSERT_MSG( pi ,wxT("not existing property") ) ; - pi->m_name = newPropertyName ; - dynamic_cast(pi->GetAccessor())->RenameProperty( oldPropertyName , newPropertyName ) ; - for ( wxDynamicObjectList::iterator iter = m_data->m_dynamicObjects.begin() ; iter != m_data->m_dynamicObjects.end() ; ++iter ) - (*iter)->RenameProperty( oldPropertyName , newPropertyName ) ; -} - -// renames an existing runtime-handler -void wxDynamicClassInfo::RenameHandler( const wxChar *oldHandlerName , const wxChar *newHandlerName ) -{ - wxASSERT_MSG(FindHandlerInfoInThisClass(oldHandlerName),wxT("not existing handler") ) ; - FindHandlerInfoInThisClass(oldHandlerName)->m_name = newHandlerName ; -} - -// ---------------------------------------------------------------------------- -// wxGenericPropertyAccessor -// ---------------------------------------------------------------------------- - -struct wxGenericPropertyAccessor::wxGenericPropertyAccessorInternal -{ - char filler ; -} ; - -wxGenericPropertyAccessor::wxGenericPropertyAccessor( const wxString& propertyName ) -: wxPropertyAccessor( NULL , NULL , NULL , NULL ) -{ - m_data = new wxGenericPropertyAccessorInternal ; - m_propertyName = propertyName ; - m_getterName = wxT("Get")+propertyName ; - m_setterName = wxT("Set")+propertyName ; -} - -wxGenericPropertyAccessor::~wxGenericPropertyAccessor() -{ - delete m_data ; -} -void wxGenericPropertyAccessor::SetProperty(wxObject *object, const wxxVariant &value) const -{ - wxDynamicObject* dynobj = dynamic_cast< wxDynamicObject * >( object ) ; - wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; - dynobj->SetProperty(m_propertyName , value ) ; -} - -void wxGenericPropertyAccessor::GetProperty(const wxObject *object, wxxVariant& value) const -{ - const wxDynamicObject* dynobj = dynamic_cast< const wxDynamicObject * >( object ) ; - wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; - value = dynobj->GetProperty( m_propertyName ) ; -} - -#endif // wxUSE_EXTENDED_RTTI +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/xti.cpp +// Purpose: runtime metadata information (extended class info +// Author: Stefan Csomor +// Modified by: +// Created: 27/07/03 +// RCS-ID: $Id: xti.cpp 38857 2006-04-20 07:31:44Z ABX $ +// Copyright: (c) 1997 Julian Smart +// (c) 2003 Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_EXTENDED_RTTI + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/list.h" + #include "wx/hash.h" +#endif + +#include "wx/xti.h" +#include "wx/xml/xml.h" +#include "wx/tokenzr.h" +#include + +#include "wx/beforestd.h" +#include +#include +#include +#include "wx/afterstd.h" + +using namespace std ; + +// ---------------------------------------------------------------------------- +// Enum Support +// ---------------------------------------------------------------------------- + +wxEnumData::wxEnumData( wxEnumMemberData* data ) +{ + m_members = data ; + for ( m_count = 0; m_members[m_count].m_name ; m_count++) + {} ; +} + +bool wxEnumData::HasEnumMemberValue(const wxChar *name, int *value) const +{ + int i; + for (i = 0; m_members[i].m_name ; i++ ) + { + if (!wxStrcmp(name, m_members[i].m_name)) + { + if ( value ) + *value = m_members[i].m_value; + return true ; + } + } + return false ; +} + +int wxEnumData::GetEnumMemberValue(const wxChar *name) const +{ + int i; + for (i = 0; m_members[i].m_name ; i++ ) + { + if (!wxStrcmp(name, m_members[i].m_name)) + { + return m_members[i].m_value; + } + } + return 0 ; +} + +const wxChar *wxEnumData::GetEnumMemberName(int value) const +{ + int i; + for (i = 0; m_members[i].m_name ; i++) + if (value == m_members[i].m_value) + return m_members[i].m_name; + + return wxEmptyString ; +} + +int wxEnumData::GetEnumMemberValueByIndex( int idx ) const +{ + // we should cache the count in order to avoid out-of-bounds errors + return m_members[idx].m_value ; +} + +const wxChar * wxEnumData::GetEnumMemberNameByIndex( int idx ) const +{ + // we should cache the count in order to avoid out-of-bounds errors + return m_members[idx].m_name ; +} + +// ---------------------------------------------------------------------------- +// Type Information +// ---------------------------------------------------------------------------- +// ---------------------------------------------------------------------------- +// value streaming +// ---------------------------------------------------------------------------- + +// streamer specializations +// for all built-in types + +// bool + +template<> void wxStringReadValue(const wxString &s , bool &data ) +{ + int intdata ; + wxSscanf(s, _T("%d"), &intdata ) ; + data = (bool)intdata ; +} + +template<> void wxStringWriteValue(wxString &s , const bool &data ) +{ + s = wxString::Format(_T("%d"), data ) ; +} + +// char + +template<> void wxStringReadValue(const wxString &s , char &data ) +{ + int intdata ; + wxSscanf(s, _T("%d"), &intdata ) ; + data = char(intdata) ; +} + +template<> void wxStringWriteValue(wxString &s , const char &data ) +{ + s = wxString::Format(_T("%d"), data ) ; +} + +// unsigned char + +template<> void wxStringReadValue(const wxString &s , unsigned char &data ) +{ + int intdata ; + wxSscanf(s, _T("%d"), &intdata ) ; + data = (unsigned char)(intdata) ; +} + +template<> void wxStringWriteValue(wxString &s , const unsigned char &data ) +{ + s = wxString::Format(_T("%d"), data ) ; +} + +// int + +template<> void wxStringReadValue(const wxString &s , int &data ) +{ + wxSscanf(s, _T("%d"), &data ) ; +} + +template<> void wxStringWriteValue(wxString &s , const int &data ) +{ + s = wxString::Format(_T("%d"), data ) ; +} + +// unsigned int + +template<> void wxStringReadValue(const wxString &s , unsigned int &data ) +{ + wxSscanf(s, _T("%d"), &data ) ; +} + +template<> void wxStringWriteValue(wxString &s , const unsigned int &data ) +{ + s = wxString::Format(_T("%d"), data ) ; +} + +// long + +template<> void wxStringReadValue(const wxString &s , long &data ) +{ + wxSscanf(s, _T("%ld"), &data ) ; +} + +template<> void wxStringWriteValue(wxString &s , const long &data ) +{ + s = wxString::Format(_T("%ld"), data ) ; +} + +// unsigned long + +template<> void wxStringReadValue(const wxString &s , unsigned long &data ) +{ + wxSscanf(s, _T("%ld"), &data ) ; +} + +template<> void wxStringWriteValue(wxString &s , const unsigned long &data ) +{ + s = wxString::Format(_T("%ld"), data ) ; +} + +// float + +template<> void wxStringReadValue(const wxString &s , float &data ) +{ + wxSscanf(s, _T("%f"), &data ) ; +} + +template<> void wxStringWriteValue(wxString &s , const float &data ) +{ + s = wxString::Format(_T("%f"), data ) ; +} + +// double + +template<> void wxStringReadValue(const wxString &s , double &data ) +{ + wxSscanf(s, _T("%lf"), &data ) ; +} + +template<> void wxStringWriteValue(wxString &s , const double &data ) +{ + s = wxString::Format(_T("%lf"), data ) ; +} + +// wxString + +template<> void wxStringReadValue(const wxString &s , wxString &data ) +{ + data = s ; +} + +template<> void wxStringWriteValue(wxString &s , const wxString &data ) +{ + s = data ; +} + +// built-ins +// + +#if wxUSE_FUNC_TEMPLATE_POINTER +#define wxBUILTIN_TYPE_INFO( element , type ) \ + wxBuiltInTypeInfo s_typeInfo##type(element , &wxToStringConverter , &wxFromStringConverter , typeid(type).name()) ; +#else +#define wxBUILTIN_TYPE_INFO( element , type ) \ + void _toString##element( const wxxVariant& data , wxString &result ) { wxToStringConverter(data, result); } \ + void _fromString##element( const wxString& data , wxxVariant &result ) { wxFromStringConverter(data, result); } \ + wxBuiltInTypeInfo s_typeInfo##type(element , &_toString##element , &_fromString##element , typeid(type).name()) ; +#endif + +typedef unsigned char unsigned_char; +typedef unsigned int unsigned_int; +typedef unsigned long unsigned_long; + +wxBuiltInTypeInfo s_typeInfovoid( wxT_VOID , NULL , NULL , typeid(void).name()); +wxBUILTIN_TYPE_INFO( wxT_BOOL , bool); +wxBUILTIN_TYPE_INFO( wxT_CHAR , char); +wxBUILTIN_TYPE_INFO( wxT_UCHAR , unsigned_char); +wxBUILTIN_TYPE_INFO( wxT_INT , int); +wxBUILTIN_TYPE_INFO( wxT_UINT , unsigned_int); +wxBUILTIN_TYPE_INFO( wxT_LONG , long); +wxBUILTIN_TYPE_INFO( wxT_ULONG , unsigned_long); +wxBUILTIN_TYPE_INFO( wxT_FLOAT , float); +wxBUILTIN_TYPE_INFO( wxT_DOUBLE , double); +wxBUILTIN_TYPE_INFO( wxT_STRING , wxString); + + +// this are compiler induced specialization which are never used anywhere + +wxILLEGAL_TYPE_SPECIALIZATION( char const * ) +wxILLEGAL_TYPE_SPECIALIZATION( char * ) +wxILLEGAL_TYPE_SPECIALIZATION( unsigned char * ) +wxILLEGAL_TYPE_SPECIALIZATION( int * ) +wxILLEGAL_TYPE_SPECIALIZATION( bool * ) +wxILLEGAL_TYPE_SPECIALIZATION( long * ) +wxILLEGAL_TYPE_SPECIALIZATION( wxString * ) + +wxCOLLECTION_TYPE_INFO( wxString , wxArrayString ) ; + +template<> void wxCollectionToVariantArray( wxArrayString const &theArray, wxxVariantArray &value) +{ + wxArrayCollectionToVariantArray( theArray , value ) ; +} + +wxTypeInfoMap *wxTypeInfo::ms_typeTable = NULL ; + +wxTypeInfo *wxTypeInfo::FindType(const wxChar *typeName) +{ + wxTypeInfoMap::iterator iter = ms_typeTable->find(typeName) ; + wxASSERT_MSG( iter != ms_typeTable->end() , wxT("lookup for a non-existent type-info") ) ; + return (wxTypeInfo *)iter->second; +} + +#if wxUSE_UNICODE +wxClassTypeInfo::wxClassTypeInfo( wxTypeKind kind , wxClassInfo* classInfo , converterToString_t to , converterFromString_t from , const char *name) : +wxTypeInfo( kind , to , from , name) +{ wxASSERT_MSG( kind == wxT_OBJECT_PTR || kind == wxT_OBJECT , wxT("Illegal Kind for Enum Type")) ; m_classInfo = classInfo ;} +#endif + +wxClassTypeInfo::wxClassTypeInfo( wxTypeKind kind , wxClassInfo* classInfo , converterToString_t to , converterFromString_t from , const wxString &name) : +wxTypeInfo( kind , to , from , name) +{ wxASSERT_MSG( kind == wxT_OBJECT_PTR || kind == wxT_OBJECT , wxT("Illegal Kind for Enum Type")) ; m_classInfo = classInfo ;} + +wxDelegateTypeInfo::wxDelegateTypeInfo( int eventType , wxClassInfo* eventClass , converterToString_t to , converterFromString_t from ) : +wxTypeInfo ( wxT_DELEGATE , to , from , wxEmptyString ) +{ m_eventClass = eventClass ; m_eventType = eventType ; m_lastEventType = -1 ;} + +wxDelegateTypeInfo::wxDelegateTypeInfo( int eventType , int lastEventType , wxClassInfo* eventClass , converterToString_t to , converterFromString_t from ) : +wxTypeInfo ( wxT_DELEGATE , to , from , wxEmptyString ) +{ m_eventClass = eventClass ; m_eventType = eventType ; m_lastEventType = lastEventType; } + +void wxTypeInfo::Register() +{ + if ( ms_typeTable == NULL ) + ms_typeTable = new wxTypeInfoMap() ; + + if( !m_name.empty() ) + (*ms_typeTable)[m_name] = this ; +} + +void wxTypeInfo::Unregister() +{ + if( !m_name.empty() ) + ms_typeTable->erase(m_name); +} + +// removing header dependancy on string tokenizer + +void wxSetStringToArray( const wxString &s , wxArrayString &array ) +{ + wxStringTokenizer tokenizer(s, wxT("| \t\n"), wxTOKEN_STRTOK); + wxString flag; + array.Clear() ; + while (tokenizer.HasMoreTokens()) + { + array.Add(tokenizer.GetNextToken()) ; + } +} + +// ---------------------------------------------------------------------------- +// wxClassInfo +// ---------------------------------------------------------------------------- + +wxPropertyInfo::~wxPropertyInfo() +{ + if ( this == m_itsClass->m_firstProperty ) + { + m_itsClass->m_firstProperty = m_next; + } + else + { + wxPropertyInfo *info = m_itsClass->m_firstProperty; + while (info) + { + if ( info->m_next == this ) + { + info->m_next = m_next; + break; + } + + info = info->m_next; + } + } +} + +wxHandlerInfo::~wxHandlerInfo() +{ + if ( this == m_itsClass->m_firstHandler ) + { + m_itsClass->m_firstHandler = m_next; + } + else + { + wxHandlerInfo *info = m_itsClass->m_firstHandler; + while (info) + { + if ( info->m_next == this ) + { + info->m_next = m_next; + break; + } + + info = info->m_next; + } + } +} + +const wxPropertyAccessor *wxClassInfo::FindAccessor(const wxChar *PropertyName) const +{ + const wxPropertyInfo* info = FindPropertyInfo( PropertyName ) ; + + if ( info ) + return info->GetAccessor() ; + + return NULL ; +} + +wxPropertyInfo *wxClassInfo::FindPropertyInfoInThisClass (const wxChar *PropertyName) const +{ + wxPropertyInfo* info = m_firstProperty ; + + while( info ) + { + if ( wxStrcmp( info->GetName() , PropertyName ) == 0 ) + return info ; + info = info->GetNext() ; + } + + return 0; +} + +const wxPropertyInfo *wxClassInfo::FindPropertyInfo (const wxChar *PropertyName) const +{ + const wxPropertyInfo* info = FindPropertyInfoInThisClass( PropertyName ) ; + if ( info ) + return info ; + + const wxClassInfo** parents = GetParents() ; + for ( int i = 0 ; parents[i] ; ++ i ) + { + if ( ( info = parents[i]->FindPropertyInfo( PropertyName ) ) != NULL ) + return info ; + } + + return 0; +} + +wxHandlerInfo *wxClassInfo::FindHandlerInfoInThisClass (const wxChar *PropertyName) const +{ + wxHandlerInfo* info = m_firstHandler ; + + while( info ) + { + if ( wxStrcmp( info->GetName() , PropertyName ) == 0 ) + return info ; + info = info->GetNext() ; + } + + return 0; +} + +const wxHandlerInfo *wxClassInfo::FindHandlerInfo (const wxChar *PropertyName) const +{ + const wxHandlerInfo* info = FindHandlerInfoInThisClass( PropertyName ) ; + + if ( info ) + return info ; + + const wxClassInfo** parents = GetParents() ; + for ( int i = 0 ; parents[i] ; ++ i ) + { + if ( ( info = parents[i]->FindHandlerInfo( PropertyName ) ) != NULL ) + return info ; + } + + return 0; +} + +wxObjectStreamingCallback wxClassInfo::GetStreamingCallback() const +{ + if ( m_streamingCallback ) + return m_streamingCallback ; + + wxObjectStreamingCallback retval = NULL ; + const wxClassInfo** parents = GetParents() ; + for ( int i = 0 ; parents[i] && retval == NULL ; ++ i ) + { + retval = parents[i]->GetStreamingCallback() ; + } + return retval ; +} + +bool wxClassInfo::BeforeWriteObject( const wxObject *obj, wxWriter *streamer , wxPersister *persister , wxxVariantArray &metadata) const +{ + wxObjectStreamingCallback sb = GetStreamingCallback() ; + if ( sb ) + return (*sb)(obj , streamer , persister , metadata ) ; + + return true ; +} + +void wxClassInfo::SetProperty(wxObject *object, const wxChar *propertyName, const wxxVariant &value) const +{ + const wxPropertyAccessor *accessor; + + accessor = FindAccessor(propertyName); + wxASSERT(accessor->HasSetter()); + accessor->SetProperty( object , value ) ; +} + +wxxVariant wxClassInfo::GetProperty(wxObject *object, const wxChar *propertyName) const +{ + const wxPropertyAccessor *accessor; + + accessor = FindAccessor(propertyName); + wxASSERT(accessor->HasGetter()); + wxxVariant result ; + accessor->GetProperty(object,result); + return result ; +} + +wxxVariantArray wxClassInfo::GetPropertyCollection(wxObject *object, const wxChar *propertyName) const +{ + const wxPropertyAccessor *accessor; + + accessor = FindAccessor(propertyName); + wxASSERT(accessor->HasGetter()); + wxxVariantArray result ; + accessor->GetPropertyCollection(object,result); + return result ; +} + +void wxClassInfo::AddToPropertyCollection(wxObject *object, const wxChar *propertyName , const wxxVariant& value) const +{ + const wxPropertyAccessor *accessor; + + accessor = FindAccessor(propertyName); + wxASSERT(accessor->HasAdder()); + accessor->AddToPropertyCollection( object , value ) ; +} + +// void wxClassInfo::GetProperties( wxPropertyInfoMap &map ) const +// The map parameter (the name map that is) seems something special +// to MSVC and so we use a other name. +void wxClassInfo::GetProperties( wxPropertyInfoMap &infomap ) const +{ + const wxPropertyInfo *pi = GetFirstProperty() ; + while( pi ) + { + if ( infomap.find( pi->GetName() ) == infomap.end() ) + infomap[pi->GetName()] = (wxPropertyInfo*) pi ; + + pi = pi->GetNext() ; + } + + const wxClassInfo** parents = GetParents() ; + for ( int i = 0 ; parents[i] ; ++ i ) + { + parents[i]->GetProperties( infomap ) ; + } +} + +/* +VARIANT TO OBJECT +*/ + +wxObject* wxxVariant::GetAsObject() +{ + const wxClassTypeInfo *ti = dynamic_cast( m_data->GetTypeInfo() ) ; + if ( ti ) + return ti->GetClassInfo()->VariantToInstance(*this) ; + else + return NULL ; +} + +// ---------------------------------------------------------------------------- +// wxDynamicObject support +// ---------------------------------------------------------------------------- +// +// Dynamic Objects are objects that have a real superclass instance and carry their +// own attributes in a hash map. Like this it is possible to create the objects and +// stream them, as if their class information was already available from compiled data + +struct wxDynamicObject::wxDynamicObjectInternal +{ + wxDynamicObjectInternal() {} + +#if wxUSE_UNICODE + map m_properties ; +#else + map m_properties ; +#endif +} ; + +typedef list< wxDynamicObject* > wxDynamicObjectList ; + +struct wxDynamicClassInfo::wxDynamicClassInfoInternal +{ + wxDynamicObjectList m_dynamicObjects ; +} ; + +// instantiates this object with an instance of its superclass +wxDynamicObject::wxDynamicObject(wxObject* superClassInstance, const wxDynamicClassInfo *info) +{ + m_superClassInstance = superClassInstance ; + m_classInfo = info ; + m_data = new wxDynamicObjectInternal ; +} + +wxDynamicObject::~wxDynamicObject() +{ + dynamic_cast(m_classInfo)->m_data->m_dynamicObjects.remove( this ) ; + delete m_data ; + delete m_superClassInstance ; +} + +void wxDynamicObject::SetProperty (const wxChar *propertyName, const wxxVariant &value) +{ + wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(propertyName),wxT("Accessing Unknown Property in a Dynamic Object") ) ; + m_data->m_properties[propertyName] = value ; +} + +wxxVariant wxDynamicObject::GetProperty (const wxChar *propertyName) const +{ + wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(propertyName),wxT("Accessing Unknown Property in a Dynamic Object") ) ; + return m_data->m_properties[propertyName] ; +} + +void wxDynamicObject::RemoveProperty( const wxChar *propertyName ) +{ + wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(propertyName),wxT("Removing Unknown Property in a Dynamic Object") ) ; + m_data->m_properties.erase( propertyName ) ; +} + +void wxDynamicObject::RenameProperty( const wxChar *oldPropertyName , const wxChar *newPropertyName ) +{ + wxASSERT_MSG(m_classInfo->FindPropertyInfoInThisClass(oldPropertyName),wxT("Renaming Unknown Property in a Dynamic Object") ) ; + wxxVariant value = m_data->m_properties[oldPropertyName] ; + m_data->m_properties.erase( oldPropertyName ) ; + m_data->m_properties[newPropertyName] = value ; +} + + +// ---------------------------------------------------------------------------- +// wxDynamiClassInfo +// ---------------------------------------------------------------------------- + +wxDynamicClassInfo::wxDynamicClassInfo( const wxChar *unitName, const wxChar *className , const wxClassInfo* superClass ) : +wxClassInfo( unitName, className , new const wxClassInfo*[2]) +{ + GetParents()[0] = superClass ; + GetParents()[1] = NULL ; + m_data = new wxDynamicClassInfoInternal ; +} + +wxDynamicClassInfo::~wxDynamicClassInfo() +{ + delete[] GetParents() ; + delete m_data ; +} + +wxObject *wxDynamicClassInfo::AllocateObject() const +{ + wxObject* parent = GetParents()[0]->AllocateObject() ; + wxDynamicObject *obj = new wxDynamicObject( parent , this ) ; + m_data->m_dynamicObjects.push_back( obj ) ; + return obj ; +} + +void wxDynamicClassInfo::Create (wxObject *object, int paramCount, wxxVariant *params) const +{ + wxDynamicObject *dynobj = dynamic_cast< wxDynamicObject *>( object ) ; + wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::Create on an object other than wxDynamicObject") ) ; + GetParents()[0]->Create( dynobj->GetSuperClassInstance() , paramCount , params ) ; +} + +// get number of parameters for constructor +int wxDynamicClassInfo::GetCreateParamCount() const +{ + return GetParents()[0]->GetCreateParamCount() ; +} + +// get i-th constructor parameter +const wxChar* wxDynamicClassInfo::GetCreateParamName(int i) const +{ + return GetParents()[0]->GetCreateParamName( i ) ; +} + +void wxDynamicClassInfo::SetProperty(wxObject *object, const wxChar *propertyName, const wxxVariant &value) const +{ + wxDynamicObject* dynobj = dynamic_cast< wxDynamicObject * >( object ) ; + wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; + if ( FindPropertyInfoInThisClass(propertyName) ) + dynobj->SetProperty( propertyName , value ) ; + else + GetParents()[0]->SetProperty( dynobj->GetSuperClassInstance() , propertyName , value ) ; +} + +wxxVariant wxDynamicClassInfo::GetProperty(wxObject *object, const wxChar *propertyName) const +{ + wxDynamicObject* dynobj = dynamic_cast< wxDynamicObject * >( object ) ; + wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; + if ( FindPropertyInfoInThisClass(propertyName) ) + return dynobj->GetProperty( propertyName ) ; + else + return GetParents()[0]->GetProperty( dynobj->GetSuperClassInstance() , propertyName ) ; +} + +void wxDynamicClassInfo::AddProperty( const wxChar *propertyName , const wxTypeInfo* typeInfo ) +{ + new wxPropertyInfo( m_firstProperty , this , propertyName , typeInfo->GetTypeName() , new wxGenericPropertyAccessor( propertyName ) , wxxVariant() ) ; +} + +void wxDynamicClassInfo::AddHandler( const wxChar *handlerName , wxObjectEventFunction address , const wxClassInfo* eventClassInfo ) +{ + new wxHandlerInfo( m_firstHandler , this , handlerName , address , eventClassInfo ) ; +} + +// removes an existing runtime-property +void wxDynamicClassInfo::RemoveProperty( const wxChar *propertyName ) +{ + for ( wxDynamicObjectList::iterator iter = m_data->m_dynamicObjects.begin() ; iter != m_data->m_dynamicObjects.end() ; ++iter ) + (*iter)->RemoveProperty( propertyName ) ; + delete FindPropertyInfoInThisClass(propertyName) ; +} + +// removes an existing runtime-handler +void wxDynamicClassInfo::RemoveHandler( const wxChar *handlerName ) +{ + delete FindHandlerInfoInThisClass(handlerName) ; +} + +// renames an existing runtime-property +void wxDynamicClassInfo::RenameProperty( const wxChar *oldPropertyName , const wxChar *newPropertyName ) +{ + wxPropertyInfo* pi = FindPropertyInfoInThisClass(oldPropertyName) ; + wxASSERT_MSG( pi ,wxT("not existing property") ) ; + pi->m_name = newPropertyName ; + dynamic_cast(pi->GetAccessor())->RenameProperty( oldPropertyName , newPropertyName ) ; + for ( wxDynamicObjectList::iterator iter = m_data->m_dynamicObjects.begin() ; iter != m_data->m_dynamicObjects.end() ; ++iter ) + (*iter)->RenameProperty( oldPropertyName , newPropertyName ) ; +} + +// renames an existing runtime-handler +void wxDynamicClassInfo::RenameHandler( const wxChar *oldHandlerName , const wxChar *newHandlerName ) +{ + wxASSERT_MSG(FindHandlerInfoInThisClass(oldHandlerName),wxT("not existing handler") ) ; + FindHandlerInfoInThisClass(oldHandlerName)->m_name = newHandlerName ; +} + +// ---------------------------------------------------------------------------- +// wxGenericPropertyAccessor +// ---------------------------------------------------------------------------- + +struct wxGenericPropertyAccessor::wxGenericPropertyAccessorInternal +{ + char filler ; +} ; + +wxGenericPropertyAccessor::wxGenericPropertyAccessor( const wxString& propertyName ) +: wxPropertyAccessor( NULL , NULL , NULL , NULL ) +{ + m_data = new wxGenericPropertyAccessorInternal ; + m_propertyName = propertyName ; + m_getterName = wxT("Get")+propertyName ; + m_setterName = wxT("Set")+propertyName ; +} + +wxGenericPropertyAccessor::~wxGenericPropertyAccessor() +{ + delete m_data ; +} +void wxGenericPropertyAccessor::SetProperty(wxObject *object, const wxxVariant &value) const +{ + wxDynamicObject* dynobj = dynamic_cast< wxDynamicObject * >( object ) ; + wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; + dynobj->SetProperty(m_propertyName , value ) ; +} + +void wxGenericPropertyAccessor::GetProperty(const wxObject *object, wxxVariant& value) const +{ + const wxDynamicObject* dynobj = dynamic_cast< const wxDynamicObject * >( object ) ; + wxASSERT_MSG( dynobj , wxT("cannot call wxDynamicClassInfo::SetProperty on an object other than wxDynamicObject") ) ; + value = dynobj->GetProperty( m_propertyName ) ; +} + +#endif // wxUSE_EXTENDED_RTTI diff --git a/Source/3rd Party/wx/src/common/xtistrm.cpp b/Source/3rd Party/wx/src/common/xtistrm.cpp index b1e7f53cb..eeb0cf4d5 100644 --- a/Source/3rd Party/wx/src/common/xtistrm.cpp +++ b/Source/3rd Party/wx/src/common/xtistrm.cpp @@ -1,847 +1,847 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/xtistrm.cpp -// Purpose: streaming runtime metadata information -// Author: Stefan Csomor -// Modified by: -// Created: 27/07/03 -// RCS-ID: $Id: xtistrm.cpp 38939 2006-04-27 12:47:14Z ABX $ -// Copyright: (c) 2003 Stefan Csomor -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_EXTENDED_RTTI - -#include "wx/xtistrm.h" - -#ifndef WX_PRECOMP - #include "wx/object.h" - #include "wx/hash.h" - #include "wx/event.h" -#endif - -#include "wx/tokenzr.h" -#include "wx/txtstrm.h" - -#include "wx/beforestd.h" -#include -#include -#include -#include "wx/afterstd.h" - -using namespace std ; - -struct wxWriter::wxWriterInternal -{ - map< const wxObject* , int > m_writtenObjects ; - int m_nextId ; -} ; - -wxWriter::wxWriter() -{ - m_data = new wxWriterInternal ; - m_data->m_nextId = 0 ; -} - -wxWriter::~wxWriter() -{ - delete m_data ; -} - -struct wxWriter::wxWriterInternalPropertiesData -{ - char nothing ; -} ; - -void wxWriter::ClearObjectContext() -{ - delete m_data ; - m_data = new wxWriterInternal() ; - m_data->m_nextId = 0 ; -} - -void wxWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo , wxPersister *persister , const wxString &name , wxxVariantArray &metadata ) -{ - DoBeginWriteTopLevelEntry( name ) ; - WriteObject( object , classInfo , persister , false , metadata) ; - DoEndWriteTopLevelEntry( name ) ; -} - -void wxWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo , wxPersister *persister , bool isEmbedded, wxxVariantArray &metadata ) -{ - if ( !classInfo->BeforeWriteObject( object , this , persister , metadata) ) - return ; - - if ( persister->BeforeWriteObject( this , object , classInfo , metadata) ) - { - if ( object == NULL ) - DoWriteNullObject() ; - else if ( IsObjectKnown( object ) ) - DoWriteRepeatedObject( GetObjectID(object) ) ; - else - { - int oid = m_data->m_nextId++ ; - if ( !isEmbedded ) - m_data->m_writtenObjects[object] = oid ; - - // in case this object is a wxDynamicObject we also have to insert is superclass - // instance with the same id, so that object relations are streamed out correctly - const wxDynamicObject* dynobj = dynamic_cast( object ) ; - if ( !isEmbedded && dynobj ) - m_data->m_writtenObjects[dynobj->GetSuperClassInstance()] = oid ; - - DoBeginWriteObject( object , classInfo , oid , metadata ) ; - wxWriterInternalPropertiesData data ; - WriteAllProperties( object , classInfo , persister , &data ) ; - DoEndWriteObject( object , classInfo , oid ) ; - } - persister->AfterWriteObject( this ,object , classInfo ) ; - } -} - -void wxWriter::FindConnectEntry(const wxEvtHandler * evSource,const wxDelegateTypeInfo* dti, const wxObject* &sink , const wxHandlerInfo *&handler) -{ - wxList *dynamicEvents = evSource->GetDynamicEventTable() ; - - if ( dynamicEvents ) - { - wxList::compatibility_iterator node = dynamicEvents->GetFirst(); - while (node) - { - wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); - - // find the match - if ( entry->m_fn && - (dti->GetEventType() == entry->m_eventType) && - (entry->m_id == -1 ) && - (entry->m_eventSink != NULL ) ) - { - sink = entry->m_eventSink ; - const wxClassInfo* sinkClassInfo = sink->GetClassInfo() ; - const wxHandlerInfo* sinkHandler = sinkClassInfo->GetFirstHandler() ; - while ( sinkHandler ) - { - if ( sinkHandler->GetEventFunction() == entry->m_fn ) - { - handler = sinkHandler ; - break ; - } - sinkHandler = sinkHandler->GetNext() ; - } - break ; - } - node = node->GetNext(); - } - } -} -void wxWriter::WriteAllProperties( const wxObject * obj , const wxClassInfo* ci , wxPersister *persister, wxWriterInternalPropertiesData * data ) -{ - wxPropertyInfoMap map ; - ci->GetProperties( map ) ; - for ( int i = 0 ; i < ci->GetCreateParamCount() ; ++i ) - { - wxString name = ci->GetCreateParamName(i) ; - const wxPropertyInfo* prop = map.find(name)->second ; - if ( prop ) - { - WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ; - } - else - { - wxLogError( _("Create Parameter not found in declared RTTI Parameters") ) ; - } - map.erase( name ) ; - } - { // Extra block for broken compilers - for( wxPropertyInfoMap::iterator iter = map.begin() ; iter != map.end() ; ++iter ) - { - const wxPropertyInfo* prop = iter->second ; - if ( prop->GetFlags() & wxPROP_OBJECT_GRAPH ) - { - WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ; - } - } - } - { // Extra block for broken compilers - for( wxPropertyInfoMap::iterator iter = map.begin() ; iter != map.end() ; ++iter ) - { - const wxPropertyInfo* prop = iter->second ; - if ( !(prop->GetFlags() & wxPROP_OBJECT_GRAPH) ) - { - WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ; - } - } - } -} - -void wxWriter::WriteOneProperty( const wxObject *obj , const wxClassInfo* ci , const wxPropertyInfo* pi , wxPersister *persister , wxWriterInternalPropertiesData *WXUNUSED(data) ) -{ - if ( pi->GetFlags() & wxPROP_DONT_STREAM ) - return ; - - // make sure that we are picking the correct object for accessing the property - const wxDynamicObject* dynobj = dynamic_cast< const wxDynamicObject* > (obj ) ; - if ( dynobj && (dynamic_cast(ci) == NULL) ) - obj = dynobj->GetSuperClassInstance() ; - - if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION ) - { - wxxVariantArray data ; - pi->GetAccessor()->GetPropertyCollection(obj, data) ; - const wxTypeInfo * elementType = dynamic_cast< const wxCollectionTypeInfo* >( pi->GetTypeInfo() )->GetElementType() ; - for ( size_t i = 0 ; i < data.GetCount() ; ++i ) - { - if ( i == 0 ) - DoBeginWriteProperty( pi ) ; - - DoBeginWriteElement() ; - wxxVariant value = data[i] ; - if ( persister->BeforeWriteProperty( this , obj, pi , value ) ) - { - const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( elementType ) ; - if ( cti ) - { - const wxClassInfo* pci = cti->GetClassInfo() ; - wxObject *vobj = pci->VariantToInstance( value ) ; - wxxVariantArray md ; - WriteObject( vobj , (vobj ? vobj->GetClassInfo() : pci ) , persister , cti->GetKind()== wxT_OBJECT , md ) ; - } - else - { - DoWriteSimpleType( value ) ; - } - } - DoEndWriteElement() ; - if ( i == data.GetCount() - 1 ) - DoEndWriteProperty( pi ) ; - } - } - else - { - const wxDelegateTypeInfo* dti = dynamic_cast< const wxDelegateTypeInfo* > ( pi->GetTypeInfo() ) ; - if ( dti ) - { - const wxObject* sink = NULL ; - const wxHandlerInfo *handler = NULL ; - - const wxEvtHandler * evSource = dynamic_cast(obj) ; - if ( evSource ) - { - FindConnectEntry( evSource , dti , sink , handler ) ; - if ( persister->BeforeWriteDelegate( this , obj , ci , pi , sink , handler ) ) - { - if ( sink != NULL && handler != NULL ) - { - DoBeginWriteProperty( pi ) ; - if ( IsObjectKnown( sink ) ) - { - DoWriteDelegate( obj , ci , pi , sink , GetObjectID( sink ) , sink->GetClassInfo() , handler ) ; - DoEndWriteProperty( pi ) ; - } - else - { - wxLogError( _("Streaming delegates for not already streamed objects not yet supported") ) ; - } - } - } - } - else - { - wxLogError(_("Illegal Object Class (Non-wxEvtHandler) as Event Source") ) ; - } - } - else - { - wxxVariant value ; - pi->GetAccessor()->GetProperty(obj, value) ; - - // avoid streaming out void objects - if( value.IsEmpty() ) - return ; - - if ( pi->GetFlags() & wxPROP_ENUM_STORE_LONG ) - { - const wxEnumTypeInfo *eti = dynamic_cast( pi->GetTypeInfo() ) ; - if ( eti ) - { - eti->ConvertFromLong( value.wxTEMPLATED_MEMBER_CALL(Get , long) , value ) ; - } - else - { - wxLogError( _("Type must have enum - long conversion") ) ; - } - } - - // avoid streaming out default values - if ( pi->GetTypeInfo()->HasStringConverters() && !pi->GetDefaultValue().IsEmpty() ) - { - if ( value.GetAsString() == pi->GetDefaultValue().GetAsString() ) - return ; - } - - // avoid streaming out null objects - const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( pi->GetTypeInfo() ) ; - - if ( cti && value.GetAsObject() == NULL ) - return ; - - if ( persister->BeforeWriteProperty( this , obj, pi , value ) ) - { - DoBeginWriteProperty( pi ) ; - if ( cti ) - { - const wxClassInfo* pci = cti->GetClassInfo() ; - wxObject *vobj = pci->VariantToInstance( value ) ; - if ( vobj && pi->GetTypeInfo()->HasStringConverters() ) - { - wxString stringValue ; - cti->ConvertToString( value , stringValue ) ; - wxxVariant convertedValue(stringValue) ; - DoWriteSimpleType( convertedValue ) ; - } - else - { - wxxVariantArray md ; - WriteObject( vobj , (vobj ? vobj->GetClassInfo() : pci ) , persister , cti->GetKind()== wxT_OBJECT , md) ; - } - } - else - { - DoWriteSimpleType( value ) ; - } - DoEndWriteProperty( pi ) ; - } - } - } -} - -int wxWriter::GetObjectID(const wxObject *obj) -{ - if ( !IsObjectKnown( obj ) ) - return wxInvalidObjectID ; - - return m_data->m_writtenObjects[obj] ; -} - -bool wxWriter::IsObjectKnown( const wxObject *obj ) -{ - return m_data->m_writtenObjects.find( obj ) != m_data->m_writtenObjects.end() ; -} - - -// ---------------------------------------------------------------------------- -// reading objects in -// ---------------------------------------------------------------------------- - -struct wxReader::wxReaderInternal -{ - map m_classInfos; -}; - -wxReader::wxReader() -{ - m_data = new wxReaderInternal; -} - -wxReader::~wxReader() -{ - delete m_data; -} - -wxClassInfo* wxReader::GetObjectClassInfo(int objectID) -{ - if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID ) - { - wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) ) ; - return NULL ; - } - if ( m_data->m_classInfos.find(objectID) == m_data->m_classInfos.end() ) - { - wxLogError( _("Unknown Object passed to GetObjectClassInfo" ) ) ; - return NULL ; - } - return m_data->m_classInfos[objectID] ; -} - -void wxReader::SetObjectClassInfo(int objectID, wxClassInfo *classInfo ) -{ - if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID ) - { - wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) ) ; - return ; - } - if ( m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() ) - { - wxLogError( _("Already Registered Object passed to SetObjectClassInfo" ) ) ; - return ; - } - m_data->m_classInfos[objectID] = classInfo ; -} - -bool wxReader::HasObjectClassInfo( int objectID ) -{ - if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID ) - { - wxLogError( _("Invalid or Null Object ID passed to HasObjectClassInfo" ) ) ; - return NULL ; - } - return m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() ; -} - - -// ---------------------------------------------------------------------------- -// reading xml in -// ---------------------------------------------------------------------------- - -/* -Reading components has not to be extended for components -as properties are always sought by typeinfo over all levels -and create params are always toplevel class only -*/ - - -// ---------------------------------------------------------------------------- -// depersisting to memory -// ---------------------------------------------------------------------------- - -struct wxRuntimeDepersister::wxRuntimeDepersisterInternal -{ - map m_objects; - - void SetObject(int objectID, wxObject *obj ) - { - if ( m_objects.find(objectID) != m_objects.end() ) - { - wxLogError( _("Passing a already registered object to SetObject") ) ; - return ; - } - m_objects[objectID] = obj ; - } - wxObject* GetObject( int objectID ) - { - if ( objectID == wxNullObjectID ) - return NULL ; - if ( m_objects.find(objectID) == m_objects.end() ) - { - wxLogError( _("Passing an unkown object to GetObject") ) ; - return NULL ; - } - - return m_objects[objectID] ; - } -} ; - -wxRuntimeDepersister::wxRuntimeDepersister() -{ - m_data = new wxRuntimeDepersisterInternal() ; -} - -wxRuntimeDepersister::~wxRuntimeDepersister() -{ - delete m_data ; -} - -void wxRuntimeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo , - wxxVariantArray &WXUNUSED(metadata)) -{ - wxObject *O; - O = classInfo->CreateObject(); - m_data->SetObject(objectID, O); -} - -void wxRuntimeDepersister::CreateObject(int objectID, - const wxClassInfo *classInfo, - int paramCount, - wxxVariant *params, - int *objectIdValues, - const wxClassInfo **objectClassInfos , - wxxVariantArray &WXUNUSED(metadata)) -{ - wxObject *o; - o = m_data->GetObject(objectID); - for ( int i = 0 ; i < paramCount ; ++i ) - { - if ( objectIdValues[i] != wxInvalidObjectID ) - { - wxObject *o; - o = m_data->GetObject(objectIdValues[i]); - // if this is a dynamic object and we are asked for another class - // than wxDynamicObject we cast it down manually. - wxDynamicObject *dyno = dynamic_cast< wxDynamicObject * > (o) ; - if ( dyno!=NULL && (objectClassInfos[i] != dyno->GetClassInfo()) ) - { - o = dyno->GetSuperClassInstance() ; - } - params[i] = objectClassInfos[i]->InstanceToVariant(o) ; - } - } - classInfo->Create(o, paramCount, params); -} - -void wxRuntimeDepersister::ConstructObject(int objectID, - const wxClassInfo *classInfo, - int paramCount, - wxxVariant *params, - int *objectIdValues, - const wxClassInfo **objectClassInfos , - wxxVariantArray &WXUNUSED(metadata)) -{ - wxObject *o; - for ( int i = 0 ; i < paramCount ; ++i ) - { - if ( objectIdValues[i] != wxInvalidObjectID ) - { - wxObject *o; - o = m_data->GetObject(objectIdValues[i]); - // if this is a dynamic object and we are asked for another class - // than wxDynamicObject we cast it down manually. - wxDynamicObject *dyno = dynamic_cast< wxDynamicObject * > (o) ; - if ( dyno!=NULL && (objectClassInfos[i] != dyno->GetClassInfo()) ) - { - o = dyno->GetSuperClassInstance() ; - } - params[i] = objectClassInfos[i]->InstanceToVariant(o) ; - } - } - o = classInfo->ConstructObject(paramCount, params); - m_data->SetObject(objectID, o); -} - - -void wxRuntimeDepersister::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo)) -{ - wxObject *o; - o = m_data->GetObject(objectID); - delete o ; -} - -void wxRuntimeDepersister::SetProperty(int objectID, - const wxClassInfo *classInfo, - const wxPropertyInfo* propertyInfo, - const wxxVariant &value) -{ - wxObject *o; - o = m_data->GetObject(objectID); - classInfo->SetProperty( o , propertyInfo->GetName() , value ) ; -} - -void wxRuntimeDepersister::SetPropertyAsObject(int objectID, - const wxClassInfo *classInfo, - const wxPropertyInfo* propertyInfo, - int valueObjectId) -{ - wxObject *o, *valo; - o = m_data->GetObject(objectID); - valo = m_data->GetObject(valueObjectId); - const wxClassInfo* valClassInfo = (dynamic_cast(propertyInfo->GetTypeInfo()))->GetClassInfo() ; - // if this is a dynamic object and we are asked for another class - // than wxDynamicObject we cast it down manually. - wxDynamicObject *dynvalo = dynamic_cast< wxDynamicObject * > (valo) ; - if ( dynvalo!=NULL && (valClassInfo != dynvalo->GetClassInfo()) ) - { - valo = dynvalo->GetSuperClassInstance() ; - } - - classInfo->SetProperty( o , propertyInfo->GetName() , valClassInfo->InstanceToVariant(valo) ) ; -} - -void wxRuntimeDepersister::SetConnect(int eventSourceObjectID, - const wxClassInfo *WXUNUSED(eventSourceClassInfo), - const wxPropertyInfo *delegateInfo , - const wxClassInfo *WXUNUSED(eventSinkClassInfo) , - const wxHandlerInfo* handlerInfo , - int eventSinkObjectID ) -{ - wxEvtHandler *ehsource = dynamic_cast< wxEvtHandler* >( m_data->GetObject( eventSourceObjectID ) ) ; - wxEvtHandler *ehsink = dynamic_cast< wxEvtHandler *>(m_data->GetObject(eventSinkObjectID) ) ; - - if ( ehsource && ehsink ) - { - const wxDelegateTypeInfo *delegateTypeInfo = dynamic_cast(delegateInfo->GetTypeInfo()); - if( delegateTypeInfo && delegateTypeInfo->GetLastEventType() == -1 ) - { - ehsource->Connect( -1 , delegateTypeInfo->GetEventType() , - handlerInfo->GetEventFunction() , NULL /*user data*/ , - ehsink ) ; - } - else - { - for ( wxEventType iter = delegateTypeInfo->GetEventType() ; iter <= delegateTypeInfo->GetLastEventType() ; ++iter ) - { - ehsource->Connect( -1 , iter , - handlerInfo->GetEventFunction() , NULL /*user data*/ , - ehsink ) ; - } - } - } -} - -wxObject *wxRuntimeDepersister::GetObject(int objectID) -{ - return m_data->GetObject( objectID ) ; -} - -// adds an element to a property collection -void wxRuntimeDepersister::AddToPropertyCollection( int objectID , - const wxClassInfo *classInfo, - const wxPropertyInfo* propertyInfo , - const wxxVariant &value) -{ - wxObject *o; - o = m_data->GetObject(objectID); - classInfo->AddToPropertyCollection( o , propertyInfo->GetName() , value ) ; -} - -// sets the corresponding property (value is an object) -void wxRuntimeDepersister::AddToPropertyCollectionAsObject(int objectID, - const wxClassInfo *classInfo, - const wxPropertyInfo* propertyInfo , - int valueObjectId) -{ - wxObject *o, *valo; - o = m_data->GetObject(objectID); - valo = m_data->GetObject(valueObjectId); - const wxCollectionTypeInfo * collectionTypeInfo = dynamic_cast< const wxCollectionTypeInfo * >(propertyInfo->GetTypeInfo() ) ; - const wxClassInfo* valClassInfo = (dynamic_cast(collectionTypeInfo->GetElementType()))->GetClassInfo() ; - // if this is a dynamic object and we are asked for another class - // than wxDynamicObject we cast it down manually. - wxDynamicObject *dynvalo = dynamic_cast< wxDynamicObject * > (valo) ; - if ( dynvalo!=NULL && (valClassInfo != dynvalo->GetClassInfo()) ) - { - valo = dynvalo->GetSuperClassInstance() ; - } - - classInfo->AddToPropertyCollection( o , propertyInfo->GetName() , valClassInfo->InstanceToVariant(valo) ) ; -} - -// ---------------------------------------------------------------------------- -// depersisting to code -// ---------------------------------------------------------------------------- - -struct wxCodeDepersister::wxCodeDepersisterInternal -{ -#if wxUSE_UNICODE - map m_objectNames ; -#else - map m_objectNames ; -#endif - - void SetObjectName(int objectID, const wxString &name ) - { - if ( m_objectNames.find(objectID) != m_objectNames.end() ) - { - wxLogError( _("Passing a already registered object to SetObjectName") ) ; - return ; - } - m_objectNames[objectID] = (const wxChar *)name; - } - - wxString GetObjectName( int objectID ) - { - if ( objectID == wxNullObjectID ) - return wxT("NULL") ; - - if ( m_objectNames.find(objectID) == m_objectNames.end() ) - { - wxLogError( _("Passing an unkown object to GetObject") ) ; - return wxEmptyString ; - } - return wxString( m_objectNames[objectID].c_str() ) ; - } -} ; - -wxCodeDepersister::wxCodeDepersister(wxTextOutputStream *out) -: m_fp(out) -{ - m_data = new wxCodeDepersisterInternal ; -} - -wxCodeDepersister::~wxCodeDepersister() -{ - delete m_data ; -} - -void wxCodeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo , - wxxVariantArray &WXUNUSED(metadata)) -{ - wxString objectName = wxString::Format( wxT("LocalObject_%d") , objectID ) ; - m_fp->WriteString( wxString::Format( wxT("\t%s *%s = new %s;\n"), - classInfo->GetClassName(), - objectName.c_str(), - classInfo->GetClassName()) ); - m_data->SetObjectName( objectID , objectName ) ; -} - -void wxCodeDepersister::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo)) -{ - m_fp->WriteString( wxString::Format( wxT("\tdelete %s;\n"), - m_data->GetObjectName( objectID).c_str() ) ); -} - -wxString wxCodeDepersister::ValueAsCode( const wxxVariant ¶m ) -{ - wxString value ; - const wxTypeInfo* type = param.GetTypeInfo() ; - if ( type->GetKind() == wxT_CUSTOM ) - { - const wxCustomTypeInfo* cti = dynamic_cast(type) ; - if ( cti ) - { - value.Printf( wxT("%s(%s)"), cti->GetTypeName().c_str(),param.GetAsString().c_str() ); - } - else - { - wxLogError ( _("Internal error, illegal wxCustomTypeInfo") ) ; - } - } - else if ( type->GetKind() == wxT_STRING ) - { - value.Printf( wxT("\"%s\""),param.GetAsString().c_str() ); - } - else - { - value.Printf( wxT("%s"), param.GetAsString().c_str() ); - } - return value ; -} - -void wxCodeDepersister::CreateObject(int objectID, - const wxClassInfo *WXUNUSED(classInfo), - int paramCount, - wxxVariant *params, - int *objectIDValues, - const wxClassInfo **WXUNUSED(objectClassInfos) , - wxxVariantArray &WXUNUSED(metadata) - ) -{ - int i; - m_fp->WriteString( wxString::Format( wxT("\t%s->Create("), m_data->GetObjectName(objectID).c_str() ) ); - for (i = 0; i < paramCount; i++) - { - if ( objectIDValues[i] != wxInvalidObjectID ) - m_fp->WriteString( wxString::Format( wxT("%s"), m_data->GetObjectName( objectIDValues[i] ).c_str() ) ); - else - { - m_fp->WriteString( wxString::Format( wxT("%s"), ValueAsCode(params[i]).c_str() ) ); - } - if (i < paramCount - 1) - m_fp->WriteString( wxT(", ")); - } - m_fp->WriteString( wxT(");\n") ); -} - -void wxCodeDepersister::ConstructObject(int objectID, - const wxClassInfo *classInfo, - int paramCount, - wxxVariant *params, - int *objectIDValues, - const wxClassInfo **WXUNUSED(objectClassInfos) , - wxxVariantArray &WXUNUSED(metadata) - ) -{ - wxString objectName = wxString::Format( wxT("LocalObject_%d") , objectID ) ; - m_fp->WriteString( wxString::Format( wxT("\t%s *%s = new %s("), - classInfo->GetClassName(), - objectName.c_str(), - classInfo->GetClassName()) ); - m_data->SetObjectName( objectID , objectName ) ; - - int i; - for (i = 0; i < paramCount; i++) - { - if ( objectIDValues[i] != wxInvalidObjectID ) - m_fp->WriteString( wxString::Format( wxT("%s"), m_data->GetObjectName( objectIDValues[i] ).c_str() ) ); - else - { - m_fp->WriteString( wxString::Format( wxT("%s"), ValueAsCode(params[i]).c_str() ) ); - } - if (i < paramCount - 1) - m_fp->WriteString( wxT(", ") ); - } - m_fp->WriteString( wxT(");\n") ); -} - -void wxCodeDepersister::SetProperty(int objectID, - const wxClassInfo *WXUNUSED(classInfo), - const wxPropertyInfo* propertyInfo, - const wxxVariant &value) -{ - m_fp->WriteString( wxString::Format( wxT("\t%s->%s(%s);\n"), - m_data->GetObjectName(objectID).c_str(), - propertyInfo->GetAccessor()->GetSetterName().c_str(), - ValueAsCode(value).c_str()) ); -} - -void wxCodeDepersister::SetPropertyAsObject(int objectID, - const wxClassInfo *WXUNUSED(classInfo), - const wxPropertyInfo* propertyInfo, - int valueObjectId) -{ - if ( propertyInfo->GetTypeInfo()->GetKind() == wxT_OBJECT ) - m_fp->WriteString( wxString::Format( wxT("\t%s->%s(*%s);\n"), - m_data->GetObjectName(objectID).c_str(), - propertyInfo->GetAccessor()->GetSetterName().c_str(), - m_data->GetObjectName( valueObjectId).c_str() ) ); - else - m_fp->WriteString( wxString::Format( wxT("\t%s->%s(%s);\n"), - m_data->GetObjectName(objectID).c_str(), - propertyInfo->GetAccessor()->GetSetterName().c_str(), - m_data->GetObjectName( valueObjectId).c_str() ) ); -} - -void wxCodeDepersister::AddToPropertyCollection( int objectID , - const wxClassInfo *WXUNUSED(classInfo), - const wxPropertyInfo* propertyInfo , - const wxxVariant &value) -{ - m_fp->WriteString( wxString::Format( wxT("\t%s->%s(%s);\n"), - m_data->GetObjectName(objectID).c_str(), - propertyInfo->GetAccessor()->GetAdderName().c_str(), - ValueAsCode(value).c_str()) ); -} - -// sets the corresponding property (value is an object) -void wxCodeDepersister::AddToPropertyCollectionAsObject(int WXUNUSED(objectID), - const wxClassInfo *WXUNUSED(classInfo), - const wxPropertyInfo* WXUNUSED(propertyInfo) , - int WXUNUSED(valueObjectId)) -{ - // TODO -} - -void wxCodeDepersister::SetConnect(int eventSourceObjectID, - const wxClassInfo *WXUNUSED(eventSourceClassInfo), - const wxPropertyInfo *delegateInfo , - const wxClassInfo *eventSinkClassInfo , - const wxHandlerInfo* handlerInfo , - int eventSinkObjectID ) -{ - wxString ehsource = m_data->GetObjectName( eventSourceObjectID ) ; - wxString ehsink = m_data->GetObjectName(eventSinkObjectID) ; - wxString ehsinkClass = eventSinkClassInfo->GetClassName() ; - const wxDelegateTypeInfo *delegateTypeInfo = dynamic_cast(delegateInfo->GetTypeInfo()); - if ( delegateTypeInfo ) - { - int eventType = delegateTypeInfo->GetEventType() ; - wxString handlerName = handlerInfo->GetName() ; - - m_fp->WriteString( wxString::Format( wxT("\t%s->Connect( %s->GetId() , %d , (wxObjectEventFunction)(wxEventFunction) & %s::%s , NULL , %s ) ;") , - ehsource.c_str() , ehsource.c_str() , eventType , ehsinkClass.c_str() , handlerName.c_str() , ehsink.c_str() ) ); - } - else - { - wxLogError(_("delegate has no type info")); - } -} - -#include "wx/arrimpl.cpp" - -WX_DEFINE_OBJARRAY(wxxVariantArray); - -#endif // wxUSE_EXTENDED_RTTI +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/xtistrm.cpp +// Purpose: streaming runtime metadata information +// Author: Stefan Csomor +// Modified by: +// Created: 27/07/03 +// RCS-ID: $Id: xtistrm.cpp 38939 2006-04-27 12:47:14Z ABX $ +// Copyright: (c) 2003 Stefan Csomor +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_EXTENDED_RTTI + +#include "wx/xtistrm.h" + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/hash.h" + #include "wx/event.h" +#endif + +#include "wx/tokenzr.h" +#include "wx/txtstrm.h" + +#include "wx/beforestd.h" +#include +#include +#include +#include "wx/afterstd.h" + +using namespace std ; + +struct wxWriter::wxWriterInternal +{ + map< const wxObject* , int > m_writtenObjects ; + int m_nextId ; +} ; + +wxWriter::wxWriter() +{ + m_data = new wxWriterInternal ; + m_data->m_nextId = 0 ; +} + +wxWriter::~wxWriter() +{ + delete m_data ; +} + +struct wxWriter::wxWriterInternalPropertiesData +{ + char nothing ; +} ; + +void wxWriter::ClearObjectContext() +{ + delete m_data ; + m_data = new wxWriterInternal() ; + m_data->m_nextId = 0 ; +} + +void wxWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo , wxPersister *persister , const wxString &name , wxxVariantArray &metadata ) +{ + DoBeginWriteTopLevelEntry( name ) ; + WriteObject( object , classInfo , persister , false , metadata) ; + DoEndWriteTopLevelEntry( name ) ; +} + +void wxWriter::WriteObject(const wxObject *object, const wxClassInfo *classInfo , wxPersister *persister , bool isEmbedded, wxxVariantArray &metadata ) +{ + if ( !classInfo->BeforeWriteObject( object , this , persister , metadata) ) + return ; + + if ( persister->BeforeWriteObject( this , object , classInfo , metadata) ) + { + if ( object == NULL ) + DoWriteNullObject() ; + else if ( IsObjectKnown( object ) ) + DoWriteRepeatedObject( GetObjectID(object) ) ; + else + { + int oid = m_data->m_nextId++ ; + if ( !isEmbedded ) + m_data->m_writtenObjects[object] = oid ; + + // in case this object is a wxDynamicObject we also have to insert is superclass + // instance with the same id, so that object relations are streamed out correctly + const wxDynamicObject* dynobj = dynamic_cast( object ) ; + if ( !isEmbedded && dynobj ) + m_data->m_writtenObjects[dynobj->GetSuperClassInstance()] = oid ; + + DoBeginWriteObject( object , classInfo , oid , metadata ) ; + wxWriterInternalPropertiesData data ; + WriteAllProperties( object , classInfo , persister , &data ) ; + DoEndWriteObject( object , classInfo , oid ) ; + } + persister->AfterWriteObject( this ,object , classInfo ) ; + } +} + +void wxWriter::FindConnectEntry(const wxEvtHandler * evSource,const wxDelegateTypeInfo* dti, const wxObject* &sink , const wxHandlerInfo *&handler) +{ + wxList *dynamicEvents = evSource->GetDynamicEventTable() ; + + if ( dynamicEvents ) + { + wxList::compatibility_iterator node = dynamicEvents->GetFirst(); + while (node) + { + wxDynamicEventTableEntry *entry = (wxDynamicEventTableEntry*)node->GetData(); + + // find the match + if ( entry->m_fn && + (dti->GetEventType() == entry->m_eventType) && + (entry->m_id == -1 ) && + (entry->m_eventSink != NULL ) ) + { + sink = entry->m_eventSink ; + const wxClassInfo* sinkClassInfo = sink->GetClassInfo() ; + const wxHandlerInfo* sinkHandler = sinkClassInfo->GetFirstHandler() ; + while ( sinkHandler ) + { + if ( sinkHandler->GetEventFunction() == entry->m_fn ) + { + handler = sinkHandler ; + break ; + } + sinkHandler = sinkHandler->GetNext() ; + } + break ; + } + node = node->GetNext(); + } + } +} +void wxWriter::WriteAllProperties( const wxObject * obj , const wxClassInfo* ci , wxPersister *persister, wxWriterInternalPropertiesData * data ) +{ + wxPropertyInfoMap map ; + ci->GetProperties( map ) ; + for ( int i = 0 ; i < ci->GetCreateParamCount() ; ++i ) + { + wxString name = ci->GetCreateParamName(i) ; + const wxPropertyInfo* prop = map.find(name)->second ; + if ( prop ) + { + WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ; + } + else + { + wxLogError( _("Create Parameter not found in declared RTTI Parameters") ) ; + } + map.erase( name ) ; + } + { // Extra block for broken compilers + for( wxPropertyInfoMap::iterator iter = map.begin() ; iter != map.end() ; ++iter ) + { + const wxPropertyInfo* prop = iter->second ; + if ( prop->GetFlags() & wxPROP_OBJECT_GRAPH ) + { + WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ; + } + } + } + { // Extra block for broken compilers + for( wxPropertyInfoMap::iterator iter = map.begin() ; iter != map.end() ; ++iter ) + { + const wxPropertyInfo* prop = iter->second ; + if ( !(prop->GetFlags() & wxPROP_OBJECT_GRAPH) ) + { + WriteOneProperty( obj , prop->GetDeclaringClass() , prop , persister , data ) ; + } + } + } +} + +void wxWriter::WriteOneProperty( const wxObject *obj , const wxClassInfo* ci , const wxPropertyInfo* pi , wxPersister *persister , wxWriterInternalPropertiesData *WXUNUSED(data) ) +{ + if ( pi->GetFlags() & wxPROP_DONT_STREAM ) + return ; + + // make sure that we are picking the correct object for accessing the property + const wxDynamicObject* dynobj = dynamic_cast< const wxDynamicObject* > (obj ) ; + if ( dynobj && (dynamic_cast(ci) == NULL) ) + obj = dynobj->GetSuperClassInstance() ; + + if ( pi->GetTypeInfo()->GetKind() == wxT_COLLECTION ) + { + wxxVariantArray data ; + pi->GetAccessor()->GetPropertyCollection(obj, data) ; + const wxTypeInfo * elementType = dynamic_cast< const wxCollectionTypeInfo* >( pi->GetTypeInfo() )->GetElementType() ; + for ( size_t i = 0 ; i < data.GetCount() ; ++i ) + { + if ( i == 0 ) + DoBeginWriteProperty( pi ) ; + + DoBeginWriteElement() ; + wxxVariant value = data[i] ; + if ( persister->BeforeWriteProperty( this , obj, pi , value ) ) + { + const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( elementType ) ; + if ( cti ) + { + const wxClassInfo* pci = cti->GetClassInfo() ; + wxObject *vobj = pci->VariantToInstance( value ) ; + wxxVariantArray md ; + WriteObject( vobj , (vobj ? vobj->GetClassInfo() : pci ) , persister , cti->GetKind()== wxT_OBJECT , md ) ; + } + else + { + DoWriteSimpleType( value ) ; + } + } + DoEndWriteElement() ; + if ( i == data.GetCount() - 1 ) + DoEndWriteProperty( pi ) ; + } + } + else + { + const wxDelegateTypeInfo* dti = dynamic_cast< const wxDelegateTypeInfo* > ( pi->GetTypeInfo() ) ; + if ( dti ) + { + const wxObject* sink = NULL ; + const wxHandlerInfo *handler = NULL ; + + const wxEvtHandler * evSource = dynamic_cast(obj) ; + if ( evSource ) + { + FindConnectEntry( evSource , dti , sink , handler ) ; + if ( persister->BeforeWriteDelegate( this , obj , ci , pi , sink , handler ) ) + { + if ( sink != NULL && handler != NULL ) + { + DoBeginWriteProperty( pi ) ; + if ( IsObjectKnown( sink ) ) + { + DoWriteDelegate( obj , ci , pi , sink , GetObjectID( sink ) , sink->GetClassInfo() , handler ) ; + DoEndWriteProperty( pi ) ; + } + else + { + wxLogError( _("Streaming delegates for not already streamed objects not yet supported") ) ; + } + } + } + } + else + { + wxLogError(_("Illegal Object Class (Non-wxEvtHandler) as Event Source") ) ; + } + } + else + { + wxxVariant value ; + pi->GetAccessor()->GetProperty(obj, value) ; + + // avoid streaming out void objects + if( value.IsEmpty() ) + return ; + + if ( pi->GetFlags() & wxPROP_ENUM_STORE_LONG ) + { + const wxEnumTypeInfo *eti = dynamic_cast( pi->GetTypeInfo() ) ; + if ( eti ) + { + eti->ConvertFromLong( value.wxTEMPLATED_MEMBER_CALL(Get , long) , value ) ; + } + else + { + wxLogError( _("Type must have enum - long conversion") ) ; + } + } + + // avoid streaming out default values + if ( pi->GetTypeInfo()->HasStringConverters() && !pi->GetDefaultValue().IsEmpty() ) + { + if ( value.GetAsString() == pi->GetDefaultValue().GetAsString() ) + return ; + } + + // avoid streaming out null objects + const wxClassTypeInfo* cti = dynamic_cast< const wxClassTypeInfo* > ( pi->GetTypeInfo() ) ; + + if ( cti && value.GetAsObject() == NULL ) + return ; + + if ( persister->BeforeWriteProperty( this , obj, pi , value ) ) + { + DoBeginWriteProperty( pi ) ; + if ( cti ) + { + const wxClassInfo* pci = cti->GetClassInfo() ; + wxObject *vobj = pci->VariantToInstance( value ) ; + if ( vobj && pi->GetTypeInfo()->HasStringConverters() ) + { + wxString stringValue ; + cti->ConvertToString( value , stringValue ) ; + wxxVariant convertedValue(stringValue) ; + DoWriteSimpleType( convertedValue ) ; + } + else + { + wxxVariantArray md ; + WriteObject( vobj , (vobj ? vobj->GetClassInfo() : pci ) , persister , cti->GetKind()== wxT_OBJECT , md) ; + } + } + else + { + DoWriteSimpleType( value ) ; + } + DoEndWriteProperty( pi ) ; + } + } + } +} + +int wxWriter::GetObjectID(const wxObject *obj) +{ + if ( !IsObjectKnown( obj ) ) + return wxInvalidObjectID ; + + return m_data->m_writtenObjects[obj] ; +} + +bool wxWriter::IsObjectKnown( const wxObject *obj ) +{ + return m_data->m_writtenObjects.find( obj ) != m_data->m_writtenObjects.end() ; +} + + +// ---------------------------------------------------------------------------- +// reading objects in +// ---------------------------------------------------------------------------- + +struct wxReader::wxReaderInternal +{ + map m_classInfos; +}; + +wxReader::wxReader() +{ + m_data = new wxReaderInternal; +} + +wxReader::~wxReader() +{ + delete m_data; +} + +wxClassInfo* wxReader::GetObjectClassInfo(int objectID) +{ + if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID ) + { + wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) ) ; + return NULL ; + } + if ( m_data->m_classInfos.find(objectID) == m_data->m_classInfos.end() ) + { + wxLogError( _("Unknown Object passed to GetObjectClassInfo" ) ) ; + return NULL ; + } + return m_data->m_classInfos[objectID] ; +} + +void wxReader::SetObjectClassInfo(int objectID, wxClassInfo *classInfo ) +{ + if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID ) + { + wxLogError( _("Invalid or Null Object ID passed to GetObjectClassInfo" ) ) ; + return ; + } + if ( m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() ) + { + wxLogError( _("Already Registered Object passed to SetObjectClassInfo" ) ) ; + return ; + } + m_data->m_classInfos[objectID] = classInfo ; +} + +bool wxReader::HasObjectClassInfo( int objectID ) +{ + if ( objectID == wxNullObjectID || objectID == wxInvalidObjectID ) + { + wxLogError( _("Invalid or Null Object ID passed to HasObjectClassInfo" ) ) ; + return NULL ; + } + return m_data->m_classInfos.find(objectID) != m_data->m_classInfos.end() ; +} + + +// ---------------------------------------------------------------------------- +// reading xml in +// ---------------------------------------------------------------------------- + +/* +Reading components has not to be extended for components +as properties are always sought by typeinfo over all levels +and create params are always toplevel class only +*/ + + +// ---------------------------------------------------------------------------- +// depersisting to memory +// ---------------------------------------------------------------------------- + +struct wxRuntimeDepersister::wxRuntimeDepersisterInternal +{ + map m_objects; + + void SetObject(int objectID, wxObject *obj ) + { + if ( m_objects.find(objectID) != m_objects.end() ) + { + wxLogError( _("Passing a already registered object to SetObject") ) ; + return ; + } + m_objects[objectID] = obj ; + } + wxObject* GetObject( int objectID ) + { + if ( objectID == wxNullObjectID ) + return NULL ; + if ( m_objects.find(objectID) == m_objects.end() ) + { + wxLogError( _("Passing an unkown object to GetObject") ) ; + return NULL ; + } + + return m_objects[objectID] ; + } +} ; + +wxRuntimeDepersister::wxRuntimeDepersister() +{ + m_data = new wxRuntimeDepersisterInternal() ; +} + +wxRuntimeDepersister::~wxRuntimeDepersister() +{ + delete m_data ; +} + +void wxRuntimeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo , + wxxVariantArray &WXUNUSED(metadata)) +{ + wxObject *O; + O = classInfo->CreateObject(); + m_data->SetObject(objectID, O); +} + +void wxRuntimeDepersister::CreateObject(int objectID, + const wxClassInfo *classInfo, + int paramCount, + wxxVariant *params, + int *objectIdValues, + const wxClassInfo **objectClassInfos , + wxxVariantArray &WXUNUSED(metadata)) +{ + wxObject *o; + o = m_data->GetObject(objectID); + for ( int i = 0 ; i < paramCount ; ++i ) + { + if ( objectIdValues[i] != wxInvalidObjectID ) + { + wxObject *o; + o = m_data->GetObject(objectIdValues[i]); + // if this is a dynamic object and we are asked for another class + // than wxDynamicObject we cast it down manually. + wxDynamicObject *dyno = dynamic_cast< wxDynamicObject * > (o) ; + if ( dyno!=NULL && (objectClassInfos[i] != dyno->GetClassInfo()) ) + { + o = dyno->GetSuperClassInstance() ; + } + params[i] = objectClassInfos[i]->InstanceToVariant(o) ; + } + } + classInfo->Create(o, paramCount, params); +} + +void wxRuntimeDepersister::ConstructObject(int objectID, + const wxClassInfo *classInfo, + int paramCount, + wxxVariant *params, + int *objectIdValues, + const wxClassInfo **objectClassInfos , + wxxVariantArray &WXUNUSED(metadata)) +{ + wxObject *o; + for ( int i = 0 ; i < paramCount ; ++i ) + { + if ( objectIdValues[i] != wxInvalidObjectID ) + { + wxObject *o; + o = m_data->GetObject(objectIdValues[i]); + // if this is a dynamic object and we are asked for another class + // than wxDynamicObject we cast it down manually. + wxDynamicObject *dyno = dynamic_cast< wxDynamicObject * > (o) ; + if ( dyno!=NULL && (objectClassInfos[i] != dyno->GetClassInfo()) ) + { + o = dyno->GetSuperClassInstance() ; + } + params[i] = objectClassInfos[i]->InstanceToVariant(o) ; + } + } + o = classInfo->ConstructObject(paramCount, params); + m_data->SetObject(objectID, o); +} + + +void wxRuntimeDepersister::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo)) +{ + wxObject *o; + o = m_data->GetObject(objectID); + delete o ; +} + +void wxRuntimeDepersister::SetProperty(int objectID, + const wxClassInfo *classInfo, + const wxPropertyInfo* propertyInfo, + const wxxVariant &value) +{ + wxObject *o; + o = m_data->GetObject(objectID); + classInfo->SetProperty( o , propertyInfo->GetName() , value ) ; +} + +void wxRuntimeDepersister::SetPropertyAsObject(int objectID, + const wxClassInfo *classInfo, + const wxPropertyInfo* propertyInfo, + int valueObjectId) +{ + wxObject *o, *valo; + o = m_data->GetObject(objectID); + valo = m_data->GetObject(valueObjectId); + const wxClassInfo* valClassInfo = (dynamic_cast(propertyInfo->GetTypeInfo()))->GetClassInfo() ; + // if this is a dynamic object and we are asked for another class + // than wxDynamicObject we cast it down manually. + wxDynamicObject *dynvalo = dynamic_cast< wxDynamicObject * > (valo) ; + if ( dynvalo!=NULL && (valClassInfo != dynvalo->GetClassInfo()) ) + { + valo = dynvalo->GetSuperClassInstance() ; + } + + classInfo->SetProperty( o , propertyInfo->GetName() , valClassInfo->InstanceToVariant(valo) ) ; +} + +void wxRuntimeDepersister::SetConnect(int eventSourceObjectID, + const wxClassInfo *WXUNUSED(eventSourceClassInfo), + const wxPropertyInfo *delegateInfo , + const wxClassInfo *WXUNUSED(eventSinkClassInfo) , + const wxHandlerInfo* handlerInfo , + int eventSinkObjectID ) +{ + wxEvtHandler *ehsource = dynamic_cast< wxEvtHandler* >( m_data->GetObject( eventSourceObjectID ) ) ; + wxEvtHandler *ehsink = dynamic_cast< wxEvtHandler *>(m_data->GetObject(eventSinkObjectID) ) ; + + if ( ehsource && ehsink ) + { + const wxDelegateTypeInfo *delegateTypeInfo = dynamic_cast(delegateInfo->GetTypeInfo()); + if( delegateTypeInfo && delegateTypeInfo->GetLastEventType() == -1 ) + { + ehsource->Connect( -1 , delegateTypeInfo->GetEventType() , + handlerInfo->GetEventFunction() , NULL /*user data*/ , + ehsink ) ; + } + else + { + for ( wxEventType iter = delegateTypeInfo->GetEventType() ; iter <= delegateTypeInfo->GetLastEventType() ; ++iter ) + { + ehsource->Connect( -1 , iter , + handlerInfo->GetEventFunction() , NULL /*user data*/ , + ehsink ) ; + } + } + } +} + +wxObject *wxRuntimeDepersister::GetObject(int objectID) +{ + return m_data->GetObject( objectID ) ; +} + +// adds an element to a property collection +void wxRuntimeDepersister::AddToPropertyCollection( int objectID , + const wxClassInfo *classInfo, + const wxPropertyInfo* propertyInfo , + const wxxVariant &value) +{ + wxObject *o; + o = m_data->GetObject(objectID); + classInfo->AddToPropertyCollection( o , propertyInfo->GetName() , value ) ; +} + +// sets the corresponding property (value is an object) +void wxRuntimeDepersister::AddToPropertyCollectionAsObject(int objectID, + const wxClassInfo *classInfo, + const wxPropertyInfo* propertyInfo , + int valueObjectId) +{ + wxObject *o, *valo; + o = m_data->GetObject(objectID); + valo = m_data->GetObject(valueObjectId); + const wxCollectionTypeInfo * collectionTypeInfo = dynamic_cast< const wxCollectionTypeInfo * >(propertyInfo->GetTypeInfo() ) ; + const wxClassInfo* valClassInfo = (dynamic_cast(collectionTypeInfo->GetElementType()))->GetClassInfo() ; + // if this is a dynamic object and we are asked for another class + // than wxDynamicObject we cast it down manually. + wxDynamicObject *dynvalo = dynamic_cast< wxDynamicObject * > (valo) ; + if ( dynvalo!=NULL && (valClassInfo != dynvalo->GetClassInfo()) ) + { + valo = dynvalo->GetSuperClassInstance() ; + } + + classInfo->AddToPropertyCollection( o , propertyInfo->GetName() , valClassInfo->InstanceToVariant(valo) ) ; +} + +// ---------------------------------------------------------------------------- +// depersisting to code +// ---------------------------------------------------------------------------- + +struct wxCodeDepersister::wxCodeDepersisterInternal +{ +#if wxUSE_UNICODE + map m_objectNames ; +#else + map m_objectNames ; +#endif + + void SetObjectName(int objectID, const wxString &name ) + { + if ( m_objectNames.find(objectID) != m_objectNames.end() ) + { + wxLogError( _("Passing a already registered object to SetObjectName") ) ; + return ; + } + m_objectNames[objectID] = (const wxChar *)name; + } + + wxString GetObjectName( int objectID ) + { + if ( objectID == wxNullObjectID ) + return wxT("NULL") ; + + if ( m_objectNames.find(objectID) == m_objectNames.end() ) + { + wxLogError( _("Passing an unkown object to GetObject") ) ; + return wxEmptyString ; + } + return wxString( m_objectNames[objectID].c_str() ) ; + } +} ; + +wxCodeDepersister::wxCodeDepersister(wxTextOutputStream *out) +: m_fp(out) +{ + m_data = new wxCodeDepersisterInternal ; +} + +wxCodeDepersister::~wxCodeDepersister() +{ + delete m_data ; +} + +void wxCodeDepersister::AllocateObject(int objectID, wxClassInfo *classInfo , + wxxVariantArray &WXUNUSED(metadata)) +{ + wxString objectName = wxString::Format( wxT("LocalObject_%d") , objectID ) ; + m_fp->WriteString( wxString::Format( wxT("\t%s *%s = new %s;\n"), + classInfo->GetClassName(), + objectName.c_str(), + classInfo->GetClassName()) ); + m_data->SetObjectName( objectID , objectName ) ; +} + +void wxCodeDepersister::DestroyObject(int objectID, wxClassInfo *WXUNUSED(classInfo)) +{ + m_fp->WriteString( wxString::Format( wxT("\tdelete %s;\n"), + m_data->GetObjectName( objectID).c_str() ) ); +} + +wxString wxCodeDepersister::ValueAsCode( const wxxVariant ¶m ) +{ + wxString value ; + const wxTypeInfo* type = param.GetTypeInfo() ; + if ( type->GetKind() == wxT_CUSTOM ) + { + const wxCustomTypeInfo* cti = dynamic_cast(type) ; + if ( cti ) + { + value.Printf( wxT("%s(%s)"), cti->GetTypeName().c_str(),param.GetAsString().c_str() ); + } + else + { + wxLogError ( _("Internal error, illegal wxCustomTypeInfo") ) ; + } + } + else if ( type->GetKind() == wxT_STRING ) + { + value.Printf( wxT("\"%s\""),param.GetAsString().c_str() ); + } + else + { + value.Printf( wxT("%s"), param.GetAsString().c_str() ); + } + return value ; +} + +void wxCodeDepersister::CreateObject(int objectID, + const wxClassInfo *WXUNUSED(classInfo), + int paramCount, + wxxVariant *params, + int *objectIDValues, + const wxClassInfo **WXUNUSED(objectClassInfos) , + wxxVariantArray &WXUNUSED(metadata) + ) +{ + int i; + m_fp->WriteString( wxString::Format( wxT("\t%s->Create("), m_data->GetObjectName(objectID).c_str() ) ); + for (i = 0; i < paramCount; i++) + { + if ( objectIDValues[i] != wxInvalidObjectID ) + m_fp->WriteString( wxString::Format( wxT("%s"), m_data->GetObjectName( objectIDValues[i] ).c_str() ) ); + else + { + m_fp->WriteString( wxString::Format( wxT("%s"), ValueAsCode(params[i]).c_str() ) ); + } + if (i < paramCount - 1) + m_fp->WriteString( wxT(", ")); + } + m_fp->WriteString( wxT(");\n") ); +} + +void wxCodeDepersister::ConstructObject(int objectID, + const wxClassInfo *classInfo, + int paramCount, + wxxVariant *params, + int *objectIDValues, + const wxClassInfo **WXUNUSED(objectClassInfos) , + wxxVariantArray &WXUNUSED(metadata) + ) +{ + wxString objectName = wxString::Format( wxT("LocalObject_%d") , objectID ) ; + m_fp->WriteString( wxString::Format( wxT("\t%s *%s = new %s("), + classInfo->GetClassName(), + objectName.c_str(), + classInfo->GetClassName()) ); + m_data->SetObjectName( objectID , objectName ) ; + + int i; + for (i = 0; i < paramCount; i++) + { + if ( objectIDValues[i] != wxInvalidObjectID ) + m_fp->WriteString( wxString::Format( wxT("%s"), m_data->GetObjectName( objectIDValues[i] ).c_str() ) ); + else + { + m_fp->WriteString( wxString::Format( wxT("%s"), ValueAsCode(params[i]).c_str() ) ); + } + if (i < paramCount - 1) + m_fp->WriteString( wxT(", ") ); + } + m_fp->WriteString( wxT(");\n") ); +} + +void wxCodeDepersister::SetProperty(int objectID, + const wxClassInfo *WXUNUSED(classInfo), + const wxPropertyInfo* propertyInfo, + const wxxVariant &value) +{ + m_fp->WriteString( wxString::Format( wxT("\t%s->%s(%s);\n"), + m_data->GetObjectName(objectID).c_str(), + propertyInfo->GetAccessor()->GetSetterName().c_str(), + ValueAsCode(value).c_str()) ); +} + +void wxCodeDepersister::SetPropertyAsObject(int objectID, + const wxClassInfo *WXUNUSED(classInfo), + const wxPropertyInfo* propertyInfo, + int valueObjectId) +{ + if ( propertyInfo->GetTypeInfo()->GetKind() == wxT_OBJECT ) + m_fp->WriteString( wxString::Format( wxT("\t%s->%s(*%s);\n"), + m_data->GetObjectName(objectID).c_str(), + propertyInfo->GetAccessor()->GetSetterName().c_str(), + m_data->GetObjectName( valueObjectId).c_str() ) ); + else + m_fp->WriteString( wxString::Format( wxT("\t%s->%s(%s);\n"), + m_data->GetObjectName(objectID).c_str(), + propertyInfo->GetAccessor()->GetSetterName().c_str(), + m_data->GetObjectName( valueObjectId).c_str() ) ); +} + +void wxCodeDepersister::AddToPropertyCollection( int objectID , + const wxClassInfo *WXUNUSED(classInfo), + const wxPropertyInfo* propertyInfo , + const wxxVariant &value) +{ + m_fp->WriteString( wxString::Format( wxT("\t%s->%s(%s);\n"), + m_data->GetObjectName(objectID).c_str(), + propertyInfo->GetAccessor()->GetAdderName().c_str(), + ValueAsCode(value).c_str()) ); +} + +// sets the corresponding property (value is an object) +void wxCodeDepersister::AddToPropertyCollectionAsObject(int WXUNUSED(objectID), + const wxClassInfo *WXUNUSED(classInfo), + const wxPropertyInfo* WXUNUSED(propertyInfo) , + int WXUNUSED(valueObjectId)) +{ + // TODO +} + +void wxCodeDepersister::SetConnect(int eventSourceObjectID, + const wxClassInfo *WXUNUSED(eventSourceClassInfo), + const wxPropertyInfo *delegateInfo , + const wxClassInfo *eventSinkClassInfo , + const wxHandlerInfo* handlerInfo , + int eventSinkObjectID ) +{ + wxString ehsource = m_data->GetObjectName( eventSourceObjectID ) ; + wxString ehsink = m_data->GetObjectName(eventSinkObjectID) ; + wxString ehsinkClass = eventSinkClassInfo->GetClassName() ; + const wxDelegateTypeInfo *delegateTypeInfo = dynamic_cast(delegateInfo->GetTypeInfo()); + if ( delegateTypeInfo ) + { + int eventType = delegateTypeInfo->GetEventType() ; + wxString handlerName = handlerInfo->GetName() ; + + m_fp->WriteString( wxString::Format( wxT("\t%s->Connect( %s->GetId() , %d , (wxObjectEventFunction)(wxEventFunction) & %s::%s , NULL , %s ) ;") , + ehsource.c_str() , ehsource.c_str() , eventType , ehsinkClass.c_str() , handlerName.c_str() , ehsink.c_str() ) ); + } + else + { + wxLogError(_("delegate has no type info")); + } +} + +#include "wx/arrimpl.cpp" + +WX_DEFINE_OBJARRAY(wxxVariantArray); + +#endif // wxUSE_EXTENDED_RTTI diff --git a/Source/3rd Party/wx/src/common/zipstrm.cpp b/Source/3rd Party/wx/src/common/zipstrm.cpp index 1cda3adce..a77df8dc8 100644 --- a/Source/3rd Party/wx/src/common/zipstrm.cpp +++ b/Source/3rd Party/wx/src/common/zipstrm.cpp @@ -1,2425 +1,2425 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: src/common/zipstrm.cpp -// Purpose: Streams for Zip files -// Author: Mike Wetherell -// RCS-ID: $Id: zipstrm.cpp 51009 2008-01-03 17:11:45Z MW $ -// Copyright: (c) Mike Wetherell -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ZIPSTREAM - -#include "wx/zipstrm.h" - -#ifndef WX_PRECOMP - #include "wx/hashmap.h" - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" -#endif - -#include "wx/datstrm.h" -#include "wx/zstream.h" -#include "wx/mstream.h" -#include "wx/ptr_scpd.h" -#include "wx/wfstream.h" -#include "zlib.h" - -// value for the 'version needed to extract' field (20 means 2.0) -enum { - VERSION_NEEDED_TO_EXTRACT = 20 -}; - -// signatures for the various records (PKxx) -enum { - CENTRAL_MAGIC = 0x02014b50, // central directory record - LOCAL_MAGIC = 0x04034b50, // local header - END_MAGIC = 0x06054b50, // end of central directory record - SUMS_MAGIC = 0x08074b50 // data descriptor (info-zip) -}; - -// unix file attributes. zip stores them in the high 16 bits of the -// 'external attributes' field, hence the extra zeros. -enum { - wxZIP_S_IFMT = 0xF0000000, - wxZIP_S_IFDIR = 0x40000000, - wxZIP_S_IFREG = 0x80000000 -}; - -// minimum sizes for the various records -enum { - CENTRAL_SIZE = 46, - LOCAL_SIZE = 30, - END_SIZE = 22, - SUMS_SIZE = 12 -}; - -// The number of bytes that must be written to an wxZipOutputStream before -// a zip entry is created. The purpose of this latency is so that -// OpenCompressor() can see a little data before deciding which compressor -// it should use. -enum { - OUTPUT_LATENCY = 4096 -}; - -// Some offsets into the local header -enum { - SUMS_OFFSET = 14 -}; - -IMPLEMENT_DYNAMIC_CLASS(wxZipEntry, wxArchiveEntry) -IMPLEMENT_DYNAMIC_CLASS(wxZipClassFactory, wxArchiveClassFactory) - - -///////////////////////////////////////////////////////////////////////////// -// Helpers - -// read a string of a given length -// -static wxString ReadString(wxInputStream& stream, wxUint16 len, wxMBConv& conv) -{ - if (len == 0) - return wxEmptyString; - -#if wxUSE_UNICODE - wxCharBuffer buf(len); - stream.Read(buf.data(), len); - wxString str(buf, conv); -#else - wxString str; - (void)conv; - { - wxStringBuffer buf(str, len); - stream.Read(buf, len); - } -#endif - - return str; -} - -// Decode a little endian wxUint32 number from a character array -// -static inline wxUint32 CrackUint32(const char *m) -{ - const unsigned char *n = (const unsigned char*)m; - return (n[3] << 24) | (n[2] << 16) | (n[1] << 8) | n[0]; -} - -// Decode a little endian wxUint16 number from a character array -// -static inline wxUint16 CrackUint16(const char *m) -{ - const unsigned char *n = (const unsigned char*)m; - return (n[1] << 8) | n[0]; -} - -// Temporarily lower the logging level in debug mode to avoid a warning -// from SeekI about seeking on a stream with data written back to it. -// -static wxFileOffset QuietSeek(wxInputStream& stream, wxFileOffset pos) -{ -#if defined(__WXDEBUG__) && wxUSE_LOG - wxLogLevel level = wxLog::GetLogLevel(); - wxLog::SetLogLevel(wxLOG_Debug - 1); - wxFileOffset result = stream.SeekI(pos); - wxLog::SetLogLevel(level); - return result; -#else - return stream.SeekI(pos); -#endif -} - - -///////////////////////////////////////////////////////////////////////////// -// Class factory - -wxZipClassFactory g_wxZipClassFactory; - -wxZipClassFactory::wxZipClassFactory() -{ - if (this == &g_wxZipClassFactory) - PushFront(); -} - -const wxChar * const * -wxZipClassFactory::GetProtocols(wxStreamProtocolType type) const -{ - static const wxChar *protocols[] = { _T("zip"), NULL }; - static const wxChar *mimetypes[] = { _T("application/zip"), NULL }; - static const wxChar *fileexts[] = { _T(".zip"), _T(".htb"), NULL }; - static const wxChar *empty[] = { NULL }; - - switch (type) { - case wxSTREAM_PROTOCOL: return protocols; - case wxSTREAM_MIMETYPE: return mimetypes; - case wxSTREAM_FILEEXT: return fileexts; - default: return empty; - } -} - - -///////////////////////////////////////////////////////////////////////////// -// Read a zip header - -class wxZipHeader -{ -public: - wxZipHeader(wxInputStream& stream, size_t size); - - inline wxUint8 Read8(); - inline wxUint16 Read16(); - inline wxUint32 Read32(); - - const char *GetData() const { return m_data; } - size_t GetSize() const { return m_size; } - operator bool() const { return m_ok; } - - size_t Seek(size_t pos) { m_pos = pos; return m_pos; } - size_t Skip(size_t size) { m_pos += size; return m_pos; } - - wxZipHeader& operator>>(wxUint8& n) { n = Read8(); return *this; } - wxZipHeader& operator>>(wxUint16& n) { n = Read16(); return *this; } - wxZipHeader& operator>>(wxUint32& n) { n = Read32(); return *this; } - -private: - char m_data[64]; - size_t m_size; - size_t m_pos; - bool m_ok; -}; - -wxZipHeader::wxZipHeader(wxInputStream& stream, size_t size) - : m_size(0), - m_pos(0), - m_ok(false) -{ - wxCHECK_RET(size <= sizeof(m_data), _T("buffer too small")); - m_size = stream.Read(m_data, size).LastRead(); - m_ok = m_size == size; -} - -inline wxUint8 wxZipHeader::Read8() -{ - wxASSERT(m_pos < m_size); - return m_data[m_pos++]; -} - -inline wxUint16 wxZipHeader::Read16() -{ - wxASSERT(m_pos + 2 <= m_size); - wxUint16 n = CrackUint16(m_data + m_pos); - m_pos += 2; - return n; -} - -inline wxUint32 wxZipHeader::Read32() -{ - wxASSERT(m_pos + 4 <= m_size); - wxUint32 n = CrackUint32(m_data + m_pos); - m_pos += 4; - return n; -} - - -///////////////////////////////////////////////////////////////////////////// -// Stored input stream -// Trival decompressor for files which are 'stored' in the zip file. - -class wxStoredInputStream : public wxFilterInputStream -{ -public: - wxStoredInputStream(wxInputStream& stream); - - void Open(wxFileOffset len) { Close(); m_len = len; } - void Close() { m_pos = 0; m_lasterror = wxSTREAM_NO_ERROR; } - - virtual char Peek() { return wxInputStream::Peek(); } - virtual wxFileOffset GetLength() const { return m_len; } - -protected: - virtual size_t OnSysRead(void *buffer, size_t size); - virtual wxFileOffset OnSysTell() const { return m_pos; } - -private: - wxFileOffset m_pos; - wxFileOffset m_len; - - DECLARE_NO_COPY_CLASS(wxStoredInputStream) -}; - -wxStoredInputStream::wxStoredInputStream(wxInputStream& stream) - : wxFilterInputStream(stream), - m_pos(0), - m_len(0) -{ -} - -size_t wxStoredInputStream::OnSysRead(void *buffer, size_t size) -{ - size_t count = wx_truncate_cast(size_t, - wxMin(size + wxFileOffset(0), m_len - m_pos + size_t(0))); - count = m_parent_i_stream->Read(buffer, count).LastRead(); - m_pos += count; - - if (count < size) - m_lasterror = m_pos == m_len ? wxSTREAM_EOF : wxSTREAM_READ_ERROR; - - return count; -} - - -///////////////////////////////////////////////////////////////////////////// -// Stored output stream -// Trival compressor for files which are 'stored' in the zip file. - -class wxStoredOutputStream : public wxFilterOutputStream -{ -public: - wxStoredOutputStream(wxOutputStream& stream) : - wxFilterOutputStream(stream), m_pos(0) { } - - bool Close() { - m_pos = 0; - m_lasterror = wxSTREAM_NO_ERROR; - return true; - } - -protected: - virtual size_t OnSysWrite(const void *buffer, size_t size); - virtual wxFileOffset OnSysTell() const { return m_pos; } - -private: - wxFileOffset m_pos; - DECLARE_NO_COPY_CLASS(wxStoredOutputStream) -}; - -size_t wxStoredOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - if (!IsOk() || !size) - return 0; - size_t count = m_parent_o_stream->Write(buffer, size).LastWrite(); - if (count != size) - m_lasterror = wxSTREAM_WRITE_ERROR; - m_pos += count; - return count; -} - - -///////////////////////////////////////////////////////////////////////////// -// wxRawInputStream -// -// Used to handle the unusal case of raw copying an entry of unknown -// length. This can only happen when the zip being copied from is being -// read from a non-seekable stream, and also was original written to a -// non-seekable stream. -// -// In this case there's no option but to decompress the stream to find -// it's length, but we can still write the raw compressed data to avoid the -// compression overhead (which is the greater one). -// -// Usage is like this: -// m_rawin = new wxRawInputStream(*m_parent_i_stream); -// m_decomp = m_rawin->Open(OpenDecompressor(m_rawin->GetTee())); -// -// The wxRawInputStream owns a wxTeeInputStream object, the role of which -// is something like the unix 'tee' command; it is a transparent filter, but -// allows the data read to be read a second time via an extra method 'GetData'. -// -// The wxRawInputStream then draws data through the tee using a decompressor -// then instead of returning the decompressed data, retuns the raw data -// from wxTeeInputStream::GetData(). - -class wxTeeInputStream : public wxFilterInputStream -{ -public: - wxTeeInputStream(wxInputStream& stream); - - size_t GetCount() const { return m_end - m_start; } - size_t GetData(char *buffer, size_t size); - - void Open(); - bool Final(); - - wxInputStream& Read(void *buffer, size_t size); - -protected: - virtual size_t OnSysRead(void *buffer, size_t size); - virtual wxFileOffset OnSysTell() const { return m_pos; } - -private: - wxFileOffset m_pos; - wxMemoryBuffer m_buf; - size_t m_start; - size_t m_end; - - DECLARE_NO_COPY_CLASS(wxTeeInputStream) -}; - -wxTeeInputStream::wxTeeInputStream(wxInputStream& stream) - : wxFilterInputStream(stream), - m_pos(0), m_buf(8192), m_start(0), m_end(0) -{ -} - -void wxTeeInputStream::Open() -{ - m_pos = m_start = m_end = 0; - m_lasterror = wxSTREAM_NO_ERROR; -} - -bool wxTeeInputStream::Final() -{ - bool final = m_end == m_buf.GetDataLen(); - m_end = m_buf.GetDataLen(); - return final; -} - -wxInputStream& wxTeeInputStream::Read(void *buffer, size_t size) -{ - size_t count = wxInputStream::Read(buffer, size).LastRead(); - m_end = m_buf.GetDataLen(); - m_buf.AppendData(buffer, count); - return *this; -} - -size_t wxTeeInputStream::OnSysRead(void *buffer, size_t size) -{ - size_t count = m_parent_i_stream->Read(buffer, size).LastRead(); - if (count < size) - m_lasterror = m_parent_i_stream->GetLastError(); - return count; -} - -size_t wxTeeInputStream::GetData(char *buffer, size_t size) -{ - if (m_wbacksize) { - size_t len = m_buf.GetDataLen(); - len = len > m_wbacksize ? len - m_wbacksize : 0; - m_buf.SetDataLen(len); - if (m_end > len) { - wxFAIL; // we've already returned data that's now being ungot - m_end = len; - } - m_parent_i_stream->Reset(); - m_parent_i_stream->Ungetch(m_wback, m_wbacksize); - free(m_wback); - m_wback = NULL; - m_wbacksize = 0; - m_wbackcur = 0; - } - - if (size > GetCount()) - size = GetCount(); - if (size) { - memcpy(buffer, m_buf + m_start, size); - m_start += size; - wxASSERT(m_start <= m_end); - } - - if (m_start == m_end && m_start > 0 && m_buf.GetDataLen() > 0) { - size_t len = m_buf.GetDataLen(); - char *buf = (char*)m_buf.GetWriteBuf(len); - len -= m_end; - memmove(buf, buf + m_end, len); - m_buf.UngetWriteBuf(len); - m_start = m_end = 0; - } - - return size; -} - -class wxRawInputStream : public wxFilterInputStream -{ -public: - wxRawInputStream(wxInputStream& stream); - virtual ~wxRawInputStream() { delete m_tee; } - - wxInputStream* Open(wxInputStream *decomp); - wxInputStream& GetTee() const { return *m_tee; } - -protected: - virtual size_t OnSysRead(void *buffer, size_t size); - virtual wxFileOffset OnSysTell() const { return m_pos; } - -private: - wxFileOffset m_pos; - wxTeeInputStream *m_tee; - - enum { BUFSIZE = 8192 }; - wxCharBuffer m_dummy; - - DECLARE_NO_COPY_CLASS(wxRawInputStream) -}; - -wxRawInputStream::wxRawInputStream(wxInputStream& stream) - : wxFilterInputStream(stream), - m_pos(0), - m_tee(new wxTeeInputStream(stream)), - m_dummy(BUFSIZE) -{ -} - -wxInputStream *wxRawInputStream::Open(wxInputStream *decomp) -{ - if (decomp) { - m_parent_i_stream = decomp; - m_pos = 0; - m_lasterror = wxSTREAM_NO_ERROR; - m_tee->Open(); - return this; - } else { - return NULL; - } -} - -size_t wxRawInputStream::OnSysRead(void *buffer, size_t size) -{ - char *buf = (char*)buffer; - size_t count = 0; - - while (count < size && IsOk()) - { - while (m_parent_i_stream->IsOk() && m_tee->GetCount() == 0) - m_parent_i_stream->Read(m_dummy.data(), BUFSIZE); - - size_t n = m_tee->GetData(buf + count, size - count); - count += n; - - if (n == 0 && m_tee->Final()) - m_lasterror = m_parent_i_stream->GetLastError(); - } - - m_pos += count; - return count; -} - - -///////////////////////////////////////////////////////////////////////////// -// Zlib streams than can be reused without recreating. - -class wxZlibOutputStream2 : public wxZlibOutputStream -{ -public: - wxZlibOutputStream2(wxOutputStream& stream, int level) : - wxZlibOutputStream(stream, level, wxZLIB_NO_HEADER) { } - - bool Open(wxOutputStream& stream); - bool Close() { DoFlush(true); m_pos = wxInvalidOffset; return IsOk(); } -}; - -bool wxZlibOutputStream2::Open(wxOutputStream& stream) -{ - wxCHECK(m_pos == wxInvalidOffset, false); - - m_deflate->next_out = m_z_buffer; - m_deflate->avail_out = m_z_size; - m_pos = 0; - m_lasterror = wxSTREAM_NO_ERROR; - m_parent_o_stream = &stream; - - if (deflateReset(m_deflate) != Z_OK) { - wxLogError(_("can't re-initialize zlib deflate stream")); - m_lasterror = wxSTREAM_WRITE_ERROR; - return false; - } - - return true; -} - -class wxZlibInputStream2 : public wxZlibInputStream -{ -public: - wxZlibInputStream2(wxInputStream& stream) : - wxZlibInputStream(stream, wxZLIB_NO_HEADER) { } - - bool Open(wxInputStream& stream); -}; - -bool wxZlibInputStream2::Open(wxInputStream& stream) -{ - m_inflate->avail_in = 0; - m_pos = 0; - m_lasterror = wxSTREAM_NO_ERROR; - m_parent_i_stream = &stream; - - if (inflateReset(m_inflate) != Z_OK) { - wxLogError(_("can't re-initialize zlib inflate stream")); - m_lasterror = wxSTREAM_READ_ERROR; - return false; - } - - return true; -} - - -///////////////////////////////////////////////////////////////////////////// -// Class to hold wxZipEntry's Extra and LocalExtra fields - -class wxZipMemory -{ -public: - wxZipMemory() : m_data(NULL), m_size(0), m_capacity(0), m_ref(1) { } - - wxZipMemory *AddRef() { m_ref++; return this; } - void Release() { if (--m_ref == 0) delete this; } - - char *GetData() const { return m_data; } - size_t GetSize() const { return m_size; } - size_t GetCapacity() const { return m_capacity; } - - wxZipMemory *Unique(size_t size); - -private: - ~wxZipMemory() { delete [] m_data; } - - char *m_data; - size_t m_size; - size_t m_capacity; - int m_ref; - - wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipMemory) -}; - -wxZipMemory *wxZipMemory::Unique(size_t size) -{ - wxZipMemory *zm; - - if (m_ref > 1) { - --m_ref; - zm = new wxZipMemory; - } else { - zm = this; - } - - if (zm->m_capacity < size) { - delete [] zm->m_data; - zm->m_data = new char[size]; - zm->m_capacity = size; - } - - zm->m_size = size; - return zm; -} - -static inline wxZipMemory *AddRef(wxZipMemory *zm) -{ - if (zm) - zm->AddRef(); - return zm; -} - -static inline void Release(wxZipMemory *zm) -{ - if (zm) - zm->Release(); -} - -static void Copy(wxZipMemory*& dest, wxZipMemory *src) -{ - Release(dest); - dest = AddRef(src); -} - -static void Unique(wxZipMemory*& zm, size_t size) -{ - if (!zm && size) - zm = new wxZipMemory; - if (zm) - zm = zm->Unique(size); -} - - -///////////////////////////////////////////////////////////////////////////// -// Collection of weak references to entries - -WX_DECLARE_HASH_MAP(long, wxZipEntry*, wxIntegerHash, - wxIntegerEqual, wxOffsetZipEntryMap_); - -class wxZipWeakLinks -{ -public: - wxZipWeakLinks() : m_ref(1) { } - - void Release(const wxZipInputStream* WXUNUSED(x)) - { if (--m_ref == 0) delete this; } - void Release(wxFileOffset key) - { RemoveEntry(key); if (--m_ref == 0) delete this; } - - wxZipWeakLinks *AddEntry(wxZipEntry *entry, wxFileOffset key); - void RemoveEntry(wxFileOffset key) - { m_entries.erase(wx_truncate_cast(key_type, key)); } - wxZipEntry *GetEntry(wxFileOffset key) const; - bool IsEmpty() const { return m_entries.empty(); } - -private: - ~wxZipWeakLinks() { wxASSERT(IsEmpty()); } - - typedef wxOffsetZipEntryMap_::key_type key_type; - - int m_ref; - wxOffsetZipEntryMap_ m_entries; - - wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipWeakLinks) -}; - -wxZipWeakLinks *wxZipWeakLinks::AddEntry(wxZipEntry *entry, wxFileOffset key) -{ - m_entries[wx_truncate_cast(key_type, key)] = entry; - m_ref++; - return this; -} - -wxZipEntry *wxZipWeakLinks::GetEntry(wxFileOffset key) const -{ - wxOffsetZipEntryMap_::const_iterator it = - m_entries.find(wx_truncate_cast(key_type, key)); - return it != m_entries.end() ? it->second : NULL; -} - - -///////////////////////////////////////////////////////////////////////////// -// ZipEntry - -wxZipEntry::wxZipEntry( - const wxString& name /*=wxEmptyString*/, - const wxDateTime& dt /*=wxDateTime::Now()*/, - wxFileOffset size /*=wxInvalidOffset*/) - : - m_SystemMadeBy(wxZIP_SYSTEM_MSDOS), - m_VersionMadeBy(wxMAJOR_VERSION * 10 + wxMINOR_VERSION), - m_VersionNeeded(VERSION_NEEDED_TO_EXTRACT), - m_Flags(0), - m_Method(wxZIP_METHOD_DEFAULT), - m_DateTime(dt), - m_Crc(0), - m_CompressedSize(wxInvalidOffset), - m_Size(size), - m_Key(wxInvalidOffset), - m_Offset(wxInvalidOffset), - m_DiskStart(0), - m_InternalAttributes(0), - m_ExternalAttributes(0), - m_Extra(NULL), - m_LocalExtra(NULL), - m_zipnotifier(NULL), - m_backlink(NULL) -{ - if (!name.empty()) - SetName(name); -} - -wxZipEntry::~wxZipEntry() -{ - if (m_backlink) - m_backlink->Release(m_Key); - Release(m_Extra); - Release(m_LocalExtra); -} - -wxZipEntry::wxZipEntry(const wxZipEntry& e) - : wxArchiveEntry(e), - m_SystemMadeBy(e.m_SystemMadeBy), - m_VersionMadeBy(e.m_VersionMadeBy), - m_VersionNeeded(e.m_VersionNeeded), - m_Flags(e.m_Flags), - m_Method(e.m_Method), - m_DateTime(e.m_DateTime), - m_Crc(e.m_Crc), - m_CompressedSize(e.m_CompressedSize), - m_Size(e.m_Size), - m_Name(e.m_Name), - m_Key(e.m_Key), - m_Offset(e.m_Offset), - m_Comment(e.m_Comment), - m_DiskStart(e.m_DiskStart), - m_InternalAttributes(e.m_InternalAttributes), - m_ExternalAttributes(e.m_ExternalAttributes), - m_Extra(AddRef(e.m_Extra)), - m_LocalExtra(AddRef(e.m_LocalExtra)), - m_zipnotifier(NULL), - m_backlink(NULL) -{ -} - -wxZipEntry& wxZipEntry::operator=(const wxZipEntry& e) -{ - if (&e != this) { - m_SystemMadeBy = e.m_SystemMadeBy; - m_VersionMadeBy = e.m_VersionMadeBy; - m_VersionNeeded = e.m_VersionNeeded; - m_Flags = e.m_Flags; - m_Method = e.m_Method; - m_DateTime = e.m_DateTime; - m_Crc = e.m_Crc; - m_CompressedSize = e.m_CompressedSize; - m_Size = e.m_Size; - m_Name = e.m_Name; - m_Key = e.m_Key; - m_Offset = e.m_Offset; - m_Comment = e.m_Comment; - m_DiskStart = e.m_DiskStart; - m_InternalAttributes = e.m_InternalAttributes; - m_ExternalAttributes = e.m_ExternalAttributes; - Copy(m_Extra, e.m_Extra); - Copy(m_LocalExtra, e.m_LocalExtra); - m_zipnotifier = NULL; - if (m_backlink) { - m_backlink->Release(m_Key); - m_backlink = NULL; - } - } - return *this; -} - -wxString wxZipEntry::GetName(wxPathFormat format /*=wxPATH_NATIVE*/) const -{ - bool isDir = IsDir() && !m_Name.empty(); - - // optimisations for common (and easy) cases - switch (wxFileName::GetFormat(format)) { - case wxPATH_DOS: - { - wxString name(isDir ? m_Name + _T("\\") : m_Name); - for (size_t i = 0; i < name.length(); i++) - if (name[i] == _T('/')) - name[i] = _T('\\'); - return name; - } - - case wxPATH_UNIX: - return isDir ? m_Name + _T("/") : m_Name; - - default: - ; - } - - wxFileName fn; - - if (isDir) - fn.AssignDir(m_Name, wxPATH_UNIX); - else - fn.Assign(m_Name, wxPATH_UNIX); - - return fn.GetFullPath(format); -} - -// Static - Internally tars and zips use forward slashes for the path -// separator, absolute paths aren't allowed, and directory names have a -// trailing slash. This function converts a path into this internal format, -// but without a trailing slash for a directory. -// -wxString wxZipEntry::GetInternalName(const wxString& name, - wxPathFormat format /*=wxPATH_NATIVE*/, - bool *pIsDir /*=NULL*/) -{ - wxString internal; - - if (wxFileName::GetFormat(format) != wxPATH_UNIX) - internal = wxFileName(name, format).GetFullPath(wxPATH_UNIX); - else - internal = name; - - bool isDir = !internal.empty() && internal.Last() == '/'; - if (pIsDir) - *pIsDir = isDir; - if (isDir) - internal.erase(internal.length() - 1); - - while (!internal.empty() && *internal.begin() == '/') - internal.erase(0, 1); - while (!internal.empty() && internal.compare(0, 2, _T("./")) == 0) - internal.erase(0, 2); - if (internal == _T(".") || internal == _T("..")) - internal = wxEmptyString; - - return internal; -} - -void wxZipEntry::SetSystemMadeBy(int system) -{ - int mode = GetMode(); - bool wasUnix = IsMadeByUnix(); - - m_SystemMadeBy = (wxUint8)system; - - if (!wasUnix && IsMadeByUnix()) { - SetIsDir(IsDir()); - SetMode(mode); - } else if (wasUnix && !IsMadeByUnix()) { - m_ExternalAttributes &= 0xffff; - } -} - -void wxZipEntry::SetIsDir(bool isDir /*=true*/) -{ - if (isDir) - m_ExternalAttributes |= wxZIP_A_SUBDIR; - else - m_ExternalAttributes &= ~wxZIP_A_SUBDIR; - - if (IsMadeByUnix()) { - m_ExternalAttributes &= ~wxZIP_S_IFMT; - if (isDir) - m_ExternalAttributes |= wxZIP_S_IFDIR; - else - m_ExternalAttributes |= wxZIP_S_IFREG; - } -} - -// Return unix style permission bits -// -int wxZipEntry::GetMode() const -{ - // return unix permissions if present - if (IsMadeByUnix()) - return (m_ExternalAttributes >> 16) & 0777; - - // otherwise synthesize from the dos attribs - int mode = 0644; - if (m_ExternalAttributes & wxZIP_A_RDONLY) - mode &= ~0200; - if (m_ExternalAttributes & wxZIP_A_SUBDIR) - mode |= 0111; - - return mode; -} - -// Set unix permissions -// -void wxZipEntry::SetMode(int mode) -{ - // Set dos attrib bits to be compatible - if (mode & 0222) - m_ExternalAttributes &= ~wxZIP_A_RDONLY; - else - m_ExternalAttributes |= wxZIP_A_RDONLY; - - // set the actual unix permission bits if the system type allows - if (IsMadeByUnix()) { - m_ExternalAttributes &= ~(0777L << 16); - m_ExternalAttributes |= (mode & 0777L) << 16; - } -} - -const char *wxZipEntry::GetExtra() const -{ - return m_Extra ? m_Extra->GetData() : NULL; -} - -size_t wxZipEntry::GetExtraLen() const -{ - return m_Extra ? m_Extra->GetSize() : 0; -} - -void wxZipEntry::SetExtra(const char *extra, size_t len) -{ - Unique(m_Extra, len); - if (len) - memcpy(m_Extra->GetData(), extra, len); -} - -const char *wxZipEntry::GetLocalExtra() const -{ - return m_LocalExtra ? m_LocalExtra->GetData() : NULL; -} - -size_t wxZipEntry::GetLocalExtraLen() const -{ - return m_LocalExtra ? m_LocalExtra->GetSize() : 0; -} - -void wxZipEntry::SetLocalExtra(const char *extra, size_t len) -{ - Unique(m_LocalExtra, len); - if (len) - memcpy(m_LocalExtra->GetData(), extra, len); -} - -void wxZipEntry::SetNotifier(wxZipNotifier& notifier) -{ - wxArchiveEntry::UnsetNotifier(); - m_zipnotifier = ¬ifier; - m_zipnotifier->OnEntryUpdated(*this); -} - -void wxZipEntry::Notify() -{ - if (m_zipnotifier) - m_zipnotifier->OnEntryUpdated(*this); - else if (GetNotifier()) - GetNotifier()->OnEntryUpdated(*this); -} - -void wxZipEntry::UnsetNotifier() -{ - wxArchiveEntry::UnsetNotifier(); - m_zipnotifier = NULL; -} - -size_t wxZipEntry::ReadLocal(wxInputStream& stream, wxMBConv& conv) -{ - wxUint16 nameLen, extraLen; - wxUint32 compressedSize, size, crc; - - wxZipHeader ds(stream, LOCAL_SIZE - 4); - if (!ds) - return 0; - - ds >> m_VersionNeeded >> m_Flags >> m_Method; - SetDateTime(wxDateTime().SetFromDOS(ds.Read32())); - ds >> crc >> compressedSize >> size >> nameLen >> extraLen; - - bool sumsValid = (m_Flags & wxZIP_SUMS_FOLLOW) == 0; - - if (sumsValid || crc) - m_Crc = crc; - if ((sumsValid || compressedSize) || m_Method == wxZIP_METHOD_STORE) - m_CompressedSize = compressedSize; - if ((sumsValid || size) || m_Method == wxZIP_METHOD_STORE) - m_Size = size; - - SetName(ReadString(stream, nameLen, conv), wxPATH_UNIX); - if (stream.LastRead() != nameLen + 0u) - return 0; - - if (extraLen || GetLocalExtraLen()) { - Unique(m_LocalExtra, extraLen); - if (extraLen) { - stream.Read(m_LocalExtra->GetData(), extraLen); - if (stream.LastRead() != extraLen + 0u) - return 0; - } - } - - return LOCAL_SIZE + nameLen + extraLen; -} - -size_t wxZipEntry::WriteLocal(wxOutputStream& stream, wxMBConv& conv) const -{ - wxString unixName = GetName(wxPATH_UNIX); - const wxWX2MBbuf name_buf = conv.cWX2MB(unixName); - const char *name = name_buf; - if (!name) name = ""; - wxUint16 nameLen = wx_truncate_cast(wxUint16, strlen(name)); - - wxDataOutputStream ds(stream); - - ds << m_VersionNeeded << m_Flags << m_Method; - ds.Write32(GetDateTime().GetAsDOS()); - - ds.Write32(m_Crc); - ds.Write32(m_CompressedSize != wxInvalidOffset ? - wx_truncate_cast(wxUint32, m_CompressedSize) : 0); - ds.Write32(m_Size != wxInvalidOffset ? - wx_truncate_cast(wxUint32, m_Size) : 0); - - ds << nameLen; - wxUint16 extraLen = wx_truncate_cast(wxUint16, GetLocalExtraLen()); - ds.Write16(extraLen); - - stream.Write(name, nameLen); - if (extraLen) - stream.Write(m_LocalExtra->GetData(), extraLen); - - return LOCAL_SIZE + nameLen + extraLen; -} - -size_t wxZipEntry::ReadCentral(wxInputStream& stream, wxMBConv& conv) -{ - wxUint16 nameLen, extraLen, commentLen; - - wxZipHeader ds(stream, CENTRAL_SIZE - 4); - if (!ds) - return 0; - - ds >> m_VersionMadeBy >> m_SystemMadeBy; - - SetVersionNeeded(ds.Read16()); - SetFlags(ds.Read16()); - SetMethod(ds.Read16()); - SetDateTime(wxDateTime().SetFromDOS(ds.Read32())); - SetCrc(ds.Read32()); - SetCompressedSize(ds.Read32()); - SetSize(ds.Read32()); - - ds >> nameLen >> extraLen >> commentLen - >> m_DiskStart >> m_InternalAttributes >> m_ExternalAttributes; - SetOffset(ds.Read32()); - - SetName(ReadString(stream, nameLen, conv), wxPATH_UNIX); - if (stream.LastRead() != nameLen + 0u) - return 0; - - if (extraLen || GetExtraLen()) { - Unique(m_Extra, extraLen); - if (extraLen) { - stream.Read(m_Extra->GetData(), extraLen); - if (stream.LastRead() != extraLen + 0u) - return 0; - } - } - - if (commentLen) { - m_Comment = ReadString(stream, commentLen, conv); - if (stream.LastRead() != commentLen + 0u) - return 0; - } else { - m_Comment.clear(); - } - - return CENTRAL_SIZE + nameLen + extraLen + commentLen; -} - -size_t wxZipEntry::WriteCentral(wxOutputStream& stream, wxMBConv& conv) const -{ - wxString unixName = GetName(wxPATH_UNIX); - const wxWX2MBbuf name_buf = conv.cWX2MB(unixName); - const char *name = name_buf; - if (!name) name = ""; - wxUint16 nameLen = wx_truncate_cast(wxUint16, strlen(name)); - - const wxWX2MBbuf comment_buf = conv.cWX2MB(m_Comment); - const char *comment = comment_buf; - if (!comment) comment = ""; - wxUint16 commentLen = wx_truncate_cast(wxUint16, strlen(comment)); - - wxUint16 extraLen = wx_truncate_cast(wxUint16, GetExtraLen()); - - wxDataOutputStream ds(stream); - - ds << CENTRAL_MAGIC << m_VersionMadeBy << m_SystemMadeBy; - - ds.Write16(wx_truncate_cast(wxUint16, GetVersionNeeded())); - ds.Write16(wx_truncate_cast(wxUint16, GetFlags())); - ds.Write16(wx_truncate_cast(wxUint16, GetMethod())); - ds.Write32(GetDateTime().GetAsDOS()); - ds.Write32(GetCrc()); - ds.Write32(wx_truncate_cast(wxUint32, GetCompressedSize())); - ds.Write32(wx_truncate_cast(wxUint32, GetSize())); - ds.Write16(nameLen); - ds.Write16(extraLen); - - ds << commentLen << m_DiskStart << m_InternalAttributes - << m_ExternalAttributes << wx_truncate_cast(wxUint32, GetOffset()); - - stream.Write(name, nameLen); - if (extraLen) - stream.Write(GetExtra(), extraLen); - stream.Write(comment, commentLen); - - return CENTRAL_SIZE + nameLen + extraLen + commentLen; -} - -// Info-zip prefixes this record with a signature, but pkzip doesn't. So if -// the 1st value is the signature then it is probably an info-zip record, -// though there is a small chance that it is in fact a pkzip record which -// happens to have the signature as it's CRC. -// -size_t wxZipEntry::ReadDescriptor(wxInputStream& stream) -{ - wxZipHeader ds(stream, SUMS_SIZE); - if (!ds) - return 0; - - m_Crc = ds.Read32(); - m_CompressedSize = ds.Read32(); - m_Size = ds.Read32(); - - // if 1st value is the signature then this is probably an info-zip record - if (m_Crc == SUMS_MAGIC) - { - wxZipHeader buf(stream, 8); - wxUint32 u1 = buf.GetSize() >= 4 ? buf.Read32() : (wxUint32)LOCAL_MAGIC; - wxUint32 u2 = buf.GetSize() == 8 ? buf.Read32() : 0; - - // look for the signature of the following record to decide which - if ((u1 == LOCAL_MAGIC || u1 == CENTRAL_MAGIC) && - (u2 != LOCAL_MAGIC && u2 != CENTRAL_MAGIC)) - { - // it's a pkzip style record after all! - if (buf.GetSize() > 0) - stream.Ungetch(buf.GetData(), buf.GetSize()); - } - else - { - // it's an info-zip record as expected - if (buf.GetSize() > 4) - stream.Ungetch(buf.GetData() + 4, buf.GetSize() - 4); - m_Crc = wx_truncate_cast(wxUint32, m_CompressedSize); - m_CompressedSize = m_Size; - m_Size = u1; - return SUMS_SIZE + 4; - } - } - - return SUMS_SIZE; -} - -size_t wxZipEntry::WriteDescriptor(wxOutputStream& stream, wxUint32 crc, - wxFileOffset compressedSize, wxFileOffset size) -{ - m_Crc = crc; - m_CompressedSize = compressedSize; - m_Size = size; - - wxDataOutputStream ds(stream); - - ds.Write32(crc); - ds.Write32(wx_truncate_cast(wxUint32, compressedSize)); - ds.Write32(wx_truncate_cast(wxUint32, size)); - - return SUMS_SIZE; -} - - -///////////////////////////////////////////////////////////////////////////// -// wxZipEndRec - holds the end of central directory record - -class wxZipEndRec -{ -public: - wxZipEndRec(); - - int GetDiskNumber() const { return m_DiskNumber; } - int GetStartDisk() const { return m_StartDisk; } - int GetEntriesHere() const { return m_EntriesHere; } - int GetTotalEntries() const { return m_TotalEntries; } - wxFileOffset GetSize() const { return m_Size; } - wxFileOffset GetOffset() const { return m_Offset; } - wxString GetComment() const { return m_Comment; } - - void SetDiskNumber(int num) - { m_DiskNumber = wx_truncate_cast(wxUint16, num); } - void SetStartDisk(int num) - { m_StartDisk = wx_truncate_cast(wxUint16, num); } - void SetEntriesHere(int num) - { m_EntriesHere = wx_truncate_cast(wxUint16, num); } - void SetTotalEntries(int num) - { m_TotalEntries = wx_truncate_cast(wxUint16, num); } - void SetSize(wxFileOffset size) - { m_Size = wx_truncate_cast(wxUint32, size); } - void SetOffset(wxFileOffset offset) - { m_Offset = wx_truncate_cast(wxUint32, offset); } - void SetComment(const wxString& comment) - { m_Comment = comment; } - - bool Read(wxInputStream& stream, wxMBConv& conv); - bool Write(wxOutputStream& stream, wxMBConv& conv) const; - -private: - wxUint16 m_DiskNumber; - wxUint16 m_StartDisk; - wxUint16 m_EntriesHere; - wxUint16 m_TotalEntries; - wxUint32 m_Size; - wxUint32 m_Offset; - wxString m_Comment; -}; - -wxZipEndRec::wxZipEndRec() - : m_DiskNumber(0), - m_StartDisk(0), - m_EntriesHere(0), - m_TotalEntries(0), - m_Size(0), - m_Offset(0) -{ -} - -bool wxZipEndRec::Write(wxOutputStream& stream, wxMBConv& conv) const -{ - const wxWX2MBbuf comment_buf = conv.cWX2MB(m_Comment); - const char *comment = comment_buf; - if (!comment) comment = ""; - wxUint16 commentLen = (wxUint16)strlen(comment); - - wxDataOutputStream ds(stream); - - ds << END_MAGIC << m_DiskNumber << m_StartDisk << m_EntriesHere - << m_TotalEntries << m_Size << m_Offset << commentLen; - - stream.Write(comment, commentLen); - - return stream.IsOk(); -} - -bool wxZipEndRec::Read(wxInputStream& stream, wxMBConv& conv) -{ - wxZipHeader ds(stream, END_SIZE - 4); - if (!ds) - return false; - - wxUint16 commentLen; - - ds >> m_DiskNumber >> m_StartDisk >> m_EntriesHere - >> m_TotalEntries >> m_Size >> m_Offset >> commentLen; - - if (commentLen) { - m_Comment = ReadString(stream, commentLen, conv); - if (stream.LastRead() != commentLen + 0u) - return false; - } - - if (m_DiskNumber != 0 || m_StartDisk != 0 || - m_EntriesHere != m_TotalEntries) - wxLogWarning(_("assuming this is a multi-part zip concatenated")); - - return true; -} - - -///////////////////////////////////////////////////////////////////////////// -// A weak link from an input stream to an output stream - -class wxZipStreamLink -{ -public: - wxZipStreamLink(wxZipOutputStream *stream) : m_ref(1), m_stream(stream) { } - - wxZipStreamLink *AddRef() { m_ref++; return this; } - wxZipOutputStream *GetOutputStream() const { return m_stream; } - - void Release(class wxZipInputStream *WXUNUSED(s)) - { if (--m_ref == 0) delete this; } - void Release(class wxZipOutputStream *WXUNUSED(s)) - { m_stream = NULL; if (--m_ref == 0) delete this; } - -private: - ~wxZipStreamLink() { } - - int m_ref; - wxZipOutputStream *m_stream; - - wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipStreamLink) -}; - - -///////////////////////////////////////////////////////////////////////////// -// Input stream - -// leave the default wxZipEntryPtr free for users -wxDECLARE_SCOPED_PTR(wxZipEntry, wxZipEntryPtr_) -wxDEFINE_SCOPED_PTR (wxZipEntry, wxZipEntryPtr_) - -// constructor -// -wxZipInputStream::wxZipInputStream(wxInputStream& stream, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveInputStream(stream, conv) -{ - Init(); -} - -wxZipInputStream::wxZipInputStream(wxInputStream *stream, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveInputStream(stream, conv) -{ - Init(); -} - -#if WXWIN_COMPATIBILITY_2_6 && wxUSE_FFILE - -// Part of the compatibility constructor, which has been made inline to -// avoid a problem with it not being exported by mingw 3.2.3 -// -void wxZipInputStream::Init(const wxString& file) -{ - // no error messages - wxLogNull nolog; - Init(); - m_allowSeeking = true; - wxFFileInputStream *ffile; - ffile = wx_static_cast(wxFFileInputStream*, m_parent_i_stream); - wxZipEntryPtr_ entry; - - if (ffile->Ok()) { - do { - entry.reset(GetNextEntry()); - } - while (entry.get() != NULL && entry->GetInternalName() != file); - } - - if (entry.get() == NULL) - m_lasterror = wxSTREAM_READ_ERROR; -} - -wxInputStream* wxZipInputStream::OpenFile(const wxString& archive) -{ - wxLogNull nolog; - return new wxFFileInputStream(archive); -} - -#endif // WXWIN_COMPATIBILITY_2_6 && wxUSE_FFILE - -void wxZipInputStream::Init() -{ - m_store = new wxStoredInputStream(*m_parent_i_stream); - m_inflate = NULL; - m_rawin = NULL; - m_raw = false; - m_headerSize = 0; - m_decomp = NULL; - m_parentSeekable = false; - m_weaklinks = new wxZipWeakLinks; - m_streamlink = NULL; - m_offsetAdjustment = 0; - m_position = wxInvalidOffset; - m_signature = 0; - m_TotalEntries = 0; - m_lasterror = m_parent_i_stream->GetLastError(); -#if WXWIN_COMPATIBILITY_2_6 - m_allowSeeking = false; -#endif -} - -wxZipInputStream::~wxZipInputStream() -{ - CloseDecompressor(m_decomp); - - delete m_store; - delete m_inflate; - delete m_rawin; - - m_weaklinks->Release(this); - - if (m_streamlink) - m_streamlink->Release(this); -} - -wxString wxZipInputStream::GetComment() -{ - if (m_position == wxInvalidOffset) - if (!LoadEndRecord()) - return wxEmptyString; - - if (!m_parentSeekable && Eof() && m_signature) { - m_lasterror = wxSTREAM_NO_ERROR; - m_lasterror = ReadLocal(true); - } - - return m_Comment; -} - -int wxZipInputStream::GetTotalEntries() -{ - if (m_position == wxInvalidOffset) - LoadEndRecord(); - return m_TotalEntries; -} - -wxZipStreamLink *wxZipInputStream::MakeLink(wxZipOutputStream *out) -{ - wxZipStreamLink *link = NULL; - - if (!m_parentSeekable && (IsOpened() || !Eof())) { - link = new wxZipStreamLink(out); - if (m_streamlink) - m_streamlink->Release(this); - m_streamlink = link->AddRef(); - } - - return link; -} - -bool wxZipInputStream::LoadEndRecord() -{ - wxCHECK(m_position == wxInvalidOffset, false); - if (!IsOk()) - return false; - - m_position = 0; - - // First find the end-of-central-directory record. - if (!FindEndRecord()) { - // failed, so either this is a non-seekable stream (ok), or not a zip - if (m_parentSeekable) { - m_lasterror = wxSTREAM_READ_ERROR; - wxLogError(_("invalid zip file")); - return false; - } - else { - wxLogNull nolog; - wxFileOffset pos = m_parent_i_stream->TellI(); - if (pos != wxInvalidOffset) - m_offsetAdjustment = m_position = pos; - return true; - } - } - - wxZipEndRec endrec; - - // Read in the end record - wxFileOffset endPos = m_parent_i_stream->TellI() - 4; - if (!endrec.Read(*m_parent_i_stream, GetConv())) - return false; - - m_TotalEntries = endrec.GetTotalEntries(); - m_Comment = endrec.GetComment(); - - // Now find the central-directory. we have the file offset of - // the CD, so look there first. - if (m_parent_i_stream->SeekI(endrec.GetOffset()) != wxInvalidOffset && - ReadSignature() == CENTRAL_MAGIC) { - m_signature = CENTRAL_MAGIC; - m_position = endrec.GetOffset(); - m_offsetAdjustment = 0; - return true; - } - - // If it's not there, then it could be that the zip has been appended - // to a self extractor, so take the CD size (also in endrec), subtract - // it from the file offset of the end-central-directory and look there. - if (m_parent_i_stream->SeekI(endPos - endrec.GetSize()) - != wxInvalidOffset && ReadSignature() == CENTRAL_MAGIC) { - m_signature = CENTRAL_MAGIC; - m_position = endPos - endrec.GetSize(); - m_offsetAdjustment = m_position - endrec.GetOffset(); - return true; - } - - wxLogError(_("can't find central directory in zip")); - m_lasterror = wxSTREAM_READ_ERROR; - return false; -} - -// Find the end-of-central-directory record. -// If found the stream will be positioned just past the 4 signature bytes. -// -bool wxZipInputStream::FindEndRecord() -{ - if (!m_parent_i_stream->IsSeekable()) - return false; - - // usually it's 22 bytes in size and the last thing in the file - { - wxLogNull nolog; - if (m_parent_i_stream->SeekI(-END_SIZE, wxFromEnd) == wxInvalidOffset) - return false; - } - - m_parentSeekable = true; - m_signature = 0; - char magic[4]; - if (m_parent_i_stream->Read(magic, 4).LastRead() != 4) - return false; - if ((m_signature = CrackUint32(magic)) == END_MAGIC) - return true; - - // unfortunately, the record has a comment field that can be up to 65535 - // bytes in length, so if the signature not found then search backwards. - wxFileOffset pos = m_parent_i_stream->TellI(); - const int BUFSIZE = 1024; - wxCharBuffer buf(BUFSIZE); - - memcpy(buf.data(), magic, 3); - wxFileOffset minpos = wxMax(pos - 65535L, 0); - - while (pos > minpos) { - size_t len = wx_truncate_cast(size_t, - pos - wxMax(pos - (BUFSIZE - 3), minpos)); - memcpy(buf.data() + len, buf, 3); - pos -= len; - - if (m_parent_i_stream->SeekI(pos, wxFromStart) == wxInvalidOffset || - m_parent_i_stream->Read(buf.data(), len).LastRead() != len) - return false; - - char *p = buf.data() + len; - - while (p-- > buf.data()) { - if ((m_signature = CrackUint32(p)) == END_MAGIC) { - size_t remainder = buf.data() + len - p; - if (remainder > 4) - m_parent_i_stream->Ungetch(p + 4, remainder - 4); - return true; - } - } - } - - return false; -} - -wxZipEntry *wxZipInputStream::GetNextEntry() -{ - if (m_position == wxInvalidOffset) - if (!LoadEndRecord()) - return NULL; - - m_lasterror = m_parentSeekable ? ReadCentral() : ReadLocal(); - if (!IsOk()) - return NULL; - - wxZipEntryPtr_ entry(new wxZipEntry(m_entry)); - entry->m_backlink = m_weaklinks->AddEntry(entry.get(), entry->GetKey()); - return entry.release(); -} - -wxStreamError wxZipInputStream::ReadCentral() -{ - if (!AtHeader()) - CloseEntry(); - - if (m_signature == END_MAGIC) - return wxSTREAM_EOF; - - if (m_signature != CENTRAL_MAGIC) { - wxLogError(_("error reading zip central directory")); - return wxSTREAM_READ_ERROR; - } - - if (QuietSeek(*m_parent_i_stream, m_position + 4) == wxInvalidOffset) - return wxSTREAM_READ_ERROR; - - size_t size = m_entry.ReadCentral(*m_parent_i_stream, GetConv()); - if (!size) { - m_signature = 0; - return wxSTREAM_READ_ERROR; - } - - m_position += size; - m_signature = ReadSignature(); - - if (m_offsetAdjustment) - m_entry.SetOffset(m_entry.GetOffset() + m_offsetAdjustment); - m_entry.SetKey(m_entry.GetOffset()); - - return wxSTREAM_NO_ERROR; -} - -wxStreamError wxZipInputStream::ReadLocal(bool readEndRec /*=false*/) -{ - if (!AtHeader()) - CloseEntry(); - - if (!m_signature) - m_signature = ReadSignature(); - - if (m_signature == CENTRAL_MAGIC || m_signature == END_MAGIC) { - if (m_streamlink && !m_streamlink->GetOutputStream()) { - m_streamlink->Release(this); - m_streamlink = NULL; - } - } - - while (m_signature == CENTRAL_MAGIC) { - if (m_weaklinks->IsEmpty() && m_streamlink == NULL) - return wxSTREAM_EOF; - - size_t size = m_entry.ReadCentral(*m_parent_i_stream, GetConv()); - m_position += size; - m_signature = 0; - if (!size) - return wxSTREAM_READ_ERROR; - - wxZipEntry *entry = m_weaklinks->GetEntry(m_entry.GetOffset()); - if (entry) { - entry->SetSystemMadeBy(m_entry.GetSystemMadeBy()); - entry->SetVersionMadeBy(m_entry.GetVersionMadeBy()); - entry->SetComment(m_entry.GetComment()); - entry->SetDiskStart(m_entry.GetDiskStart()); - entry->SetInternalAttributes(m_entry.GetInternalAttributes()); - entry->SetExternalAttributes(m_entry.GetExternalAttributes()); - Copy(entry->m_Extra, m_entry.m_Extra); - entry->Notify(); - m_weaklinks->RemoveEntry(entry->GetOffset()); - } - - m_signature = ReadSignature(); - } - - if (m_signature == END_MAGIC) { - if (readEndRec || m_streamlink) { - wxZipEndRec endrec; - endrec.Read(*m_parent_i_stream, GetConv()); - m_Comment = endrec.GetComment(); - m_signature = 0; - if (m_streamlink) { - m_streamlink->GetOutputStream()->SetComment(endrec.GetComment()); - m_streamlink->Release(this); - m_streamlink = NULL; - } - } - return wxSTREAM_EOF; - } - - if (m_signature == LOCAL_MAGIC) { - m_headerSize = m_entry.ReadLocal(*m_parent_i_stream, GetConv()); - m_signature = 0; - m_entry.SetOffset(m_position); - m_entry.SetKey(m_position); - - if (m_headerSize) { - m_TotalEntries++; - return wxSTREAM_NO_ERROR; - } - } - - wxLogError(_("error reading zip local header")); - return wxSTREAM_READ_ERROR; -} - -wxUint32 wxZipInputStream::ReadSignature() -{ - char magic[4]; - m_parent_i_stream->Read(magic, 4); - return m_parent_i_stream->LastRead() == 4 ? CrackUint32(magic) : 0; -} - -bool wxZipInputStream::OpenEntry(wxArchiveEntry& entry) -{ - wxZipEntry *zipEntry = wxStaticCast(&entry, wxZipEntry); - return zipEntry ? OpenEntry(*zipEntry) : false; -} - -// Open an entry -// -bool wxZipInputStream::DoOpen(wxZipEntry *entry, bool raw) -{ - if (m_position == wxInvalidOffset) - if (!LoadEndRecord()) - return false; - if (m_lasterror == wxSTREAM_READ_ERROR) - return false; - if (IsOpened()) - CloseEntry(); - - m_raw = raw; - - if (entry) { - if (AfterHeader() && entry->GetKey() == m_entry.GetOffset()) - return true; - // can only open the current entry on a non-seekable stream - wxCHECK(m_parentSeekable, false); - } - - m_lasterror = wxSTREAM_READ_ERROR; - - if (entry) - m_entry = *entry; - - if (m_parentSeekable) { - if (QuietSeek(*m_parent_i_stream, m_entry.GetOffset()) - == wxInvalidOffset) - return false; - if (ReadSignature() != LOCAL_MAGIC) { - wxLogError(_("bad zipfile offset to entry")); - return false; - } - } - - if (m_parentSeekable || AtHeader()) { - m_headerSize = m_entry.ReadLocal(*m_parent_i_stream, GetConv()); - if (m_headerSize && m_parentSeekable) { - wxZipEntry *ref = m_weaklinks->GetEntry(m_entry.GetKey()); - if (ref) { - Copy(ref->m_LocalExtra, m_entry.m_LocalExtra); - ref->Notify(); - m_weaklinks->RemoveEntry(ref->GetKey()); - } - if (entry && entry != ref) { - Copy(entry->m_LocalExtra, m_entry.m_LocalExtra); - entry->Notify(); - } - } - } - - if (m_headerSize) - m_lasterror = wxSTREAM_NO_ERROR; - return IsOk(); -} - -bool wxZipInputStream::OpenDecompressor(bool raw /*=false*/) -{ - wxASSERT(AfterHeader()); - - wxFileOffset compressedSize = m_entry.GetCompressedSize(); - - if (raw) - m_raw = true; - - if (m_raw) { - if (compressedSize != wxInvalidOffset) { - m_store->Open(compressedSize); - m_decomp = m_store; - } else { - if (!m_rawin) - m_rawin = new wxRawInputStream(*m_parent_i_stream); - m_decomp = m_rawin->Open(OpenDecompressor(m_rawin->GetTee())); - } - } else { - if (compressedSize != wxInvalidOffset && - (m_entry.GetMethod() != wxZIP_METHOD_DEFLATE || - wxZlibInputStream::CanHandleGZip())) { - m_store->Open(compressedSize); - m_decomp = OpenDecompressor(*m_store); - } else { - m_decomp = OpenDecompressor(*m_parent_i_stream); - } - } - - m_crcAccumulator = crc32(0, Z_NULL, 0); - m_lasterror = m_decomp ? m_decomp->GetLastError() : wxSTREAM_READ_ERROR; - return IsOk(); -} - -// Can be overriden to add support for additional decompression methods -// -wxInputStream *wxZipInputStream::OpenDecompressor(wxInputStream& stream) -{ - switch (m_entry.GetMethod()) { - case wxZIP_METHOD_STORE: - if (m_entry.GetSize() == wxInvalidOffset) { - wxLogError(_("stored file length not in Zip header")); - break; - } - m_store->Open(m_entry.GetSize()); - return m_store; - - case wxZIP_METHOD_DEFLATE: - if (!m_inflate) - m_inflate = new wxZlibInputStream2(stream); - else - m_inflate->Open(stream); - return m_inflate; - - default: - wxLogError(_("unsupported Zip compression method")); - } - - return NULL; -} - -bool wxZipInputStream::CloseDecompressor(wxInputStream *decomp) -{ - if (decomp && decomp == m_rawin) - return CloseDecompressor(m_rawin->GetFilterInputStream()); - if (decomp != m_store && decomp != m_inflate) - delete decomp; - return true; -} - -// Closes the current entry and positions the underlying stream at the start -// of the next entry -// -bool wxZipInputStream::CloseEntry() -{ - if (AtHeader()) - return true; - if (m_lasterror == wxSTREAM_READ_ERROR) - return false; - - if (!m_parentSeekable) { - if (!IsOpened() && !OpenDecompressor(true)) - return false; - - const int BUFSIZE = 8192; - wxCharBuffer buf(BUFSIZE); - while (IsOk()) - Read(buf.data(), BUFSIZE); - - m_position += m_headerSize + m_entry.GetCompressedSize(); - } - - if (m_lasterror == wxSTREAM_EOF) - m_lasterror = wxSTREAM_NO_ERROR; - - CloseDecompressor(m_decomp); - m_decomp = NULL; - m_entry = wxZipEntry(); - m_headerSize = 0; - m_raw = false; - - return IsOk(); -} - -size_t wxZipInputStream::OnSysRead(void *buffer, size_t size) -{ - if (!IsOpened()) - if ((AtHeader() && !DoOpen()) || !OpenDecompressor()) - m_lasterror = wxSTREAM_READ_ERROR; - if (!IsOk() || !size) - return 0; - - size_t count = m_decomp->Read(buffer, size).LastRead(); - if (!m_raw) - m_crcAccumulator = crc32(m_crcAccumulator, (Byte*)buffer, count); - if (count < size) - m_lasterror = m_decomp->GetLastError(); - - if (Eof()) { - if ((m_entry.GetFlags() & wxZIP_SUMS_FOLLOW) != 0) { - m_headerSize += m_entry.ReadDescriptor(*m_parent_i_stream); - wxZipEntry *entry = m_weaklinks->GetEntry(m_entry.GetKey()); - - if (entry) { - entry->SetCrc(m_entry.GetCrc()); - entry->SetCompressedSize(m_entry.GetCompressedSize()); - entry->SetSize(m_entry.GetSize()); - entry->Notify(); - } - } - - if (!m_raw) { - m_lasterror = wxSTREAM_READ_ERROR; - - if (m_entry.GetSize() != TellI()) - wxLogError(_("reading zip stream (entry %s): bad length"), - m_entry.GetName().c_str()); - else if (m_crcAccumulator != m_entry.GetCrc()) - wxLogError(_("reading zip stream (entry %s): bad crc"), - m_entry.GetName().c_str()); - else - m_lasterror = wxSTREAM_EOF; - } - } - - return count; -} - -#if WXWIN_COMPATIBILITY_2_6 - -// Borrowed from VS's zip stream (c) 1999 Vaclav Slavik -// -wxFileOffset wxZipInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) -{ - // seeking works when the stream is created with the compatibility - // constructor - if (!m_allowSeeking) - return wxInvalidOffset; - if (!IsOpened()) - if ((AtHeader() && !DoOpen()) || !OpenDecompressor()) - m_lasterror = wxSTREAM_READ_ERROR; - if (!IsOk()) - return wxInvalidOffset; - - // NB: since ZIP files don't natively support seeking, we have to - // implement a brute force workaround -- reading all the data - // between current and the new position (or between beginning of - // the file and new position...) - - wxFileOffset nextpos; - wxFileOffset pos = TellI(); - - switch ( mode ) - { - case wxFromCurrent : nextpos = seek + pos; break; - case wxFromStart : nextpos = seek; break; - case wxFromEnd : nextpos = GetLength() + seek; break; - default : nextpos = pos; break; /* just to fool compiler, never happens */ - } - - wxFileOffset toskip wxDUMMY_INITIALIZE(0); - if ( nextpos >= pos ) - { - toskip = nextpos - pos; - } - else - { - wxZipEntry current(m_entry); - if (!OpenEntry(current)) - { - m_lasterror = wxSTREAM_READ_ERROR; - return pos; - } - toskip = nextpos; - } - - if ( toskip > 0 ) - { - const int BUFSIZE = 4096; - size_t sz; - char buffer[BUFSIZE]; - while ( toskip > 0 ) - { - sz = wx_truncate_cast(size_t, wxMin(toskip, BUFSIZE)); - Read(buffer, sz); - toskip -= sz; - } - } - - pos = nextpos; - return pos; -} - -#endif // WXWIN_COMPATIBILITY_2_6 - - -///////////////////////////////////////////////////////////////////////////// -// Output stream - -#include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxZipEntryList_) - -wxZipOutputStream::wxZipOutputStream(wxOutputStream& stream, - int level /*=-1*/, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveOutputStream(stream, conv) -{ - Init(level); -} - -wxZipOutputStream::wxZipOutputStream(wxOutputStream *stream, - int level /*=-1*/, - wxMBConv& conv /*=wxConvLocal*/) - : wxArchiveOutputStream(stream, conv) -{ - Init(level); -} - -void wxZipOutputStream::Init(int level) -{ - m_store = new wxStoredOutputStream(*m_parent_o_stream); - m_deflate = NULL; - m_backlink = NULL; - m_initialData = new char[OUTPUT_LATENCY]; - m_initialSize = 0; - m_pending = NULL; - m_raw = false; - m_headerOffset = 0; - m_headerSize = 0; - m_entrySize = 0; - m_comp = NULL; - m_level = level; - m_offsetAdjustment = wxInvalidOffset; -} - -wxZipOutputStream::~wxZipOutputStream() -{ - Close(); - WX_CLEAR_LIST(wxZipEntryList_, m_entries); - delete m_store; - delete m_deflate; - delete m_pending; - delete [] m_initialData; - if (m_backlink) - m_backlink->Release(this); -} - -bool wxZipOutputStream::PutNextEntry( - const wxString& name, - const wxDateTime& dt /*=wxDateTime::Now()*/, - wxFileOffset size /*=wxInvalidOffset*/) -{ - return PutNextEntry(new wxZipEntry(name, dt, size)); -} - -bool wxZipOutputStream::PutNextDirEntry( - const wxString& name, - const wxDateTime& dt /*=wxDateTime::Now()*/) -{ - wxZipEntry *entry = new wxZipEntry(name, dt); - entry->SetIsDir(); - return PutNextEntry(entry); -} - -bool wxZipOutputStream::CopyEntry(wxZipEntry *entry, - wxZipInputStream& inputStream) -{ - wxZipEntryPtr_ e(entry); - - return - inputStream.DoOpen(e.get(), true) && - DoCreate(e.release(), true) && - Write(inputStream).IsOk() && inputStream.Eof(); -} - -bool wxZipOutputStream::PutNextEntry(wxArchiveEntry *entry) -{ - wxZipEntry *zipEntry = wxStaticCast(entry, wxZipEntry); - if (!zipEntry) - delete entry; - return PutNextEntry(zipEntry); -} - -bool wxZipOutputStream::CopyEntry(wxArchiveEntry *entry, - wxArchiveInputStream& stream) -{ - wxZipEntry *zipEntry = wxStaticCast(entry, wxZipEntry); - - if (!zipEntry || !stream.OpenEntry(*zipEntry)) { - delete entry; - return false; - } - - return CopyEntry(zipEntry, wx_static_cast(wxZipInputStream&, stream)); -} - -bool wxZipOutputStream::CopyArchiveMetaData(wxZipInputStream& inputStream) -{ - m_Comment = inputStream.GetComment(); - if (m_backlink) - m_backlink->Release(this); - m_backlink = inputStream.MakeLink(this); - return true; -} - -bool wxZipOutputStream::CopyArchiveMetaData(wxArchiveInputStream& stream) -{ - return CopyArchiveMetaData(wx_static_cast(wxZipInputStream&, stream)); -} - -void wxZipOutputStream::SetLevel(int level) -{ - if (level != m_level) { - if (m_comp != m_deflate) - delete m_deflate; - m_deflate = NULL; - m_level = level; - } -} - -bool wxZipOutputStream::DoCreate(wxZipEntry *entry, bool raw /*=false*/) -{ - CloseEntry(); - - m_pending = entry; - if (!m_pending) - return false; - - // write the signature bytes right away - wxDataOutputStream ds(*m_parent_o_stream); - ds << LOCAL_MAGIC; - - // and if this is the first entry test for seekability - if (m_headerOffset == 0 && m_parent_o_stream->IsSeekable()) { -#if wxUSE_LOG - bool logging = wxLog::IsEnabled(); - wxLogNull nolog; -#endif // wxUSE_LOG - wxFileOffset here = m_parent_o_stream->TellO(); - - if (here != wxInvalidOffset && here >= 4) { - if (m_parent_o_stream->SeekO(here - 4) == here - 4) { - m_offsetAdjustment = here - 4; -#if wxUSE_LOG - wxLog::EnableLogging(logging); -#endif // wxUSE_LOG - m_parent_o_stream->SeekO(here); - } - } - } - - m_pending->SetOffset(m_headerOffset); - - m_crcAccumulator = crc32(0, Z_NULL, 0); - - if (raw) - m_raw = true; - - m_lasterror = wxSTREAM_NO_ERROR; - return true; -} - -// Can be overriden to add support for additional compression methods -// -wxOutputStream *wxZipOutputStream::OpenCompressor( - wxOutputStream& stream, - wxZipEntry& entry, - const Buffer bufs[]) -{ - if (entry.GetMethod() == wxZIP_METHOD_DEFAULT) { - if (GetLevel() == 0 - && (IsParentSeekable() - || entry.GetCompressedSize() != wxInvalidOffset - || entry.GetSize() != wxInvalidOffset)) { - entry.SetMethod(wxZIP_METHOD_STORE); - } else { - int size = 0; - for (int i = 0; bufs[i].m_data; ++i) - size += bufs[i].m_size; - entry.SetMethod(size <= 6 ? - wxZIP_METHOD_STORE : wxZIP_METHOD_DEFLATE); - } - } - - switch (entry.GetMethod()) { - case wxZIP_METHOD_STORE: - if (entry.GetCompressedSize() == wxInvalidOffset) - entry.SetCompressedSize(entry.GetSize()); - return m_store; - - case wxZIP_METHOD_DEFLATE: - { - int defbits = wxZIP_DEFLATE_NORMAL; - switch (GetLevel()) { - case 0: case 1: - defbits = wxZIP_DEFLATE_SUPERFAST; - break; - case 2: case 3: case 4: - defbits = wxZIP_DEFLATE_FAST; - break; - case 8: case 9: - defbits = wxZIP_DEFLATE_EXTRA; - break; - } - entry.SetFlags((entry.GetFlags() & ~wxZIP_DEFLATE_MASK) | - defbits | wxZIP_SUMS_FOLLOW); - - if (!m_deflate) - m_deflate = new wxZlibOutputStream2(stream, GetLevel()); - else - m_deflate->Open(stream); - - return m_deflate; - } - - default: - wxLogError(_("unsupported Zip compression method")); - } - - return NULL; -} - -bool wxZipOutputStream::CloseCompressor(wxOutputStream *comp) -{ - if (comp == m_deflate) - m_deflate->Close(); - else if (comp != m_store) - delete comp; - return true; -} - -// This is called when OUPUT_LATENCY bytes has been written to the -// wxZipOutputStream to actually create the zip entry. -// -void wxZipOutputStream::CreatePendingEntry(const void *buffer, size_t size) -{ - wxASSERT(IsOk() && m_pending && !m_comp); - wxZipEntryPtr_ spPending(m_pending); - m_pending = NULL; - - Buffer bufs[] = { - { m_initialData, m_initialSize }, - { (const char*)buffer, size }, - { NULL, 0 } - }; - - if (m_raw) - m_comp = m_store; - else - m_comp = OpenCompressor(*m_store, *spPending, - m_initialSize ? bufs : bufs + 1); - - if (IsParentSeekable() - || (spPending->m_Crc - && spPending->m_CompressedSize != wxInvalidOffset - && spPending->m_Size != wxInvalidOffset)) - spPending->m_Flags &= ~wxZIP_SUMS_FOLLOW; - else - if (spPending->m_CompressedSize != wxInvalidOffset) - spPending->m_Flags |= wxZIP_SUMS_FOLLOW; - - m_headerSize = spPending->WriteLocal(*m_parent_o_stream, GetConv()); - m_lasterror = m_parent_o_stream->GetLastError(); - - if (IsOk()) { - m_entries.push_back(spPending.release()); - OnSysWrite(m_initialData, m_initialSize); - } - - m_initialSize = 0; -} - -// This is called to write out the zip entry when Close has been called -// before OUTPUT_LATENCY bytes has been written to the wxZipOutputStream. -// -void wxZipOutputStream::CreatePendingEntry() -{ - wxASSERT(IsOk() && m_pending && !m_comp); - wxZipEntryPtr_ spPending(m_pending); - m_pending = NULL; - m_lasterror = wxSTREAM_WRITE_ERROR; - - if (!m_raw) { - // Initially compresses the data to memory, then fall back to 'store' - // if the compressor makes the data larger rather than smaller. - wxMemoryOutputStream mem; - Buffer bufs[] = { { m_initialData, m_initialSize }, { NULL, 0 } }; - wxOutputStream *comp = OpenCompressor(mem, *spPending, bufs); - - if (!comp) - return; - if (comp != m_store) { - bool ok = comp->Write(m_initialData, m_initialSize).IsOk(); - CloseCompressor(comp); - if (!ok) - return; - } - - m_entrySize = m_initialSize; - m_crcAccumulator = crc32(0, (Byte*)m_initialData, m_initialSize); - - if (mem.GetSize() > 0 && mem.GetSize() < m_initialSize) { - m_initialSize = mem.GetSize(); - mem.CopyTo(m_initialData, m_initialSize); - } else { - spPending->SetMethod(wxZIP_METHOD_STORE); - } - - spPending->SetSize(m_entrySize); - spPending->SetCrc(m_crcAccumulator); - spPending->SetCompressedSize(m_initialSize); - } - - spPending->m_Flags &= ~wxZIP_SUMS_FOLLOW; - m_headerSize = spPending->WriteLocal(*m_parent_o_stream, GetConv()); - - if (m_parent_o_stream->IsOk()) { - m_entries.push_back(spPending.release()); - m_comp = m_store; - m_store->Write(m_initialData, m_initialSize); - } - - m_initialSize = 0; - m_lasterror = m_parent_o_stream->GetLastError(); -} - -// Write the 'central directory' and the 'end-central-directory' records. -// -bool wxZipOutputStream::Close() -{ - CloseEntry(); - - if (m_lasterror == wxSTREAM_WRITE_ERROR || m_entries.size() == 0) { - wxFilterOutputStream::Close(); - return false; - } - - wxZipEndRec endrec; - - endrec.SetEntriesHere(m_entries.size()); - endrec.SetTotalEntries(m_entries.size()); - endrec.SetOffset(m_headerOffset); - endrec.SetComment(m_Comment); - - wxZipEntryList_::iterator it; - wxFileOffset size = 0; - - for (it = m_entries.begin(); it != m_entries.end(); ++it) { - size += (*it)->WriteCentral(*m_parent_o_stream, GetConv()); - delete *it; - } - m_entries.clear(); - - endrec.SetSize(size); - endrec.Write(*m_parent_o_stream, GetConv()); - - m_lasterror = m_parent_o_stream->GetLastError(); - - if (!wxFilterOutputStream::Close() || !IsOk()) - return false; - m_lasterror = wxSTREAM_EOF; - return true; -} - -// Finish writing the current entry -// -bool wxZipOutputStream::CloseEntry() -{ - if (IsOk() && m_pending) - CreatePendingEntry(); - if (!IsOk()) - return false; - if (!m_comp) - return true; - - CloseCompressor(m_comp); - m_comp = NULL; - - wxFileOffset compressedSize = m_store->TellO(); - - wxZipEntry& entry = *m_entries.back(); - - // When writing raw the crc and size can't be checked - if (m_raw) { - m_crcAccumulator = entry.GetCrc(); - m_entrySize = entry.GetSize(); - } - - // Write the sums in the trailing 'data descriptor' if necessary - if (entry.m_Flags & wxZIP_SUMS_FOLLOW) { - wxASSERT(!IsParentSeekable()); - m_headerOffset += - entry.WriteDescriptor(*m_parent_o_stream, m_crcAccumulator, - compressedSize, m_entrySize); - m_lasterror = m_parent_o_stream->GetLastError(); - } - - // If the local header didn't have the correct crc and size written to - // it then seek back and fix it - else if (m_crcAccumulator != entry.GetCrc() - || m_entrySize != entry.GetSize() - || compressedSize != entry.GetCompressedSize()) - { - if (IsParentSeekable()) { - wxFileOffset here = m_parent_o_stream->TellO(); - wxFileOffset headerOffset = m_headerOffset + m_offsetAdjustment; - m_parent_o_stream->SeekO(headerOffset + SUMS_OFFSET); - entry.WriteDescriptor(*m_parent_o_stream, m_crcAccumulator, - compressedSize, m_entrySize); - m_parent_o_stream->SeekO(here); - m_lasterror = m_parent_o_stream->GetLastError(); - } else { - m_lasterror = wxSTREAM_WRITE_ERROR; - } - } - - m_headerOffset += m_headerSize + compressedSize; - m_headerSize = 0; - m_entrySize = 0; - m_store->Close(); - m_raw = false; - - if (IsOk()) - m_lasterror = m_parent_o_stream->GetLastError(); - else - wxLogError(_("error writing zip entry '%s': bad crc or length"), - entry.GetName().c_str()); - return IsOk(); -} - -void wxZipOutputStream::Sync() -{ - if (IsOk() && m_pending) - CreatePendingEntry(NULL, 0); - if (!m_comp) - m_lasterror = wxSTREAM_WRITE_ERROR; - if (IsOk()) { - m_comp->Sync(); - m_lasterror = m_comp->GetLastError(); - } -} - -size_t wxZipOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - if (IsOk() && m_pending) { - if (m_initialSize + size < OUTPUT_LATENCY) { - memcpy(m_initialData + m_initialSize, buffer, size); - m_initialSize += size; - return size; - } else { - CreatePendingEntry(buffer, size); - } - } - - if (!m_comp) - m_lasterror = wxSTREAM_WRITE_ERROR; - if (!IsOk() || !size) - return 0; - - if (m_comp->Write(buffer, size).LastWrite() != size) - m_lasterror = wxSTREAM_WRITE_ERROR; - m_crcAccumulator = crc32(m_crcAccumulator, (Byte*)buffer, size); - m_entrySize += m_comp->LastWrite(); - - return m_comp->LastWrite(); -} - -#endif // wxUSE_ZIPSTREAM +///////////////////////////////////////////////////////////////////////////// +// Name: src/common/zipstrm.cpp +// Purpose: Streams for Zip files +// Author: Mike Wetherell +// RCS-ID: $Id: zipstrm.cpp 51009 2008-01-03 17:11:45Z MW $ +// Copyright: (c) Mike Wetherell +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ZIPSTREAM + +#include "wx/zipstrm.h" + +#ifndef WX_PRECOMP + #include "wx/hashmap.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" +#endif + +#include "wx/datstrm.h" +#include "wx/zstream.h" +#include "wx/mstream.h" +#include "wx/ptr_scpd.h" +#include "wx/wfstream.h" +#include "zlib.h" + +// value for the 'version needed to extract' field (20 means 2.0) +enum { + VERSION_NEEDED_TO_EXTRACT = 20 +}; + +// signatures for the various records (PKxx) +enum { + CENTRAL_MAGIC = 0x02014b50, // central directory record + LOCAL_MAGIC = 0x04034b50, // local header + END_MAGIC = 0x06054b50, // end of central directory record + SUMS_MAGIC = 0x08074b50 // data descriptor (info-zip) +}; + +// unix file attributes. zip stores them in the high 16 bits of the +// 'external attributes' field, hence the extra zeros. +enum { + wxZIP_S_IFMT = 0xF0000000, + wxZIP_S_IFDIR = 0x40000000, + wxZIP_S_IFREG = 0x80000000 +}; + +// minimum sizes for the various records +enum { + CENTRAL_SIZE = 46, + LOCAL_SIZE = 30, + END_SIZE = 22, + SUMS_SIZE = 12 +}; + +// The number of bytes that must be written to an wxZipOutputStream before +// a zip entry is created. The purpose of this latency is so that +// OpenCompressor() can see a little data before deciding which compressor +// it should use. +enum { + OUTPUT_LATENCY = 4096 +}; + +// Some offsets into the local header +enum { + SUMS_OFFSET = 14 +}; + +IMPLEMENT_DYNAMIC_CLASS(wxZipEntry, wxArchiveEntry) +IMPLEMENT_DYNAMIC_CLASS(wxZipClassFactory, wxArchiveClassFactory) + + +///////////////////////////////////////////////////////////////////////////// +// Helpers + +// read a string of a given length +// +static wxString ReadString(wxInputStream& stream, wxUint16 len, wxMBConv& conv) +{ + if (len == 0) + return wxEmptyString; + +#if wxUSE_UNICODE + wxCharBuffer buf(len); + stream.Read(buf.data(), len); + wxString str(buf, conv); +#else + wxString str; + (void)conv; + { + wxStringBuffer buf(str, len); + stream.Read(buf, len); + } +#endif + + return str; +} + +// Decode a little endian wxUint32 number from a character array +// +static inline wxUint32 CrackUint32(const char *m) +{ + const unsigned char *n = (const unsigned char*)m; + return (n[3] << 24) | (n[2] << 16) | (n[1] << 8) | n[0]; +} + +// Decode a little endian wxUint16 number from a character array +// +static inline wxUint16 CrackUint16(const char *m) +{ + const unsigned char *n = (const unsigned char*)m; + return (n[1] << 8) | n[0]; +} + +// Temporarily lower the logging level in debug mode to avoid a warning +// from SeekI about seeking on a stream with data written back to it. +// +static wxFileOffset QuietSeek(wxInputStream& stream, wxFileOffset pos) +{ +#if defined(__WXDEBUG__) && wxUSE_LOG + wxLogLevel level = wxLog::GetLogLevel(); + wxLog::SetLogLevel(wxLOG_Debug - 1); + wxFileOffset result = stream.SeekI(pos); + wxLog::SetLogLevel(level); + return result; +#else + return stream.SeekI(pos); +#endif +} + + +///////////////////////////////////////////////////////////////////////////// +// Class factory + +wxZipClassFactory g_wxZipClassFactory; + +wxZipClassFactory::wxZipClassFactory() +{ + if (this == &g_wxZipClassFactory) + PushFront(); +} + +const wxChar * const * +wxZipClassFactory::GetProtocols(wxStreamProtocolType type) const +{ + static const wxChar *protocols[] = { _T("zip"), NULL }; + static const wxChar *mimetypes[] = { _T("application/zip"), NULL }; + static const wxChar *fileexts[] = { _T(".zip"), _T(".htb"), NULL }; + static const wxChar *empty[] = { NULL }; + + switch (type) { + case wxSTREAM_PROTOCOL: return protocols; + case wxSTREAM_MIMETYPE: return mimetypes; + case wxSTREAM_FILEEXT: return fileexts; + default: return empty; + } +} + + +///////////////////////////////////////////////////////////////////////////// +// Read a zip header + +class wxZipHeader +{ +public: + wxZipHeader(wxInputStream& stream, size_t size); + + inline wxUint8 Read8(); + inline wxUint16 Read16(); + inline wxUint32 Read32(); + + const char *GetData() const { return m_data; } + size_t GetSize() const { return m_size; } + operator bool() const { return m_ok; } + + size_t Seek(size_t pos) { m_pos = pos; return m_pos; } + size_t Skip(size_t size) { m_pos += size; return m_pos; } + + wxZipHeader& operator>>(wxUint8& n) { n = Read8(); return *this; } + wxZipHeader& operator>>(wxUint16& n) { n = Read16(); return *this; } + wxZipHeader& operator>>(wxUint32& n) { n = Read32(); return *this; } + +private: + char m_data[64]; + size_t m_size; + size_t m_pos; + bool m_ok; +}; + +wxZipHeader::wxZipHeader(wxInputStream& stream, size_t size) + : m_size(0), + m_pos(0), + m_ok(false) +{ + wxCHECK_RET(size <= sizeof(m_data), _T("buffer too small")); + m_size = stream.Read(m_data, size).LastRead(); + m_ok = m_size == size; +} + +inline wxUint8 wxZipHeader::Read8() +{ + wxASSERT(m_pos < m_size); + return m_data[m_pos++]; +} + +inline wxUint16 wxZipHeader::Read16() +{ + wxASSERT(m_pos + 2 <= m_size); + wxUint16 n = CrackUint16(m_data + m_pos); + m_pos += 2; + return n; +} + +inline wxUint32 wxZipHeader::Read32() +{ + wxASSERT(m_pos + 4 <= m_size); + wxUint32 n = CrackUint32(m_data + m_pos); + m_pos += 4; + return n; +} + + +///////////////////////////////////////////////////////////////////////////// +// Stored input stream +// Trival decompressor for files which are 'stored' in the zip file. + +class wxStoredInputStream : public wxFilterInputStream +{ +public: + wxStoredInputStream(wxInputStream& stream); + + void Open(wxFileOffset len) { Close(); m_len = len; } + void Close() { m_pos = 0; m_lasterror = wxSTREAM_NO_ERROR; } + + virtual char Peek() { return wxInputStream::Peek(); } + virtual wxFileOffset GetLength() const { return m_len; } + +protected: + virtual size_t OnSysRead(void *buffer, size_t size); + virtual wxFileOffset OnSysTell() const { return m_pos; } + +private: + wxFileOffset m_pos; + wxFileOffset m_len; + + DECLARE_NO_COPY_CLASS(wxStoredInputStream) +}; + +wxStoredInputStream::wxStoredInputStream(wxInputStream& stream) + : wxFilterInputStream(stream), + m_pos(0), + m_len(0) +{ +} + +size_t wxStoredInputStream::OnSysRead(void *buffer, size_t size) +{ + size_t count = wx_truncate_cast(size_t, + wxMin(size + wxFileOffset(0), m_len - m_pos + size_t(0))); + count = m_parent_i_stream->Read(buffer, count).LastRead(); + m_pos += count; + + if (count < size) + m_lasterror = m_pos == m_len ? wxSTREAM_EOF : wxSTREAM_READ_ERROR; + + return count; +} + + +///////////////////////////////////////////////////////////////////////////// +// Stored output stream +// Trival compressor for files which are 'stored' in the zip file. + +class wxStoredOutputStream : public wxFilterOutputStream +{ +public: + wxStoredOutputStream(wxOutputStream& stream) : + wxFilterOutputStream(stream), m_pos(0) { } + + bool Close() { + m_pos = 0; + m_lasterror = wxSTREAM_NO_ERROR; + return true; + } + +protected: + virtual size_t OnSysWrite(const void *buffer, size_t size); + virtual wxFileOffset OnSysTell() const { return m_pos; } + +private: + wxFileOffset m_pos; + DECLARE_NO_COPY_CLASS(wxStoredOutputStream) +}; + +size_t wxStoredOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + if (!IsOk() || !size) + return 0; + size_t count = m_parent_o_stream->Write(buffer, size).LastWrite(); + if (count != size) + m_lasterror = wxSTREAM_WRITE_ERROR; + m_pos += count; + return count; +} + + +///////////////////////////////////////////////////////////////////////////// +// wxRawInputStream +// +// Used to handle the unusal case of raw copying an entry of unknown +// length. This can only happen when the zip being copied from is being +// read from a non-seekable stream, and also was original written to a +// non-seekable stream. +// +// In this case there's no option but to decompress the stream to find +// it's length, but we can still write the raw compressed data to avoid the +// compression overhead (which is the greater one). +// +// Usage is like this: +// m_rawin = new wxRawInputStream(*m_parent_i_stream); +// m_decomp = m_rawin->Open(OpenDecompressor(m_rawin->GetTee())); +// +// The wxRawInputStream owns a wxTeeInputStream object, the role of which +// is something like the unix 'tee' command; it is a transparent filter, but +// allows the data read to be read a second time via an extra method 'GetData'. +// +// The wxRawInputStream then draws data through the tee using a decompressor +// then instead of returning the decompressed data, retuns the raw data +// from wxTeeInputStream::GetData(). + +class wxTeeInputStream : public wxFilterInputStream +{ +public: + wxTeeInputStream(wxInputStream& stream); + + size_t GetCount() const { return m_end - m_start; } + size_t GetData(char *buffer, size_t size); + + void Open(); + bool Final(); + + wxInputStream& Read(void *buffer, size_t size); + +protected: + virtual size_t OnSysRead(void *buffer, size_t size); + virtual wxFileOffset OnSysTell() const { return m_pos; } + +private: + wxFileOffset m_pos; + wxMemoryBuffer m_buf; + size_t m_start; + size_t m_end; + + DECLARE_NO_COPY_CLASS(wxTeeInputStream) +}; + +wxTeeInputStream::wxTeeInputStream(wxInputStream& stream) + : wxFilterInputStream(stream), + m_pos(0), m_buf(8192), m_start(0), m_end(0) +{ +} + +void wxTeeInputStream::Open() +{ + m_pos = m_start = m_end = 0; + m_lasterror = wxSTREAM_NO_ERROR; +} + +bool wxTeeInputStream::Final() +{ + bool final = m_end == m_buf.GetDataLen(); + m_end = m_buf.GetDataLen(); + return final; +} + +wxInputStream& wxTeeInputStream::Read(void *buffer, size_t size) +{ + size_t count = wxInputStream::Read(buffer, size).LastRead(); + m_end = m_buf.GetDataLen(); + m_buf.AppendData(buffer, count); + return *this; +} + +size_t wxTeeInputStream::OnSysRead(void *buffer, size_t size) +{ + size_t count = m_parent_i_stream->Read(buffer, size).LastRead(); + if (count < size) + m_lasterror = m_parent_i_stream->GetLastError(); + return count; +} + +size_t wxTeeInputStream::GetData(char *buffer, size_t size) +{ + if (m_wbacksize) { + size_t len = m_buf.GetDataLen(); + len = len > m_wbacksize ? len - m_wbacksize : 0; + m_buf.SetDataLen(len); + if (m_end > len) { + wxFAIL; // we've already returned data that's now being ungot + m_end = len; + } + m_parent_i_stream->Reset(); + m_parent_i_stream->Ungetch(m_wback, m_wbacksize); + free(m_wback); + m_wback = NULL; + m_wbacksize = 0; + m_wbackcur = 0; + } + + if (size > GetCount()) + size = GetCount(); + if (size) { + memcpy(buffer, m_buf + m_start, size); + m_start += size; + wxASSERT(m_start <= m_end); + } + + if (m_start == m_end && m_start > 0 && m_buf.GetDataLen() > 0) { + size_t len = m_buf.GetDataLen(); + char *buf = (char*)m_buf.GetWriteBuf(len); + len -= m_end; + memmove(buf, buf + m_end, len); + m_buf.UngetWriteBuf(len); + m_start = m_end = 0; + } + + return size; +} + +class wxRawInputStream : public wxFilterInputStream +{ +public: + wxRawInputStream(wxInputStream& stream); + virtual ~wxRawInputStream() { delete m_tee; } + + wxInputStream* Open(wxInputStream *decomp); + wxInputStream& GetTee() const { return *m_tee; } + +protected: + virtual size_t OnSysRead(void *buffer, size_t size); + virtual wxFileOffset OnSysTell() const { return m_pos; } + +private: + wxFileOffset m_pos; + wxTeeInputStream *m_tee; + + enum { BUFSIZE = 8192 }; + wxCharBuffer m_dummy; + + DECLARE_NO_COPY_CLASS(wxRawInputStream) +}; + +wxRawInputStream::wxRawInputStream(wxInputStream& stream) + : wxFilterInputStream(stream), + m_pos(0), + m_tee(new wxTeeInputStream(stream)), + m_dummy(BUFSIZE) +{ +} + +wxInputStream *wxRawInputStream::Open(wxInputStream *decomp) +{ + if (decomp) { + m_parent_i_stream = decomp; + m_pos = 0; + m_lasterror = wxSTREAM_NO_ERROR; + m_tee->Open(); + return this; + } else { + return NULL; + } +} + +size_t wxRawInputStream::OnSysRead(void *buffer, size_t size) +{ + char *buf = (char*)buffer; + size_t count = 0; + + while (count < size && IsOk()) + { + while (m_parent_i_stream->IsOk() && m_tee->GetCount() == 0) + m_parent_i_stream->Read(m_dummy.data(), BUFSIZE); + + size_t n = m_tee->GetData(buf + count, size - count); + count += n; + + if (n == 0 && m_tee->Final()) + m_lasterror = m_parent_i_stream->GetLastError(); + } + + m_pos += count; + return count; +} + + +///////////////////////////////////////////////////////////////////////////// +// Zlib streams than can be reused without recreating. + +class wxZlibOutputStream2 : public wxZlibOutputStream +{ +public: + wxZlibOutputStream2(wxOutputStream& stream, int level) : + wxZlibOutputStream(stream, level, wxZLIB_NO_HEADER) { } + + bool Open(wxOutputStream& stream); + bool Close() { DoFlush(true); m_pos = wxInvalidOffset; return IsOk(); } +}; + +bool wxZlibOutputStream2::Open(wxOutputStream& stream) +{ + wxCHECK(m_pos == wxInvalidOffset, false); + + m_deflate->next_out = m_z_buffer; + m_deflate->avail_out = m_z_size; + m_pos = 0; + m_lasterror = wxSTREAM_NO_ERROR; + m_parent_o_stream = &stream; + + if (deflateReset(m_deflate) != Z_OK) { + wxLogError(_("can't re-initialize zlib deflate stream")); + m_lasterror = wxSTREAM_WRITE_ERROR; + return false; + } + + return true; +} + +class wxZlibInputStream2 : public wxZlibInputStream +{ +public: + wxZlibInputStream2(wxInputStream& stream) : + wxZlibInputStream(stream, wxZLIB_NO_HEADER) { } + + bool Open(wxInputStream& stream); +}; + +bool wxZlibInputStream2::Open(wxInputStream& stream) +{ + m_inflate->avail_in = 0; + m_pos = 0; + m_lasterror = wxSTREAM_NO_ERROR; + m_parent_i_stream = &stream; + + if (inflateReset(m_inflate) != Z_OK) { + wxLogError(_("can't re-initialize zlib inflate stream")); + m_lasterror = wxSTREAM_READ_ERROR; + return false; + } + + return true; +} + + +///////////////////////////////////////////////////////////////////////////// +// Class to hold wxZipEntry's Extra and LocalExtra fields + +class wxZipMemory +{ +public: + wxZipMemory() : m_data(NULL), m_size(0), m_capacity(0), m_ref(1) { } + + wxZipMemory *AddRef() { m_ref++; return this; } + void Release() { if (--m_ref == 0) delete this; } + + char *GetData() const { return m_data; } + size_t GetSize() const { return m_size; } + size_t GetCapacity() const { return m_capacity; } + + wxZipMemory *Unique(size_t size); + +private: + ~wxZipMemory() { delete [] m_data; } + + char *m_data; + size_t m_size; + size_t m_capacity; + int m_ref; + + wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipMemory) +}; + +wxZipMemory *wxZipMemory::Unique(size_t size) +{ + wxZipMemory *zm; + + if (m_ref > 1) { + --m_ref; + zm = new wxZipMemory; + } else { + zm = this; + } + + if (zm->m_capacity < size) { + delete [] zm->m_data; + zm->m_data = new char[size]; + zm->m_capacity = size; + } + + zm->m_size = size; + return zm; +} + +static inline wxZipMemory *AddRef(wxZipMemory *zm) +{ + if (zm) + zm->AddRef(); + return zm; +} + +static inline void Release(wxZipMemory *zm) +{ + if (zm) + zm->Release(); +} + +static void Copy(wxZipMemory*& dest, wxZipMemory *src) +{ + Release(dest); + dest = AddRef(src); +} + +static void Unique(wxZipMemory*& zm, size_t size) +{ + if (!zm && size) + zm = new wxZipMemory; + if (zm) + zm = zm->Unique(size); +} + + +///////////////////////////////////////////////////////////////////////////// +// Collection of weak references to entries + +WX_DECLARE_HASH_MAP(long, wxZipEntry*, wxIntegerHash, + wxIntegerEqual, wxOffsetZipEntryMap_); + +class wxZipWeakLinks +{ +public: + wxZipWeakLinks() : m_ref(1) { } + + void Release(const wxZipInputStream* WXUNUSED(x)) + { if (--m_ref == 0) delete this; } + void Release(wxFileOffset key) + { RemoveEntry(key); if (--m_ref == 0) delete this; } + + wxZipWeakLinks *AddEntry(wxZipEntry *entry, wxFileOffset key); + void RemoveEntry(wxFileOffset key) + { m_entries.erase(wx_truncate_cast(key_type, key)); } + wxZipEntry *GetEntry(wxFileOffset key) const; + bool IsEmpty() const { return m_entries.empty(); } + +private: + ~wxZipWeakLinks() { wxASSERT(IsEmpty()); } + + typedef wxOffsetZipEntryMap_::key_type key_type; + + int m_ref; + wxOffsetZipEntryMap_ m_entries; + + wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipWeakLinks) +}; + +wxZipWeakLinks *wxZipWeakLinks::AddEntry(wxZipEntry *entry, wxFileOffset key) +{ + m_entries[wx_truncate_cast(key_type, key)] = entry; + m_ref++; + return this; +} + +wxZipEntry *wxZipWeakLinks::GetEntry(wxFileOffset key) const +{ + wxOffsetZipEntryMap_::const_iterator it = + m_entries.find(wx_truncate_cast(key_type, key)); + return it != m_entries.end() ? it->second : NULL; +} + + +///////////////////////////////////////////////////////////////////////////// +// ZipEntry + +wxZipEntry::wxZipEntry( + const wxString& name /*=wxEmptyString*/, + const wxDateTime& dt /*=wxDateTime::Now()*/, + wxFileOffset size /*=wxInvalidOffset*/) + : + m_SystemMadeBy(wxZIP_SYSTEM_MSDOS), + m_VersionMadeBy(wxMAJOR_VERSION * 10 + wxMINOR_VERSION), + m_VersionNeeded(VERSION_NEEDED_TO_EXTRACT), + m_Flags(0), + m_Method(wxZIP_METHOD_DEFAULT), + m_DateTime(dt), + m_Crc(0), + m_CompressedSize(wxInvalidOffset), + m_Size(size), + m_Key(wxInvalidOffset), + m_Offset(wxInvalidOffset), + m_DiskStart(0), + m_InternalAttributes(0), + m_ExternalAttributes(0), + m_Extra(NULL), + m_LocalExtra(NULL), + m_zipnotifier(NULL), + m_backlink(NULL) +{ + if (!name.empty()) + SetName(name); +} + +wxZipEntry::~wxZipEntry() +{ + if (m_backlink) + m_backlink->Release(m_Key); + Release(m_Extra); + Release(m_LocalExtra); +} + +wxZipEntry::wxZipEntry(const wxZipEntry& e) + : wxArchiveEntry(e), + m_SystemMadeBy(e.m_SystemMadeBy), + m_VersionMadeBy(e.m_VersionMadeBy), + m_VersionNeeded(e.m_VersionNeeded), + m_Flags(e.m_Flags), + m_Method(e.m_Method), + m_DateTime(e.m_DateTime), + m_Crc(e.m_Crc), + m_CompressedSize(e.m_CompressedSize), + m_Size(e.m_Size), + m_Name(e.m_Name), + m_Key(e.m_Key), + m_Offset(e.m_Offset), + m_Comment(e.m_Comment), + m_DiskStart(e.m_DiskStart), + m_InternalAttributes(e.m_InternalAttributes), + m_ExternalAttributes(e.m_ExternalAttributes), + m_Extra(AddRef(e.m_Extra)), + m_LocalExtra(AddRef(e.m_LocalExtra)), + m_zipnotifier(NULL), + m_backlink(NULL) +{ +} + +wxZipEntry& wxZipEntry::operator=(const wxZipEntry& e) +{ + if (&e != this) { + m_SystemMadeBy = e.m_SystemMadeBy; + m_VersionMadeBy = e.m_VersionMadeBy; + m_VersionNeeded = e.m_VersionNeeded; + m_Flags = e.m_Flags; + m_Method = e.m_Method; + m_DateTime = e.m_DateTime; + m_Crc = e.m_Crc; + m_CompressedSize = e.m_CompressedSize; + m_Size = e.m_Size; + m_Name = e.m_Name; + m_Key = e.m_Key; + m_Offset = e.m_Offset; + m_Comment = e.m_Comment; + m_DiskStart = e.m_DiskStart; + m_InternalAttributes = e.m_InternalAttributes; + m_ExternalAttributes = e.m_ExternalAttributes; + Copy(m_Extra, e.m_Extra); + Copy(m_LocalExtra, e.m_LocalExtra); + m_zipnotifier = NULL; + if (m_backlink) { + m_backlink->Release(m_Key); + m_backlink = NULL; + } + } + return *this; +} + +wxString wxZipEntry::GetName(wxPathFormat format /*=wxPATH_NATIVE*/) const +{ + bool isDir = IsDir() && !m_Name.empty(); + + // optimisations for common (and easy) cases + switch (wxFileName::GetFormat(format)) { + case wxPATH_DOS: + { + wxString name(isDir ? m_Name + _T("\\") : m_Name); + for (size_t i = 0; i < name.length(); i++) + if (name[i] == _T('/')) + name[i] = _T('\\'); + return name; + } + + case wxPATH_UNIX: + return isDir ? m_Name + _T("/") : m_Name; + + default: + ; + } + + wxFileName fn; + + if (isDir) + fn.AssignDir(m_Name, wxPATH_UNIX); + else + fn.Assign(m_Name, wxPATH_UNIX); + + return fn.GetFullPath(format); +} + +// Static - Internally tars and zips use forward slashes for the path +// separator, absolute paths aren't allowed, and directory names have a +// trailing slash. This function converts a path into this internal format, +// but without a trailing slash for a directory. +// +wxString wxZipEntry::GetInternalName(const wxString& name, + wxPathFormat format /*=wxPATH_NATIVE*/, + bool *pIsDir /*=NULL*/) +{ + wxString internal; + + if (wxFileName::GetFormat(format) != wxPATH_UNIX) + internal = wxFileName(name, format).GetFullPath(wxPATH_UNIX); + else + internal = name; + + bool isDir = !internal.empty() && internal.Last() == '/'; + if (pIsDir) + *pIsDir = isDir; + if (isDir) + internal.erase(internal.length() - 1); + + while (!internal.empty() && *internal.begin() == '/') + internal.erase(0, 1); + while (!internal.empty() && internal.compare(0, 2, _T("./")) == 0) + internal.erase(0, 2); + if (internal == _T(".") || internal == _T("..")) + internal = wxEmptyString; + + return internal; +} + +void wxZipEntry::SetSystemMadeBy(int system) +{ + int mode = GetMode(); + bool wasUnix = IsMadeByUnix(); + + m_SystemMadeBy = (wxUint8)system; + + if (!wasUnix && IsMadeByUnix()) { + SetIsDir(IsDir()); + SetMode(mode); + } else if (wasUnix && !IsMadeByUnix()) { + m_ExternalAttributes &= 0xffff; + } +} + +void wxZipEntry::SetIsDir(bool isDir /*=true*/) +{ + if (isDir) + m_ExternalAttributes |= wxZIP_A_SUBDIR; + else + m_ExternalAttributes &= ~wxZIP_A_SUBDIR; + + if (IsMadeByUnix()) { + m_ExternalAttributes &= ~wxZIP_S_IFMT; + if (isDir) + m_ExternalAttributes |= wxZIP_S_IFDIR; + else + m_ExternalAttributes |= wxZIP_S_IFREG; + } +} + +// Return unix style permission bits +// +int wxZipEntry::GetMode() const +{ + // return unix permissions if present + if (IsMadeByUnix()) + return (m_ExternalAttributes >> 16) & 0777; + + // otherwise synthesize from the dos attribs + int mode = 0644; + if (m_ExternalAttributes & wxZIP_A_RDONLY) + mode &= ~0200; + if (m_ExternalAttributes & wxZIP_A_SUBDIR) + mode |= 0111; + + return mode; +} + +// Set unix permissions +// +void wxZipEntry::SetMode(int mode) +{ + // Set dos attrib bits to be compatible + if (mode & 0222) + m_ExternalAttributes &= ~wxZIP_A_RDONLY; + else + m_ExternalAttributes |= wxZIP_A_RDONLY; + + // set the actual unix permission bits if the system type allows + if (IsMadeByUnix()) { + m_ExternalAttributes &= ~(0777L << 16); + m_ExternalAttributes |= (mode & 0777L) << 16; + } +} + +const char *wxZipEntry::GetExtra() const +{ + return m_Extra ? m_Extra->GetData() : NULL; +} + +size_t wxZipEntry::GetExtraLen() const +{ + return m_Extra ? m_Extra->GetSize() : 0; +} + +void wxZipEntry::SetExtra(const char *extra, size_t len) +{ + Unique(m_Extra, len); + if (len) + memcpy(m_Extra->GetData(), extra, len); +} + +const char *wxZipEntry::GetLocalExtra() const +{ + return m_LocalExtra ? m_LocalExtra->GetData() : NULL; +} + +size_t wxZipEntry::GetLocalExtraLen() const +{ + return m_LocalExtra ? m_LocalExtra->GetSize() : 0; +} + +void wxZipEntry::SetLocalExtra(const char *extra, size_t len) +{ + Unique(m_LocalExtra, len); + if (len) + memcpy(m_LocalExtra->GetData(), extra, len); +} + +void wxZipEntry::SetNotifier(wxZipNotifier& notifier) +{ + wxArchiveEntry::UnsetNotifier(); + m_zipnotifier = ¬ifier; + m_zipnotifier->OnEntryUpdated(*this); +} + +void wxZipEntry::Notify() +{ + if (m_zipnotifier) + m_zipnotifier->OnEntryUpdated(*this); + else if (GetNotifier()) + GetNotifier()->OnEntryUpdated(*this); +} + +void wxZipEntry::UnsetNotifier() +{ + wxArchiveEntry::UnsetNotifier(); + m_zipnotifier = NULL; +} + +size_t wxZipEntry::ReadLocal(wxInputStream& stream, wxMBConv& conv) +{ + wxUint16 nameLen, extraLen; + wxUint32 compressedSize, size, crc; + + wxZipHeader ds(stream, LOCAL_SIZE - 4); + if (!ds) + return 0; + + ds >> m_VersionNeeded >> m_Flags >> m_Method; + SetDateTime(wxDateTime().SetFromDOS(ds.Read32())); + ds >> crc >> compressedSize >> size >> nameLen >> extraLen; + + bool sumsValid = (m_Flags & wxZIP_SUMS_FOLLOW) == 0; + + if (sumsValid || crc) + m_Crc = crc; + if ((sumsValid || compressedSize) || m_Method == wxZIP_METHOD_STORE) + m_CompressedSize = compressedSize; + if ((sumsValid || size) || m_Method == wxZIP_METHOD_STORE) + m_Size = size; + + SetName(ReadString(stream, nameLen, conv), wxPATH_UNIX); + if (stream.LastRead() != nameLen + 0u) + return 0; + + if (extraLen || GetLocalExtraLen()) { + Unique(m_LocalExtra, extraLen); + if (extraLen) { + stream.Read(m_LocalExtra->GetData(), extraLen); + if (stream.LastRead() != extraLen + 0u) + return 0; + } + } + + return LOCAL_SIZE + nameLen + extraLen; +} + +size_t wxZipEntry::WriteLocal(wxOutputStream& stream, wxMBConv& conv) const +{ + wxString unixName = GetName(wxPATH_UNIX); + const wxWX2MBbuf name_buf = conv.cWX2MB(unixName); + const char *name = name_buf; + if (!name) name = ""; + wxUint16 nameLen = wx_truncate_cast(wxUint16, strlen(name)); + + wxDataOutputStream ds(stream); + + ds << m_VersionNeeded << m_Flags << m_Method; + ds.Write32(GetDateTime().GetAsDOS()); + + ds.Write32(m_Crc); + ds.Write32(m_CompressedSize != wxInvalidOffset ? + wx_truncate_cast(wxUint32, m_CompressedSize) : 0); + ds.Write32(m_Size != wxInvalidOffset ? + wx_truncate_cast(wxUint32, m_Size) : 0); + + ds << nameLen; + wxUint16 extraLen = wx_truncate_cast(wxUint16, GetLocalExtraLen()); + ds.Write16(extraLen); + + stream.Write(name, nameLen); + if (extraLen) + stream.Write(m_LocalExtra->GetData(), extraLen); + + return LOCAL_SIZE + nameLen + extraLen; +} + +size_t wxZipEntry::ReadCentral(wxInputStream& stream, wxMBConv& conv) +{ + wxUint16 nameLen, extraLen, commentLen; + + wxZipHeader ds(stream, CENTRAL_SIZE - 4); + if (!ds) + return 0; + + ds >> m_VersionMadeBy >> m_SystemMadeBy; + + SetVersionNeeded(ds.Read16()); + SetFlags(ds.Read16()); + SetMethod(ds.Read16()); + SetDateTime(wxDateTime().SetFromDOS(ds.Read32())); + SetCrc(ds.Read32()); + SetCompressedSize(ds.Read32()); + SetSize(ds.Read32()); + + ds >> nameLen >> extraLen >> commentLen + >> m_DiskStart >> m_InternalAttributes >> m_ExternalAttributes; + SetOffset(ds.Read32()); + + SetName(ReadString(stream, nameLen, conv), wxPATH_UNIX); + if (stream.LastRead() != nameLen + 0u) + return 0; + + if (extraLen || GetExtraLen()) { + Unique(m_Extra, extraLen); + if (extraLen) { + stream.Read(m_Extra->GetData(), extraLen); + if (stream.LastRead() != extraLen + 0u) + return 0; + } + } + + if (commentLen) { + m_Comment = ReadString(stream, commentLen, conv); + if (stream.LastRead() != commentLen + 0u) + return 0; + } else { + m_Comment.clear(); + } + + return CENTRAL_SIZE + nameLen + extraLen + commentLen; +} + +size_t wxZipEntry::WriteCentral(wxOutputStream& stream, wxMBConv& conv) const +{ + wxString unixName = GetName(wxPATH_UNIX); + const wxWX2MBbuf name_buf = conv.cWX2MB(unixName); + const char *name = name_buf; + if (!name) name = ""; + wxUint16 nameLen = wx_truncate_cast(wxUint16, strlen(name)); + + const wxWX2MBbuf comment_buf = conv.cWX2MB(m_Comment); + const char *comment = comment_buf; + if (!comment) comment = ""; + wxUint16 commentLen = wx_truncate_cast(wxUint16, strlen(comment)); + + wxUint16 extraLen = wx_truncate_cast(wxUint16, GetExtraLen()); + + wxDataOutputStream ds(stream); + + ds << CENTRAL_MAGIC << m_VersionMadeBy << m_SystemMadeBy; + + ds.Write16(wx_truncate_cast(wxUint16, GetVersionNeeded())); + ds.Write16(wx_truncate_cast(wxUint16, GetFlags())); + ds.Write16(wx_truncate_cast(wxUint16, GetMethod())); + ds.Write32(GetDateTime().GetAsDOS()); + ds.Write32(GetCrc()); + ds.Write32(wx_truncate_cast(wxUint32, GetCompressedSize())); + ds.Write32(wx_truncate_cast(wxUint32, GetSize())); + ds.Write16(nameLen); + ds.Write16(extraLen); + + ds << commentLen << m_DiskStart << m_InternalAttributes + << m_ExternalAttributes << wx_truncate_cast(wxUint32, GetOffset()); + + stream.Write(name, nameLen); + if (extraLen) + stream.Write(GetExtra(), extraLen); + stream.Write(comment, commentLen); + + return CENTRAL_SIZE + nameLen + extraLen + commentLen; +} + +// Info-zip prefixes this record with a signature, but pkzip doesn't. So if +// the 1st value is the signature then it is probably an info-zip record, +// though there is a small chance that it is in fact a pkzip record which +// happens to have the signature as it's CRC. +// +size_t wxZipEntry::ReadDescriptor(wxInputStream& stream) +{ + wxZipHeader ds(stream, SUMS_SIZE); + if (!ds) + return 0; + + m_Crc = ds.Read32(); + m_CompressedSize = ds.Read32(); + m_Size = ds.Read32(); + + // if 1st value is the signature then this is probably an info-zip record + if (m_Crc == SUMS_MAGIC) + { + wxZipHeader buf(stream, 8); + wxUint32 u1 = buf.GetSize() >= 4 ? buf.Read32() : (wxUint32)LOCAL_MAGIC; + wxUint32 u2 = buf.GetSize() == 8 ? buf.Read32() : 0; + + // look for the signature of the following record to decide which + if ((u1 == LOCAL_MAGIC || u1 == CENTRAL_MAGIC) && + (u2 != LOCAL_MAGIC && u2 != CENTRAL_MAGIC)) + { + // it's a pkzip style record after all! + if (buf.GetSize() > 0) + stream.Ungetch(buf.GetData(), buf.GetSize()); + } + else + { + // it's an info-zip record as expected + if (buf.GetSize() > 4) + stream.Ungetch(buf.GetData() + 4, buf.GetSize() - 4); + m_Crc = wx_truncate_cast(wxUint32, m_CompressedSize); + m_CompressedSize = m_Size; + m_Size = u1; + return SUMS_SIZE + 4; + } + } + + return SUMS_SIZE; +} + +size_t wxZipEntry::WriteDescriptor(wxOutputStream& stream, wxUint32 crc, + wxFileOffset compressedSize, wxFileOffset size) +{ + m_Crc = crc; + m_CompressedSize = compressedSize; + m_Size = size; + + wxDataOutputStream ds(stream); + + ds.Write32(crc); + ds.Write32(wx_truncate_cast(wxUint32, compressedSize)); + ds.Write32(wx_truncate_cast(wxUint32, size)); + + return SUMS_SIZE; +} + + +///////////////////////////////////////////////////////////////////////////// +// wxZipEndRec - holds the end of central directory record + +class wxZipEndRec +{ +public: + wxZipEndRec(); + + int GetDiskNumber() const { return m_DiskNumber; } + int GetStartDisk() const { return m_StartDisk; } + int GetEntriesHere() const { return m_EntriesHere; } + int GetTotalEntries() const { return m_TotalEntries; } + wxFileOffset GetSize() const { return m_Size; } + wxFileOffset GetOffset() const { return m_Offset; } + wxString GetComment() const { return m_Comment; } + + void SetDiskNumber(int num) + { m_DiskNumber = wx_truncate_cast(wxUint16, num); } + void SetStartDisk(int num) + { m_StartDisk = wx_truncate_cast(wxUint16, num); } + void SetEntriesHere(int num) + { m_EntriesHere = wx_truncate_cast(wxUint16, num); } + void SetTotalEntries(int num) + { m_TotalEntries = wx_truncate_cast(wxUint16, num); } + void SetSize(wxFileOffset size) + { m_Size = wx_truncate_cast(wxUint32, size); } + void SetOffset(wxFileOffset offset) + { m_Offset = wx_truncate_cast(wxUint32, offset); } + void SetComment(const wxString& comment) + { m_Comment = comment; } + + bool Read(wxInputStream& stream, wxMBConv& conv); + bool Write(wxOutputStream& stream, wxMBConv& conv) const; + +private: + wxUint16 m_DiskNumber; + wxUint16 m_StartDisk; + wxUint16 m_EntriesHere; + wxUint16 m_TotalEntries; + wxUint32 m_Size; + wxUint32 m_Offset; + wxString m_Comment; +}; + +wxZipEndRec::wxZipEndRec() + : m_DiskNumber(0), + m_StartDisk(0), + m_EntriesHere(0), + m_TotalEntries(0), + m_Size(0), + m_Offset(0) +{ +} + +bool wxZipEndRec::Write(wxOutputStream& stream, wxMBConv& conv) const +{ + const wxWX2MBbuf comment_buf = conv.cWX2MB(m_Comment); + const char *comment = comment_buf; + if (!comment) comment = ""; + wxUint16 commentLen = (wxUint16)strlen(comment); + + wxDataOutputStream ds(stream); + + ds << END_MAGIC << m_DiskNumber << m_StartDisk << m_EntriesHere + << m_TotalEntries << m_Size << m_Offset << commentLen; + + stream.Write(comment, commentLen); + + return stream.IsOk(); +} + +bool wxZipEndRec::Read(wxInputStream& stream, wxMBConv& conv) +{ + wxZipHeader ds(stream, END_SIZE - 4); + if (!ds) + return false; + + wxUint16 commentLen; + + ds >> m_DiskNumber >> m_StartDisk >> m_EntriesHere + >> m_TotalEntries >> m_Size >> m_Offset >> commentLen; + + if (commentLen) { + m_Comment = ReadString(stream, commentLen, conv); + if (stream.LastRead() != commentLen + 0u) + return false; + } + + if (m_DiskNumber != 0 || m_StartDisk != 0 || + m_EntriesHere != m_TotalEntries) + wxLogWarning(_("assuming this is a multi-part zip concatenated")); + + return true; +} + + +///////////////////////////////////////////////////////////////////////////// +// A weak link from an input stream to an output stream + +class wxZipStreamLink +{ +public: + wxZipStreamLink(wxZipOutputStream *stream) : m_ref(1), m_stream(stream) { } + + wxZipStreamLink *AddRef() { m_ref++; return this; } + wxZipOutputStream *GetOutputStream() const { return m_stream; } + + void Release(class wxZipInputStream *WXUNUSED(s)) + { if (--m_ref == 0) delete this; } + void Release(class wxZipOutputStream *WXUNUSED(s)) + { m_stream = NULL; if (--m_ref == 0) delete this; } + +private: + ~wxZipStreamLink() { } + + int m_ref; + wxZipOutputStream *m_stream; + + wxSUPPRESS_GCC_PRIVATE_DTOR_WARNING(wxZipStreamLink) +}; + + +///////////////////////////////////////////////////////////////////////////// +// Input stream + +// leave the default wxZipEntryPtr free for users +wxDECLARE_SCOPED_PTR(wxZipEntry, wxZipEntryPtr_) +wxDEFINE_SCOPED_PTR (wxZipEntry, wxZipEntryPtr_) + +// constructor +// +wxZipInputStream::wxZipInputStream(wxInputStream& stream, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveInputStream(stream, conv) +{ + Init(); +} + +wxZipInputStream::wxZipInputStream(wxInputStream *stream, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveInputStream(stream, conv) +{ + Init(); +} + +#if WXWIN_COMPATIBILITY_2_6 && wxUSE_FFILE + +// Part of the compatibility constructor, which has been made inline to +// avoid a problem with it not being exported by mingw 3.2.3 +// +void wxZipInputStream::Init(const wxString& file) +{ + // no error messages + wxLogNull nolog; + Init(); + m_allowSeeking = true; + wxFFileInputStream *ffile; + ffile = wx_static_cast(wxFFileInputStream*, m_parent_i_stream); + wxZipEntryPtr_ entry; + + if (ffile->Ok()) { + do { + entry.reset(GetNextEntry()); + } + while (entry.get() != NULL && entry->GetInternalName() != file); + } + + if (entry.get() == NULL) + m_lasterror = wxSTREAM_READ_ERROR; +} + +wxInputStream* wxZipInputStream::OpenFile(const wxString& archive) +{ + wxLogNull nolog; + return new wxFFileInputStream(archive); +} + +#endif // WXWIN_COMPATIBILITY_2_6 && wxUSE_FFILE + +void wxZipInputStream::Init() +{ + m_store = new wxStoredInputStream(*m_parent_i_stream); + m_inflate = NULL; + m_rawin = NULL; + m_raw = false; + m_headerSize = 0; + m_decomp = NULL; + m_parentSeekable = false; + m_weaklinks = new wxZipWeakLinks; + m_streamlink = NULL; + m_offsetAdjustment = 0; + m_position = wxInvalidOffset; + m_signature = 0; + m_TotalEntries = 0; + m_lasterror = m_parent_i_stream->GetLastError(); +#if WXWIN_COMPATIBILITY_2_6 + m_allowSeeking = false; +#endif +} + +wxZipInputStream::~wxZipInputStream() +{ + CloseDecompressor(m_decomp); + + delete m_store; + delete m_inflate; + delete m_rawin; + + m_weaklinks->Release(this); + + if (m_streamlink) + m_streamlink->Release(this); +} + +wxString wxZipInputStream::GetComment() +{ + if (m_position == wxInvalidOffset) + if (!LoadEndRecord()) + return wxEmptyString; + + if (!m_parentSeekable && Eof() && m_signature) { + m_lasterror = wxSTREAM_NO_ERROR; + m_lasterror = ReadLocal(true); + } + + return m_Comment; +} + +int wxZipInputStream::GetTotalEntries() +{ + if (m_position == wxInvalidOffset) + LoadEndRecord(); + return m_TotalEntries; +} + +wxZipStreamLink *wxZipInputStream::MakeLink(wxZipOutputStream *out) +{ + wxZipStreamLink *link = NULL; + + if (!m_parentSeekable && (IsOpened() || !Eof())) { + link = new wxZipStreamLink(out); + if (m_streamlink) + m_streamlink->Release(this); + m_streamlink = link->AddRef(); + } + + return link; +} + +bool wxZipInputStream::LoadEndRecord() +{ + wxCHECK(m_position == wxInvalidOffset, false); + if (!IsOk()) + return false; + + m_position = 0; + + // First find the end-of-central-directory record. + if (!FindEndRecord()) { + // failed, so either this is a non-seekable stream (ok), or not a zip + if (m_parentSeekable) { + m_lasterror = wxSTREAM_READ_ERROR; + wxLogError(_("invalid zip file")); + return false; + } + else { + wxLogNull nolog; + wxFileOffset pos = m_parent_i_stream->TellI(); + if (pos != wxInvalidOffset) + m_offsetAdjustment = m_position = pos; + return true; + } + } + + wxZipEndRec endrec; + + // Read in the end record + wxFileOffset endPos = m_parent_i_stream->TellI() - 4; + if (!endrec.Read(*m_parent_i_stream, GetConv())) + return false; + + m_TotalEntries = endrec.GetTotalEntries(); + m_Comment = endrec.GetComment(); + + // Now find the central-directory. we have the file offset of + // the CD, so look there first. + if (m_parent_i_stream->SeekI(endrec.GetOffset()) != wxInvalidOffset && + ReadSignature() == CENTRAL_MAGIC) { + m_signature = CENTRAL_MAGIC; + m_position = endrec.GetOffset(); + m_offsetAdjustment = 0; + return true; + } + + // If it's not there, then it could be that the zip has been appended + // to a self extractor, so take the CD size (also in endrec), subtract + // it from the file offset of the end-central-directory and look there. + if (m_parent_i_stream->SeekI(endPos - endrec.GetSize()) + != wxInvalidOffset && ReadSignature() == CENTRAL_MAGIC) { + m_signature = CENTRAL_MAGIC; + m_position = endPos - endrec.GetSize(); + m_offsetAdjustment = m_position - endrec.GetOffset(); + return true; + } + + wxLogError(_("can't find central directory in zip")); + m_lasterror = wxSTREAM_READ_ERROR; + return false; +} + +// Find the end-of-central-directory record. +// If found the stream will be positioned just past the 4 signature bytes. +// +bool wxZipInputStream::FindEndRecord() +{ + if (!m_parent_i_stream->IsSeekable()) + return false; + + // usually it's 22 bytes in size and the last thing in the file + { + wxLogNull nolog; + if (m_parent_i_stream->SeekI(-END_SIZE, wxFromEnd) == wxInvalidOffset) + return false; + } + + m_parentSeekable = true; + m_signature = 0; + char magic[4]; + if (m_parent_i_stream->Read(magic, 4).LastRead() != 4) + return false; + if ((m_signature = CrackUint32(magic)) == END_MAGIC) + return true; + + // unfortunately, the record has a comment field that can be up to 65535 + // bytes in length, so if the signature not found then search backwards. + wxFileOffset pos = m_parent_i_stream->TellI(); + const int BUFSIZE = 1024; + wxCharBuffer buf(BUFSIZE); + + memcpy(buf.data(), magic, 3); + wxFileOffset minpos = wxMax(pos - 65535L, 0); + + while (pos > minpos) { + size_t len = wx_truncate_cast(size_t, + pos - wxMax(pos - (BUFSIZE - 3), minpos)); + memcpy(buf.data() + len, buf, 3); + pos -= len; + + if (m_parent_i_stream->SeekI(pos, wxFromStart) == wxInvalidOffset || + m_parent_i_stream->Read(buf.data(), len).LastRead() != len) + return false; + + char *p = buf.data() + len; + + while (p-- > buf.data()) { + if ((m_signature = CrackUint32(p)) == END_MAGIC) { + size_t remainder = buf.data() + len - p; + if (remainder > 4) + m_parent_i_stream->Ungetch(p + 4, remainder - 4); + return true; + } + } + } + + return false; +} + +wxZipEntry *wxZipInputStream::GetNextEntry() +{ + if (m_position == wxInvalidOffset) + if (!LoadEndRecord()) + return NULL; + + m_lasterror = m_parentSeekable ? ReadCentral() : ReadLocal(); + if (!IsOk()) + return NULL; + + wxZipEntryPtr_ entry(new wxZipEntry(m_entry)); + entry->m_backlink = m_weaklinks->AddEntry(entry.get(), entry->GetKey()); + return entry.release(); +} + +wxStreamError wxZipInputStream::ReadCentral() +{ + if (!AtHeader()) + CloseEntry(); + + if (m_signature == END_MAGIC) + return wxSTREAM_EOF; + + if (m_signature != CENTRAL_MAGIC) { + wxLogError(_("error reading zip central directory")); + return wxSTREAM_READ_ERROR; + } + + if (QuietSeek(*m_parent_i_stream, m_position + 4) == wxInvalidOffset) + return wxSTREAM_READ_ERROR; + + size_t size = m_entry.ReadCentral(*m_parent_i_stream, GetConv()); + if (!size) { + m_signature = 0; + return wxSTREAM_READ_ERROR; + } + + m_position += size; + m_signature = ReadSignature(); + + if (m_offsetAdjustment) + m_entry.SetOffset(m_entry.GetOffset() + m_offsetAdjustment); + m_entry.SetKey(m_entry.GetOffset()); + + return wxSTREAM_NO_ERROR; +} + +wxStreamError wxZipInputStream::ReadLocal(bool readEndRec /*=false*/) +{ + if (!AtHeader()) + CloseEntry(); + + if (!m_signature) + m_signature = ReadSignature(); + + if (m_signature == CENTRAL_MAGIC || m_signature == END_MAGIC) { + if (m_streamlink && !m_streamlink->GetOutputStream()) { + m_streamlink->Release(this); + m_streamlink = NULL; + } + } + + while (m_signature == CENTRAL_MAGIC) { + if (m_weaklinks->IsEmpty() && m_streamlink == NULL) + return wxSTREAM_EOF; + + size_t size = m_entry.ReadCentral(*m_parent_i_stream, GetConv()); + m_position += size; + m_signature = 0; + if (!size) + return wxSTREAM_READ_ERROR; + + wxZipEntry *entry = m_weaklinks->GetEntry(m_entry.GetOffset()); + if (entry) { + entry->SetSystemMadeBy(m_entry.GetSystemMadeBy()); + entry->SetVersionMadeBy(m_entry.GetVersionMadeBy()); + entry->SetComment(m_entry.GetComment()); + entry->SetDiskStart(m_entry.GetDiskStart()); + entry->SetInternalAttributes(m_entry.GetInternalAttributes()); + entry->SetExternalAttributes(m_entry.GetExternalAttributes()); + Copy(entry->m_Extra, m_entry.m_Extra); + entry->Notify(); + m_weaklinks->RemoveEntry(entry->GetOffset()); + } + + m_signature = ReadSignature(); + } + + if (m_signature == END_MAGIC) { + if (readEndRec || m_streamlink) { + wxZipEndRec endrec; + endrec.Read(*m_parent_i_stream, GetConv()); + m_Comment = endrec.GetComment(); + m_signature = 0; + if (m_streamlink) { + m_streamlink->GetOutputStream()->SetComment(endrec.GetComment()); + m_streamlink->Release(this); + m_streamlink = NULL; + } + } + return wxSTREAM_EOF; + } + + if (m_signature == LOCAL_MAGIC) { + m_headerSize = m_entry.ReadLocal(*m_parent_i_stream, GetConv()); + m_signature = 0; + m_entry.SetOffset(m_position); + m_entry.SetKey(m_position); + + if (m_headerSize) { + m_TotalEntries++; + return wxSTREAM_NO_ERROR; + } + } + + wxLogError(_("error reading zip local header")); + return wxSTREAM_READ_ERROR; +} + +wxUint32 wxZipInputStream::ReadSignature() +{ + char magic[4]; + m_parent_i_stream->Read(magic, 4); + return m_parent_i_stream->LastRead() == 4 ? CrackUint32(magic) : 0; +} + +bool wxZipInputStream::OpenEntry(wxArchiveEntry& entry) +{ + wxZipEntry *zipEntry = wxStaticCast(&entry, wxZipEntry); + return zipEntry ? OpenEntry(*zipEntry) : false; +} + +// Open an entry +// +bool wxZipInputStream::DoOpen(wxZipEntry *entry, bool raw) +{ + if (m_position == wxInvalidOffset) + if (!LoadEndRecord()) + return false; + if (m_lasterror == wxSTREAM_READ_ERROR) + return false; + if (IsOpened()) + CloseEntry(); + + m_raw = raw; + + if (entry) { + if (AfterHeader() && entry->GetKey() == m_entry.GetOffset()) + return true; + // can only open the current entry on a non-seekable stream + wxCHECK(m_parentSeekable, false); + } + + m_lasterror = wxSTREAM_READ_ERROR; + + if (entry) + m_entry = *entry; + + if (m_parentSeekable) { + if (QuietSeek(*m_parent_i_stream, m_entry.GetOffset()) + == wxInvalidOffset) + return false; + if (ReadSignature() != LOCAL_MAGIC) { + wxLogError(_("bad zipfile offset to entry")); + return false; + } + } + + if (m_parentSeekable || AtHeader()) { + m_headerSize = m_entry.ReadLocal(*m_parent_i_stream, GetConv()); + if (m_headerSize && m_parentSeekable) { + wxZipEntry *ref = m_weaklinks->GetEntry(m_entry.GetKey()); + if (ref) { + Copy(ref->m_LocalExtra, m_entry.m_LocalExtra); + ref->Notify(); + m_weaklinks->RemoveEntry(ref->GetKey()); + } + if (entry && entry != ref) { + Copy(entry->m_LocalExtra, m_entry.m_LocalExtra); + entry->Notify(); + } + } + } + + if (m_headerSize) + m_lasterror = wxSTREAM_NO_ERROR; + return IsOk(); +} + +bool wxZipInputStream::OpenDecompressor(bool raw /*=false*/) +{ + wxASSERT(AfterHeader()); + + wxFileOffset compressedSize = m_entry.GetCompressedSize(); + + if (raw) + m_raw = true; + + if (m_raw) { + if (compressedSize != wxInvalidOffset) { + m_store->Open(compressedSize); + m_decomp = m_store; + } else { + if (!m_rawin) + m_rawin = new wxRawInputStream(*m_parent_i_stream); + m_decomp = m_rawin->Open(OpenDecompressor(m_rawin->GetTee())); + } + } else { + if (compressedSize != wxInvalidOffset && + (m_entry.GetMethod() != wxZIP_METHOD_DEFLATE || + wxZlibInputStream::CanHandleGZip())) { + m_store->Open(compressedSize); + m_decomp = OpenDecompressor(*m_store); + } else { + m_decomp = OpenDecompressor(*m_parent_i_stream); + } + } + + m_crcAccumulator = crc32(0, Z_NULL, 0); + m_lasterror = m_decomp ? m_decomp->GetLastError() : wxSTREAM_READ_ERROR; + return IsOk(); +} + +// Can be overriden to add support for additional decompression methods +// +wxInputStream *wxZipInputStream::OpenDecompressor(wxInputStream& stream) +{ + switch (m_entry.GetMethod()) { + case wxZIP_METHOD_STORE: + if (m_entry.GetSize() == wxInvalidOffset) { + wxLogError(_("stored file length not in Zip header")); + break; + } + m_store->Open(m_entry.GetSize()); + return m_store; + + case wxZIP_METHOD_DEFLATE: + if (!m_inflate) + m_inflate = new wxZlibInputStream2(stream); + else + m_inflate->Open(stream); + return m_inflate; + + default: + wxLogError(_("unsupported Zip compression method")); + } + + return NULL; +} + +bool wxZipInputStream::CloseDecompressor(wxInputStream *decomp) +{ + if (decomp && decomp == m_rawin) + return CloseDecompressor(m_rawin->GetFilterInputStream()); + if (decomp != m_store && decomp != m_inflate) + delete decomp; + return true; +} + +// Closes the current entry and positions the underlying stream at the start +// of the next entry +// +bool wxZipInputStream::CloseEntry() +{ + if (AtHeader()) + return true; + if (m_lasterror == wxSTREAM_READ_ERROR) + return false; + + if (!m_parentSeekable) { + if (!IsOpened() && !OpenDecompressor(true)) + return false; + + const int BUFSIZE = 8192; + wxCharBuffer buf(BUFSIZE); + while (IsOk()) + Read(buf.data(), BUFSIZE); + + m_position += m_headerSize + m_entry.GetCompressedSize(); + } + + if (m_lasterror == wxSTREAM_EOF) + m_lasterror = wxSTREAM_NO_ERROR; + + CloseDecompressor(m_decomp); + m_decomp = NULL; + m_entry = wxZipEntry(); + m_headerSize = 0; + m_raw = false; + + return IsOk(); +} + +size_t wxZipInputStream::OnSysRead(void *buffer, size_t size) +{ + if (!IsOpened()) + if ((AtHeader() && !DoOpen()) || !OpenDecompressor()) + m_lasterror = wxSTREAM_READ_ERROR; + if (!IsOk() || !size) + return 0; + + size_t count = m_decomp->Read(buffer, size).LastRead(); + if (!m_raw) + m_crcAccumulator = crc32(m_crcAccumulator, (Byte*)buffer, count); + if (count < size) + m_lasterror = m_decomp->GetLastError(); + + if (Eof()) { + if ((m_entry.GetFlags() & wxZIP_SUMS_FOLLOW) != 0) { + m_headerSize += m_entry.ReadDescriptor(*m_parent_i_stream); + wxZipEntry *entry = m_weaklinks->GetEntry(m_entry.GetKey()); + + if (entry) { + entry->SetCrc(m_entry.GetCrc()); + entry->SetCompressedSize(m_entry.GetCompressedSize()); + entry->SetSize(m_entry.GetSize()); + entry->Notify(); + } + } + + if (!m_raw) { + m_lasterror = wxSTREAM_READ_ERROR; + + if (m_entry.GetSize() != TellI()) + wxLogError(_("reading zip stream (entry %s): bad length"), + m_entry.GetName().c_str()); + else if (m_crcAccumulator != m_entry.GetCrc()) + wxLogError(_("reading zip stream (entry %s): bad crc"), + m_entry.GetName().c_str()); + else + m_lasterror = wxSTREAM_EOF; + } + } + + return count; +} + +#if WXWIN_COMPATIBILITY_2_6 + +// Borrowed from VS's zip stream (c) 1999 Vaclav Slavik +// +wxFileOffset wxZipInputStream::OnSysSeek(wxFileOffset seek, wxSeekMode mode) +{ + // seeking works when the stream is created with the compatibility + // constructor + if (!m_allowSeeking) + return wxInvalidOffset; + if (!IsOpened()) + if ((AtHeader() && !DoOpen()) || !OpenDecompressor()) + m_lasterror = wxSTREAM_READ_ERROR; + if (!IsOk()) + return wxInvalidOffset; + + // NB: since ZIP files don't natively support seeking, we have to + // implement a brute force workaround -- reading all the data + // between current and the new position (or between beginning of + // the file and new position...) + + wxFileOffset nextpos; + wxFileOffset pos = TellI(); + + switch ( mode ) + { + case wxFromCurrent : nextpos = seek + pos; break; + case wxFromStart : nextpos = seek; break; + case wxFromEnd : nextpos = GetLength() + seek; break; + default : nextpos = pos; break; /* just to fool compiler, never happens */ + } + + wxFileOffset toskip wxDUMMY_INITIALIZE(0); + if ( nextpos >= pos ) + { + toskip = nextpos - pos; + } + else + { + wxZipEntry current(m_entry); + if (!OpenEntry(current)) + { + m_lasterror = wxSTREAM_READ_ERROR; + return pos; + } + toskip = nextpos; + } + + if ( toskip > 0 ) + { + const int BUFSIZE = 4096; + size_t sz; + char buffer[BUFSIZE]; + while ( toskip > 0 ) + { + sz = wx_truncate_cast(size_t, wxMin(toskip, BUFSIZE)); + Read(buffer, sz); + toskip -= sz; + } + } + + pos = nextpos; + return pos; +} + +#endif // WXWIN_COMPATIBILITY_2_6 + + +///////////////////////////////////////////////////////////////////////////// +// Output stream + +#include "wx/listimpl.cpp" +WX_DEFINE_LIST(wxZipEntryList_) + +wxZipOutputStream::wxZipOutputStream(wxOutputStream& stream, + int level /*=-1*/, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveOutputStream(stream, conv) +{ + Init(level); +} + +wxZipOutputStream::wxZipOutputStream(wxOutputStream *stream, + int level /*=-1*/, + wxMBConv& conv /*=wxConvLocal*/) + : wxArchiveOutputStream(stream, conv) +{ + Init(level); +} + +void wxZipOutputStream::Init(int level) +{ + m_store = new wxStoredOutputStream(*m_parent_o_stream); + m_deflate = NULL; + m_backlink = NULL; + m_initialData = new char[OUTPUT_LATENCY]; + m_initialSize = 0; + m_pending = NULL; + m_raw = false; + m_headerOffset = 0; + m_headerSize = 0; + m_entrySize = 0; + m_comp = NULL; + m_level = level; + m_offsetAdjustment = wxInvalidOffset; +} + +wxZipOutputStream::~wxZipOutputStream() +{ + Close(); + WX_CLEAR_LIST(wxZipEntryList_, m_entries); + delete m_store; + delete m_deflate; + delete m_pending; + delete [] m_initialData; + if (m_backlink) + m_backlink->Release(this); +} + +bool wxZipOutputStream::PutNextEntry( + const wxString& name, + const wxDateTime& dt /*=wxDateTime::Now()*/, + wxFileOffset size /*=wxInvalidOffset*/) +{ + return PutNextEntry(new wxZipEntry(name, dt, size)); +} + +bool wxZipOutputStream::PutNextDirEntry( + const wxString& name, + const wxDateTime& dt /*=wxDateTime::Now()*/) +{ + wxZipEntry *entry = new wxZipEntry(name, dt); + entry->SetIsDir(); + return PutNextEntry(entry); +} + +bool wxZipOutputStream::CopyEntry(wxZipEntry *entry, + wxZipInputStream& inputStream) +{ + wxZipEntryPtr_ e(entry); + + return + inputStream.DoOpen(e.get(), true) && + DoCreate(e.release(), true) && + Write(inputStream).IsOk() && inputStream.Eof(); +} + +bool wxZipOutputStream::PutNextEntry(wxArchiveEntry *entry) +{ + wxZipEntry *zipEntry = wxStaticCast(entry, wxZipEntry); + if (!zipEntry) + delete entry; + return PutNextEntry(zipEntry); +} + +bool wxZipOutputStream::CopyEntry(wxArchiveEntry *entry, + wxArchiveInputStream& stream) +{ + wxZipEntry *zipEntry = wxStaticCast(entry, wxZipEntry); + + if (!zipEntry || !stream.OpenEntry(*zipEntry)) { + delete entry; + return false; + } + + return CopyEntry(zipEntry, wx_static_cast(wxZipInputStream&, stream)); +} + +bool wxZipOutputStream::CopyArchiveMetaData(wxZipInputStream& inputStream) +{ + m_Comment = inputStream.GetComment(); + if (m_backlink) + m_backlink->Release(this); + m_backlink = inputStream.MakeLink(this); + return true; +} + +bool wxZipOutputStream::CopyArchiveMetaData(wxArchiveInputStream& stream) +{ + return CopyArchiveMetaData(wx_static_cast(wxZipInputStream&, stream)); +} + +void wxZipOutputStream::SetLevel(int level) +{ + if (level != m_level) { + if (m_comp != m_deflate) + delete m_deflate; + m_deflate = NULL; + m_level = level; + } +} + +bool wxZipOutputStream::DoCreate(wxZipEntry *entry, bool raw /*=false*/) +{ + CloseEntry(); + + m_pending = entry; + if (!m_pending) + return false; + + // write the signature bytes right away + wxDataOutputStream ds(*m_parent_o_stream); + ds << LOCAL_MAGIC; + + // and if this is the first entry test for seekability + if (m_headerOffset == 0 && m_parent_o_stream->IsSeekable()) { +#if wxUSE_LOG + bool logging = wxLog::IsEnabled(); + wxLogNull nolog; +#endif // wxUSE_LOG + wxFileOffset here = m_parent_o_stream->TellO(); + + if (here != wxInvalidOffset && here >= 4) { + if (m_parent_o_stream->SeekO(here - 4) == here - 4) { + m_offsetAdjustment = here - 4; +#if wxUSE_LOG + wxLog::EnableLogging(logging); +#endif // wxUSE_LOG + m_parent_o_stream->SeekO(here); + } + } + } + + m_pending->SetOffset(m_headerOffset); + + m_crcAccumulator = crc32(0, Z_NULL, 0); + + if (raw) + m_raw = true; + + m_lasterror = wxSTREAM_NO_ERROR; + return true; +} + +// Can be overriden to add support for additional compression methods +// +wxOutputStream *wxZipOutputStream::OpenCompressor( + wxOutputStream& stream, + wxZipEntry& entry, + const Buffer bufs[]) +{ + if (entry.GetMethod() == wxZIP_METHOD_DEFAULT) { + if (GetLevel() == 0 + && (IsParentSeekable() + || entry.GetCompressedSize() != wxInvalidOffset + || entry.GetSize() != wxInvalidOffset)) { + entry.SetMethod(wxZIP_METHOD_STORE); + } else { + int size = 0; + for (int i = 0; bufs[i].m_data; ++i) + size += bufs[i].m_size; + entry.SetMethod(size <= 6 ? + wxZIP_METHOD_STORE : wxZIP_METHOD_DEFLATE); + } + } + + switch (entry.GetMethod()) { + case wxZIP_METHOD_STORE: + if (entry.GetCompressedSize() == wxInvalidOffset) + entry.SetCompressedSize(entry.GetSize()); + return m_store; + + case wxZIP_METHOD_DEFLATE: + { + int defbits = wxZIP_DEFLATE_NORMAL; + switch (GetLevel()) { + case 0: case 1: + defbits = wxZIP_DEFLATE_SUPERFAST; + break; + case 2: case 3: case 4: + defbits = wxZIP_DEFLATE_FAST; + break; + case 8: case 9: + defbits = wxZIP_DEFLATE_EXTRA; + break; + } + entry.SetFlags((entry.GetFlags() & ~wxZIP_DEFLATE_MASK) | + defbits | wxZIP_SUMS_FOLLOW); + + if (!m_deflate) + m_deflate = new wxZlibOutputStream2(stream, GetLevel()); + else + m_deflate->Open(stream); + + return m_deflate; + } + + default: + wxLogError(_("unsupported Zip compression method")); + } + + return NULL; +} + +bool wxZipOutputStream::CloseCompressor(wxOutputStream *comp) +{ + if (comp == m_deflate) + m_deflate->Close(); + else if (comp != m_store) + delete comp; + return true; +} + +// This is called when OUPUT_LATENCY bytes has been written to the +// wxZipOutputStream to actually create the zip entry. +// +void wxZipOutputStream::CreatePendingEntry(const void *buffer, size_t size) +{ + wxASSERT(IsOk() && m_pending && !m_comp); + wxZipEntryPtr_ spPending(m_pending); + m_pending = NULL; + + Buffer bufs[] = { + { m_initialData, m_initialSize }, + { (const char*)buffer, size }, + { NULL, 0 } + }; + + if (m_raw) + m_comp = m_store; + else + m_comp = OpenCompressor(*m_store, *spPending, + m_initialSize ? bufs : bufs + 1); + + if (IsParentSeekable() + || (spPending->m_Crc + && spPending->m_CompressedSize != wxInvalidOffset + && spPending->m_Size != wxInvalidOffset)) + spPending->m_Flags &= ~wxZIP_SUMS_FOLLOW; + else + if (spPending->m_CompressedSize != wxInvalidOffset) + spPending->m_Flags |= wxZIP_SUMS_FOLLOW; + + m_headerSize = spPending->WriteLocal(*m_parent_o_stream, GetConv()); + m_lasterror = m_parent_o_stream->GetLastError(); + + if (IsOk()) { + m_entries.push_back(spPending.release()); + OnSysWrite(m_initialData, m_initialSize); + } + + m_initialSize = 0; +} + +// This is called to write out the zip entry when Close has been called +// before OUTPUT_LATENCY bytes has been written to the wxZipOutputStream. +// +void wxZipOutputStream::CreatePendingEntry() +{ + wxASSERT(IsOk() && m_pending && !m_comp); + wxZipEntryPtr_ spPending(m_pending); + m_pending = NULL; + m_lasterror = wxSTREAM_WRITE_ERROR; + + if (!m_raw) { + // Initially compresses the data to memory, then fall back to 'store' + // if the compressor makes the data larger rather than smaller. + wxMemoryOutputStream mem; + Buffer bufs[] = { { m_initialData, m_initialSize }, { NULL, 0 } }; + wxOutputStream *comp = OpenCompressor(mem, *spPending, bufs); + + if (!comp) + return; + if (comp != m_store) { + bool ok = comp->Write(m_initialData, m_initialSize).IsOk(); + CloseCompressor(comp); + if (!ok) + return; + } + + m_entrySize = m_initialSize; + m_crcAccumulator = crc32(0, (Byte*)m_initialData, m_initialSize); + + if (mem.GetSize() > 0 && mem.GetSize() < m_initialSize) { + m_initialSize = mem.GetSize(); + mem.CopyTo(m_initialData, m_initialSize); + } else { + spPending->SetMethod(wxZIP_METHOD_STORE); + } + + spPending->SetSize(m_entrySize); + spPending->SetCrc(m_crcAccumulator); + spPending->SetCompressedSize(m_initialSize); + } + + spPending->m_Flags &= ~wxZIP_SUMS_FOLLOW; + m_headerSize = spPending->WriteLocal(*m_parent_o_stream, GetConv()); + + if (m_parent_o_stream->IsOk()) { + m_entries.push_back(spPending.release()); + m_comp = m_store; + m_store->Write(m_initialData, m_initialSize); + } + + m_initialSize = 0; + m_lasterror = m_parent_o_stream->GetLastError(); +} + +// Write the 'central directory' and the 'end-central-directory' records. +// +bool wxZipOutputStream::Close() +{ + CloseEntry(); + + if (m_lasterror == wxSTREAM_WRITE_ERROR || m_entries.size() == 0) { + wxFilterOutputStream::Close(); + return false; + } + + wxZipEndRec endrec; + + endrec.SetEntriesHere(m_entries.size()); + endrec.SetTotalEntries(m_entries.size()); + endrec.SetOffset(m_headerOffset); + endrec.SetComment(m_Comment); + + wxZipEntryList_::iterator it; + wxFileOffset size = 0; + + for (it = m_entries.begin(); it != m_entries.end(); ++it) { + size += (*it)->WriteCentral(*m_parent_o_stream, GetConv()); + delete *it; + } + m_entries.clear(); + + endrec.SetSize(size); + endrec.Write(*m_parent_o_stream, GetConv()); + + m_lasterror = m_parent_o_stream->GetLastError(); + + if (!wxFilterOutputStream::Close() || !IsOk()) + return false; + m_lasterror = wxSTREAM_EOF; + return true; +} + +// Finish writing the current entry +// +bool wxZipOutputStream::CloseEntry() +{ + if (IsOk() && m_pending) + CreatePendingEntry(); + if (!IsOk()) + return false; + if (!m_comp) + return true; + + CloseCompressor(m_comp); + m_comp = NULL; + + wxFileOffset compressedSize = m_store->TellO(); + + wxZipEntry& entry = *m_entries.back(); + + // When writing raw the crc and size can't be checked + if (m_raw) { + m_crcAccumulator = entry.GetCrc(); + m_entrySize = entry.GetSize(); + } + + // Write the sums in the trailing 'data descriptor' if necessary + if (entry.m_Flags & wxZIP_SUMS_FOLLOW) { + wxASSERT(!IsParentSeekable()); + m_headerOffset += + entry.WriteDescriptor(*m_parent_o_stream, m_crcAccumulator, + compressedSize, m_entrySize); + m_lasterror = m_parent_o_stream->GetLastError(); + } + + // If the local header didn't have the correct crc and size written to + // it then seek back and fix it + else if (m_crcAccumulator != entry.GetCrc() + || m_entrySize != entry.GetSize() + || compressedSize != entry.GetCompressedSize()) + { + if (IsParentSeekable()) { + wxFileOffset here = m_parent_o_stream->TellO(); + wxFileOffset headerOffset = m_headerOffset + m_offsetAdjustment; + m_parent_o_stream->SeekO(headerOffset + SUMS_OFFSET); + entry.WriteDescriptor(*m_parent_o_stream, m_crcAccumulator, + compressedSize, m_entrySize); + m_parent_o_stream->SeekO(here); + m_lasterror = m_parent_o_stream->GetLastError(); + } else { + m_lasterror = wxSTREAM_WRITE_ERROR; + } + } + + m_headerOffset += m_headerSize + compressedSize; + m_headerSize = 0; + m_entrySize = 0; + m_store->Close(); + m_raw = false; + + if (IsOk()) + m_lasterror = m_parent_o_stream->GetLastError(); + else + wxLogError(_("error writing zip entry '%s': bad crc or length"), + entry.GetName().c_str()); + return IsOk(); +} + +void wxZipOutputStream::Sync() +{ + if (IsOk() && m_pending) + CreatePendingEntry(NULL, 0); + if (!m_comp) + m_lasterror = wxSTREAM_WRITE_ERROR; + if (IsOk()) { + m_comp->Sync(); + m_lasterror = m_comp->GetLastError(); + } +} + +size_t wxZipOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + if (IsOk() && m_pending) { + if (m_initialSize + size < OUTPUT_LATENCY) { + memcpy(m_initialData + m_initialSize, buffer, size); + m_initialSize += size; + return size; + } else { + CreatePendingEntry(buffer, size); + } + } + + if (!m_comp) + m_lasterror = wxSTREAM_WRITE_ERROR; + if (!IsOk() || !size) + return 0; + + if (m_comp->Write(buffer, size).LastWrite() != size) + m_lasterror = wxSTREAM_WRITE_ERROR; + m_crcAccumulator = crc32(m_crcAccumulator, (Byte*)buffer, size); + m_entrySize += m_comp->LastWrite(); + + return m_comp->LastWrite(); +} + +#endif // wxUSE_ZIPSTREAM diff --git a/Source/3rd Party/wx/src/common/zstream.cpp b/Source/3rd Party/wx/src/common/zstream.cpp index a3a427007..8f66fce17 100644 --- a/Source/3rd Party/wx/src/common/zstream.cpp +++ b/Source/3rd Party/wx/src/common/zstream.cpp @@ -1,428 +1,428 @@ -////////////////////////////////////////////////////////////////////////////// -// Name: src/common/zstream.cpp -// Purpose: Compressed stream classes -// Author: Guilhem Lavaux -// Modified by: Mike Wetherell -// Created: 11/07/98 -// RCS-ID: $Id: zstream.cpp 42621 2006-10-29 16:47:20Z MW $ -// Copyright: (c) Guilhem Lavaux -// Licence: wxWindows licence -///////////////////////////////////////////////////////////////////////////// - -// For compilers that support precompilation, includes "wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ - #pragma hdrstop -#endif - -#if wxUSE_ZLIB && wxUSE_STREAMS - -#include "wx/zstream.h" - -#ifndef WX_PRECOMP - #include "wx/intl.h" - #include "wx/log.h" - #include "wx/utils.h" -#endif - - -// normally, the compiler options should contain -I../zlib, but it is -// apparently not the case for all MSW makefiles and so, unless we use -// configure (which defines __WX_SETUP_H__) or it is explicitly overridden by -// the user (who can define wxUSE_ZLIB_H_IN_PATH), we hardcode the path here -#if defined(__WXMSW__) && !defined(__WX_SETUP_H__) && !defined(wxUSE_ZLIB_H_IN_PATH) - #include "../zlib/zlib.h" -#else - #include "zlib.h" -#endif - -enum { - ZSTREAM_BUFFER_SIZE = 16384, - ZSTREAM_GZIP = 0x10, // gzip header - ZSTREAM_AUTO = 0x20 // auto detect between gzip and zlib -}; - - -///////////////////////////////////////////////////////////////////////////// -// Zlib Class factory - -IMPLEMENT_DYNAMIC_CLASS(wxZlibClassFactory, wxFilterClassFactory) - -static wxZlibClassFactory g_wxZlibClassFactory; - -wxZlibClassFactory::wxZlibClassFactory() -{ - if (this == &g_wxZlibClassFactory) - PushFront(); -} - -const wxChar * const * -wxZlibClassFactory::GetProtocols(wxStreamProtocolType type) const -{ - static const wxChar *mimes[] = { _T("application/x-deflate"), NULL }; - static const wxChar *encs[] = { _T("deflate"), NULL }; - static const wxChar *empty[] = { NULL }; - - switch (type) { - case wxSTREAM_MIMETYPE: return mimes; - case wxSTREAM_ENCODING: return encs; - default: return empty; - } -} - - -///////////////////////////////////////////////////////////////////////////// -// Gzip Class factory - -IMPLEMENT_DYNAMIC_CLASS(wxGzipClassFactory, wxFilterClassFactory) - -static wxGzipClassFactory g_wxGzipClassFactory; - -wxGzipClassFactory::wxGzipClassFactory() -{ - if (this == &g_wxGzipClassFactory && wxZlibInputStream::CanHandleGZip()) - PushFront(); -} - -const wxChar * const * -wxGzipClassFactory::GetProtocols(wxStreamProtocolType type) const -{ - static const wxChar *protos[] = - { _T("gzip"), NULL }; - static const wxChar *mimes[] = - { _T("application/gzip"), _T("application/x-gzip"), NULL }; - static const wxChar *encs[] = - { _T("gzip"), NULL }; - static const wxChar *exts[] = - { _T(".gz"), _T(".gzip"), NULL }; - static const wxChar *empty[] = - { NULL }; - - switch (type) { - case wxSTREAM_PROTOCOL: return protos; - case wxSTREAM_MIMETYPE: return mimes; - case wxSTREAM_ENCODING: return encs; - case wxSTREAM_FILEEXT: return exts; - default: return empty; - } -} - - -////////////////////// -// wxZlibInputStream -////////////////////// - -wxZlibInputStream::wxZlibInputStream(wxInputStream& stream, int flags) - : wxFilterInputStream(stream) -{ - Init(flags); -} - -wxZlibInputStream::wxZlibInputStream(wxInputStream *stream, int flags) - : wxFilterInputStream(stream) -{ - Init(flags); -} - -void wxZlibInputStream::Init(int flags) -{ - m_inflate = NULL; - m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE]; - m_z_size = ZSTREAM_BUFFER_SIZE; - m_pos = 0; - -#if WXWIN_COMPATIBILITY_2_4 - // treat compatibility mode as auto - m_24compatibilty = flags == wxZLIB_24COMPATIBLE; - if (m_24compatibilty) - flags = wxZLIB_AUTO; -#endif - - // if gzip is asked for but not supported... - if ((flags == wxZLIB_GZIP || flags == wxZLIB_AUTO) && !CanHandleGZip()) { - if (flags == wxZLIB_AUTO) { - // an error will come later if the input turns out not to be a zlib - flags = wxZLIB_ZLIB; - } - else { - wxLogError(_("Gzip not supported by this version of zlib")); - m_lasterror = wxSTREAM_READ_ERROR; - return; - } - } - - if (m_z_buffer) { - m_inflate = new z_stream_s; - - if (m_inflate) { - memset(m_inflate, 0, sizeof(z_stream_s)); - - // see zlib.h for documentation on windowBits - int windowBits = MAX_WBITS; - switch (flags) { - case wxZLIB_NO_HEADER: windowBits = -MAX_WBITS; break; - case wxZLIB_ZLIB: windowBits = MAX_WBITS; break; - case wxZLIB_GZIP: windowBits = MAX_WBITS | ZSTREAM_GZIP; break; - case wxZLIB_AUTO: windowBits = MAX_WBITS | ZSTREAM_AUTO; break; - default: wxFAIL_MSG(wxT("Invalid zlib flag")); - } - - if (inflateInit2(m_inflate, windowBits) == Z_OK) - return; - } - } - - wxLogError(_("Can't initialize zlib inflate stream.")); - m_lasterror = wxSTREAM_READ_ERROR; -} - -wxZlibInputStream::~wxZlibInputStream() -{ - inflateEnd(m_inflate); - delete m_inflate; - - delete [] m_z_buffer; -} - -size_t wxZlibInputStream::OnSysRead(void *buffer, size_t size) -{ - wxASSERT_MSG(m_inflate && m_z_buffer, wxT("Inflate stream not open")); - - if (!m_inflate || !m_z_buffer) - m_lasterror = wxSTREAM_READ_ERROR; - if (!IsOk() || !size) - return 0; - - int err = Z_OK; - m_inflate->next_out = (unsigned char *)buffer; - m_inflate->avail_out = size; - - while (err == Z_OK && m_inflate->avail_out > 0) { - if (m_inflate->avail_in == 0 && m_parent_i_stream->IsOk()) { - m_parent_i_stream->Read(m_z_buffer, m_z_size); - m_inflate->next_in = m_z_buffer; - m_inflate->avail_in = m_parent_i_stream->LastRead(); - } - err = inflate(m_inflate, Z_SYNC_FLUSH); - } - - switch (err) { - case Z_OK: - break; - - case Z_STREAM_END: - if (m_inflate->avail_out) { - // Unread any data taken from past the end of the deflate stream, so that - // any additional data can be read from the underlying stream (the crc - // in a gzip for example) - if (m_inflate->avail_in) { - m_parent_i_stream->Reset(); - m_parent_i_stream->Ungetch(m_inflate->next_in, m_inflate->avail_in); - m_inflate->avail_in = 0; - } - m_lasterror = wxSTREAM_EOF; - } - break; - - case Z_BUF_ERROR: - // Indicates that zlib was expecting more data, but the parent stream - // has none. Other than Eof the error will have been already reported - // by the parent strean, - m_lasterror = wxSTREAM_READ_ERROR; - if (m_parent_i_stream->Eof()) -#if WXWIN_COMPATIBILITY_2_4 - if (m_24compatibilty) - m_lasterror = wxSTREAM_EOF; - else -#endif - wxLogError(_("Can't read inflate stream: unexpected EOF in underlying stream.")); - break; - - default: - wxString msg(m_inflate->msg, *wxConvCurrent); - if (!msg) - msg = wxString::Format(_("zlib error %d"), err); - wxLogError(_("Can't read from inflate stream: %s"), msg.c_str()); - m_lasterror = wxSTREAM_READ_ERROR; - } - - size -= m_inflate->avail_out; - m_pos += size; - return size; -} - -/* static */ bool wxZlibInputStream::CanHandleGZip() -{ - const char *dot = strchr(zlibVersion(), '.'); - int major = atoi(zlibVersion()); - int minor = dot ? atoi(dot + 1) : 0; - return major > 1 || (major == 1 && minor >= 2); -} - - -////////////////////// -// wxZlibOutputStream -////////////////////// - -wxZlibOutputStream::wxZlibOutputStream(wxOutputStream& stream, - int level, - int flags) - : wxFilterOutputStream(stream) -{ - Init(level, flags); -} - -wxZlibOutputStream::wxZlibOutputStream(wxOutputStream *stream, - int level, - int flags) - : wxFilterOutputStream(stream) -{ - Init(level, flags); -} - -void wxZlibOutputStream::Init(int level, int flags) -{ - m_deflate = NULL; - m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE]; - m_z_size = ZSTREAM_BUFFER_SIZE; - m_pos = 0; - - if ( level == -1 ) - { - level = Z_DEFAULT_COMPRESSION; - } - else - { - wxASSERT_MSG(level >= 0 && level <= 9, wxT("wxZlibOutputStream compression level must be between 0 and 9!")); - } - - // if gzip is asked for but not supported... - if (flags == wxZLIB_GZIP && !CanHandleGZip()) { - wxLogError(_("Gzip not supported by this version of zlib")); - m_lasterror = wxSTREAM_WRITE_ERROR; - return; - } - - if (m_z_buffer) { - m_deflate = new z_stream_s; - - if (m_deflate) { - memset(m_deflate, 0, sizeof(z_stream_s)); - m_deflate->next_out = m_z_buffer; - m_deflate->avail_out = m_z_size; - - // see zlib.h for documentation on windowBits - int windowBits = MAX_WBITS; - switch (flags) { - case wxZLIB_NO_HEADER: windowBits = -MAX_WBITS; break; - case wxZLIB_ZLIB: windowBits = MAX_WBITS; break; - case wxZLIB_GZIP: windowBits = MAX_WBITS | ZSTREAM_GZIP; break; - default: wxFAIL_MSG(wxT("Invalid zlib flag")); - } - - if (deflateInit2(m_deflate, level, Z_DEFLATED, windowBits, - 8, Z_DEFAULT_STRATEGY) == Z_OK) - return; - } - } - - wxLogError(_("Can't initialize zlib deflate stream.")); - m_lasterror = wxSTREAM_WRITE_ERROR; -} - -bool wxZlibOutputStream::Close() - { - DoFlush(true); - deflateEnd(m_deflate); - delete m_deflate; - - m_deflate = NULL; - delete[] m_z_buffer; - m_z_buffer = NULL; - - return wxFilterOutputStream::Close() && IsOk(); - } - -void wxZlibOutputStream::DoFlush(bool final) -{ - if (!m_deflate || !m_z_buffer) - m_lasterror = wxSTREAM_WRITE_ERROR; - if (!IsOk()) - return; - - int err = Z_OK; - bool done = false; - - while (err == Z_OK || err == Z_STREAM_END) { - size_t len = m_z_size - m_deflate->avail_out; - if (len) { - if (m_parent_o_stream->Write(m_z_buffer, len).LastWrite() != len) { - m_lasterror = wxSTREAM_WRITE_ERROR; - wxLogDebug(wxT("wxZlibOutputStream: Error writing to underlying stream")); - break; - } - m_deflate->next_out = m_z_buffer; - m_deflate->avail_out = m_z_size; - } - - if (done) - break; - err = deflate(m_deflate, final ? Z_FINISH : Z_FULL_FLUSH); - done = m_deflate->avail_out != 0 || err == Z_STREAM_END; - } -} - -size_t wxZlibOutputStream::OnSysWrite(const void *buffer, size_t size) -{ - wxASSERT_MSG(m_deflate && m_z_buffer, wxT("Deflate stream not open")); - - if (!m_deflate || !m_z_buffer) - { - // notice that this will make IsOk() test just below return false - m_lasterror = wxSTREAM_WRITE_ERROR; - } - - if (!IsOk() || !size) - return 0; - - int err = Z_OK; - m_deflate->next_in = (unsigned char *)buffer; - m_deflate->avail_in = size; - - while (err == Z_OK && m_deflate->avail_in > 0) { - if (m_deflate->avail_out == 0) { - m_parent_o_stream->Write(m_z_buffer, m_z_size); - if (m_parent_o_stream->LastWrite() != m_z_size) { - m_lasterror = wxSTREAM_WRITE_ERROR; - wxLogDebug(wxT("wxZlibOutputStream: Error writing to underlying stream")); - break; - } - - m_deflate->next_out = m_z_buffer; - m_deflate->avail_out = m_z_size; - } - - err = deflate(m_deflate, Z_NO_FLUSH); - } - - if (err != Z_OK) { - m_lasterror = wxSTREAM_WRITE_ERROR; - wxString msg(m_deflate->msg, *wxConvCurrent); - if (!msg) - msg = wxString::Format(_("zlib error %d"), err); - wxLogError(_("Can't write to deflate stream: %s"), msg.c_str()); - } - - size -= m_deflate->avail_in; - m_pos += size; - return size; -} - -/* static */ bool wxZlibOutputStream::CanHandleGZip() -{ - return wxZlibInputStream::CanHandleGZip(); -} - -#endif - // wxUSE_ZLIB && wxUSE_STREAMS +////////////////////////////////////////////////////////////////////////////// +// Name: src/common/zstream.cpp +// Purpose: Compressed stream classes +// Author: Guilhem Lavaux +// Modified by: Mike Wetherell +// Created: 11/07/98 +// RCS-ID: $Id: zstream.cpp 42621 2006-10-29 16:47:20Z MW $ +// Copyright: (c) Guilhem Lavaux +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_ZLIB && wxUSE_STREAMS + +#include "wx/zstream.h" + +#ifndef WX_PRECOMP + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/utils.h" +#endif + + +// normally, the compiler options should contain -I../zlib, but it is +// apparently not the case for all MSW makefiles and so, unless we use +// configure (which defines __WX_SETUP_H__) or it is explicitly overridden by +// the user (who can define wxUSE_ZLIB_H_IN_PATH), we hardcode the path here +#if defined(__WXMSW__) && !defined(__WX_SETUP_H__) && !defined(wxUSE_ZLIB_H_IN_PATH) + #include "../zlib/zlib.h" +#else + #include "zlib.h" +#endif + +enum { + ZSTREAM_BUFFER_SIZE = 16384, + ZSTREAM_GZIP = 0x10, // gzip header + ZSTREAM_AUTO = 0x20 // auto detect between gzip and zlib +}; + + +///////////////////////////////////////////////////////////////////////////// +// Zlib Class factory + +IMPLEMENT_DYNAMIC_CLASS(wxZlibClassFactory, wxFilterClassFactory) + +static wxZlibClassFactory g_wxZlibClassFactory; + +wxZlibClassFactory::wxZlibClassFactory() +{ + if (this == &g_wxZlibClassFactory) + PushFront(); +} + +const wxChar * const * +wxZlibClassFactory::GetProtocols(wxStreamProtocolType type) const +{ + static const wxChar *mimes[] = { _T("application/x-deflate"), NULL }; + static const wxChar *encs[] = { _T("deflate"), NULL }; + static const wxChar *empty[] = { NULL }; + + switch (type) { + case wxSTREAM_MIMETYPE: return mimes; + case wxSTREAM_ENCODING: return encs; + default: return empty; + } +} + + +///////////////////////////////////////////////////////////////////////////// +// Gzip Class factory + +IMPLEMENT_DYNAMIC_CLASS(wxGzipClassFactory, wxFilterClassFactory) + +static wxGzipClassFactory g_wxGzipClassFactory; + +wxGzipClassFactory::wxGzipClassFactory() +{ + if (this == &g_wxGzipClassFactory && wxZlibInputStream::CanHandleGZip()) + PushFront(); +} + +const wxChar * const * +wxGzipClassFactory::GetProtocols(wxStreamProtocolType type) const +{ + static const wxChar *protos[] = + { _T("gzip"), NULL }; + static const wxChar *mimes[] = + { _T("application/gzip"), _T("application/x-gzip"), NULL }; + static const wxChar *encs[] = + { _T("gzip"), NULL }; + static const wxChar *exts[] = + { _T(".gz"), _T(".gzip"), NULL }; + static const wxChar *empty[] = + { NULL }; + + switch (type) { + case wxSTREAM_PROTOCOL: return protos; + case wxSTREAM_MIMETYPE: return mimes; + case wxSTREAM_ENCODING: return encs; + case wxSTREAM_FILEEXT: return exts; + default: return empty; + } +} + + +////////////////////// +// wxZlibInputStream +////////////////////// + +wxZlibInputStream::wxZlibInputStream(wxInputStream& stream, int flags) + : wxFilterInputStream(stream) +{ + Init(flags); +} + +wxZlibInputStream::wxZlibInputStream(wxInputStream *stream, int flags) + : wxFilterInputStream(stream) +{ + Init(flags); +} + +void wxZlibInputStream::Init(int flags) +{ + m_inflate = NULL; + m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE]; + m_z_size = ZSTREAM_BUFFER_SIZE; + m_pos = 0; + +#if WXWIN_COMPATIBILITY_2_4 + // treat compatibility mode as auto + m_24compatibilty = flags == wxZLIB_24COMPATIBLE; + if (m_24compatibilty) + flags = wxZLIB_AUTO; +#endif + + // if gzip is asked for but not supported... + if ((flags == wxZLIB_GZIP || flags == wxZLIB_AUTO) && !CanHandleGZip()) { + if (flags == wxZLIB_AUTO) { + // an error will come later if the input turns out not to be a zlib + flags = wxZLIB_ZLIB; + } + else { + wxLogError(_("Gzip not supported by this version of zlib")); + m_lasterror = wxSTREAM_READ_ERROR; + return; + } + } + + if (m_z_buffer) { + m_inflate = new z_stream_s; + + if (m_inflate) { + memset(m_inflate, 0, sizeof(z_stream_s)); + + // see zlib.h for documentation on windowBits + int windowBits = MAX_WBITS; + switch (flags) { + case wxZLIB_NO_HEADER: windowBits = -MAX_WBITS; break; + case wxZLIB_ZLIB: windowBits = MAX_WBITS; break; + case wxZLIB_GZIP: windowBits = MAX_WBITS | ZSTREAM_GZIP; break; + case wxZLIB_AUTO: windowBits = MAX_WBITS | ZSTREAM_AUTO; break; + default: wxFAIL_MSG(wxT("Invalid zlib flag")); + } + + if (inflateInit2(m_inflate, windowBits) == Z_OK) + return; + } + } + + wxLogError(_("Can't initialize zlib inflate stream.")); + m_lasterror = wxSTREAM_READ_ERROR; +} + +wxZlibInputStream::~wxZlibInputStream() +{ + inflateEnd(m_inflate); + delete m_inflate; + + delete [] m_z_buffer; +} + +size_t wxZlibInputStream::OnSysRead(void *buffer, size_t size) +{ + wxASSERT_MSG(m_inflate && m_z_buffer, wxT("Inflate stream not open")); + + if (!m_inflate || !m_z_buffer) + m_lasterror = wxSTREAM_READ_ERROR; + if (!IsOk() || !size) + return 0; + + int err = Z_OK; + m_inflate->next_out = (unsigned char *)buffer; + m_inflate->avail_out = size; + + while (err == Z_OK && m_inflate->avail_out > 0) { + if (m_inflate->avail_in == 0 && m_parent_i_stream->IsOk()) { + m_parent_i_stream->Read(m_z_buffer, m_z_size); + m_inflate->next_in = m_z_buffer; + m_inflate->avail_in = m_parent_i_stream->LastRead(); + } + err = inflate(m_inflate, Z_SYNC_FLUSH); + } + + switch (err) { + case Z_OK: + break; + + case Z_STREAM_END: + if (m_inflate->avail_out) { + // Unread any data taken from past the end of the deflate stream, so that + // any additional data can be read from the underlying stream (the crc + // in a gzip for example) + if (m_inflate->avail_in) { + m_parent_i_stream->Reset(); + m_parent_i_stream->Ungetch(m_inflate->next_in, m_inflate->avail_in); + m_inflate->avail_in = 0; + } + m_lasterror = wxSTREAM_EOF; + } + break; + + case Z_BUF_ERROR: + // Indicates that zlib was expecting more data, but the parent stream + // has none. Other than Eof the error will have been already reported + // by the parent strean, + m_lasterror = wxSTREAM_READ_ERROR; + if (m_parent_i_stream->Eof()) +#if WXWIN_COMPATIBILITY_2_4 + if (m_24compatibilty) + m_lasterror = wxSTREAM_EOF; + else +#endif + wxLogError(_("Can't read inflate stream: unexpected EOF in underlying stream.")); + break; + + default: + wxString msg(m_inflate->msg, *wxConvCurrent); + if (!msg) + msg = wxString::Format(_("zlib error %d"), err); + wxLogError(_("Can't read from inflate stream: %s"), msg.c_str()); + m_lasterror = wxSTREAM_READ_ERROR; + } + + size -= m_inflate->avail_out; + m_pos += size; + return size; +} + +/* static */ bool wxZlibInputStream::CanHandleGZip() +{ + const char *dot = strchr(zlibVersion(), '.'); + int major = atoi(zlibVersion()); + int minor = dot ? atoi(dot + 1) : 0; + return major > 1 || (major == 1 && minor >= 2); +} + + +////////////////////// +// wxZlibOutputStream +////////////////////// + +wxZlibOutputStream::wxZlibOutputStream(wxOutputStream& stream, + int level, + int flags) + : wxFilterOutputStream(stream) +{ + Init(level, flags); +} + +wxZlibOutputStream::wxZlibOutputStream(wxOutputStream *stream, + int level, + int flags) + : wxFilterOutputStream(stream) +{ + Init(level, flags); +} + +void wxZlibOutputStream::Init(int level, int flags) +{ + m_deflate = NULL; + m_z_buffer = new unsigned char[ZSTREAM_BUFFER_SIZE]; + m_z_size = ZSTREAM_BUFFER_SIZE; + m_pos = 0; + + if ( level == -1 ) + { + level = Z_DEFAULT_COMPRESSION; + } + else + { + wxASSERT_MSG(level >= 0 && level <= 9, wxT("wxZlibOutputStream compression level must be between 0 and 9!")); + } + + // if gzip is asked for but not supported... + if (flags == wxZLIB_GZIP && !CanHandleGZip()) { + wxLogError(_("Gzip not supported by this version of zlib")); + m_lasterror = wxSTREAM_WRITE_ERROR; + return; + } + + if (m_z_buffer) { + m_deflate = new z_stream_s; + + if (m_deflate) { + memset(m_deflate, 0, sizeof(z_stream_s)); + m_deflate->next_out = m_z_buffer; + m_deflate->avail_out = m_z_size; + + // see zlib.h for documentation on windowBits + int windowBits = MAX_WBITS; + switch (flags) { + case wxZLIB_NO_HEADER: windowBits = -MAX_WBITS; break; + case wxZLIB_ZLIB: windowBits = MAX_WBITS; break; + case wxZLIB_GZIP: windowBits = MAX_WBITS | ZSTREAM_GZIP; break; + default: wxFAIL_MSG(wxT("Invalid zlib flag")); + } + + if (deflateInit2(m_deflate, level, Z_DEFLATED, windowBits, + 8, Z_DEFAULT_STRATEGY) == Z_OK) + return; + } + } + + wxLogError(_("Can't initialize zlib deflate stream.")); + m_lasterror = wxSTREAM_WRITE_ERROR; +} + +bool wxZlibOutputStream::Close() + { + DoFlush(true); + deflateEnd(m_deflate); + delete m_deflate; + + m_deflate = NULL; + delete[] m_z_buffer; + m_z_buffer = NULL; + + return wxFilterOutputStream::Close() && IsOk(); + } + +void wxZlibOutputStream::DoFlush(bool final) +{ + if (!m_deflate || !m_z_buffer) + m_lasterror = wxSTREAM_WRITE_ERROR; + if (!IsOk()) + return; + + int err = Z_OK; + bool done = false; + + while (err == Z_OK || err == Z_STREAM_END) { + size_t len = m_z_size - m_deflate->avail_out; + if (len) { + if (m_parent_o_stream->Write(m_z_buffer, len).LastWrite() != len) { + m_lasterror = wxSTREAM_WRITE_ERROR; + wxLogDebug(wxT("wxZlibOutputStream: Error writing to underlying stream")); + break; + } + m_deflate->next_out = m_z_buffer; + m_deflate->avail_out = m_z_size; + } + + if (done) + break; + err = deflate(m_deflate, final ? Z_FINISH : Z_FULL_FLUSH); + done = m_deflate->avail_out != 0 || err == Z_STREAM_END; + } +} + +size_t wxZlibOutputStream::OnSysWrite(const void *buffer, size_t size) +{ + wxASSERT_MSG(m_deflate && m_z_buffer, wxT("Deflate stream not open")); + + if (!m_deflate || !m_z_buffer) + { + // notice that this will make IsOk() test just below return false + m_lasterror = wxSTREAM_WRITE_ERROR; + } + + if (!IsOk() || !size) + return 0; + + int err = Z_OK; + m_deflate->next_in = (unsigned char *)buffer; + m_deflate->avail_in = size; + + while (err == Z_OK && m_deflate->avail_in > 0) { + if (m_deflate->avail_out == 0) { + m_parent_o_stream->Write(m_z_buffer, m_z_size); + if (m_parent_o_stream->LastWrite() != m_z_size) { + m_lasterror = wxSTREAM_WRITE_ERROR; + wxLogDebug(wxT("wxZlibOutputStream: Error writing to underlying stream")); + break; + } + + m_deflate->next_out = m_z_buffer; + m_deflate->avail_out = m_z_size; + } + + err = deflate(m_deflate, Z_NO_FLUSH); + } + + if (err != Z_OK) { + m_lasterror = wxSTREAM_WRITE_ERROR; + wxString msg(m_deflate->msg, *wxConvCurrent); + if (!msg) + msg = wxString::Format(_("zlib error %d"), err); + wxLogError(_("Can't write to deflate stream: %s"), msg.c_str()); + } + + size -= m_deflate->avail_in; + m_pos += size; + return size; +} + +/* static */ bool wxZlibOutputStream::CanHandleGZip() +{ + return wxZlibInputStream::CanHandleGZip(); +} + +#endif + // wxUSE_ZLIB && wxUSE_STREAMS diff --git a/Source/3rd Party/wx/src/generic/panelg.cpp b/Source/3rd Party/wx/src/generic/panelg.cpp new file mode 100644 index 000000000..cd4dbee65 --- /dev/null +++ b/Source/3rd Party/wx/src/generic/panelg.cpp @@ -0,0 +1,180 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/generic/panelg.cpp +// Purpose: wxPanel and the keyboard handling code +// Author: Julian Smart, Robert Roebling, Vadim Zeitlin +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: panelg.cpp 40307 2006-07-25 01:31:13Z VZ $ +// Copyright: (c) Julian Smart +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#ifndef WX_PRECOMP + #include "wx/object.h" + #include "wx/font.h" + #include "wx/colour.h" + #include "wx/settings.h" + #include "wx/log.h" + #include "wx/panel.h" + #include "wx/containr.h" +#endif + +// ---------------------------------------------------------------------------- +// wxWin macros +// ---------------------------------------------------------------------------- + +#if wxUSE_EXTENDED_RTTI +WX_DEFINE_FLAGS( wxPanelStyle ) + +wxBEGIN_FLAGS( wxPanelStyle ) + // new style border flags, we put them first to + // use them for streaming out + wxFLAGS_MEMBER(wxBORDER_SIMPLE) + wxFLAGS_MEMBER(wxBORDER_SUNKEN) + wxFLAGS_MEMBER(wxBORDER_DOUBLE) + wxFLAGS_MEMBER(wxBORDER_RAISED) + wxFLAGS_MEMBER(wxBORDER_STATIC) + wxFLAGS_MEMBER(wxBORDER_NONE) + + // old style border flags + wxFLAGS_MEMBER(wxSIMPLE_BORDER) + wxFLAGS_MEMBER(wxSUNKEN_BORDER) + wxFLAGS_MEMBER(wxDOUBLE_BORDER) + wxFLAGS_MEMBER(wxRAISED_BORDER) + wxFLAGS_MEMBER(wxSTATIC_BORDER) + wxFLAGS_MEMBER(wxBORDER) + + // standard window styles + wxFLAGS_MEMBER(wxTAB_TRAVERSAL) + wxFLAGS_MEMBER(wxCLIP_CHILDREN) + wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) + wxFLAGS_MEMBER(wxWANTS_CHARS) + wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) + wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) + wxFLAGS_MEMBER(wxVSCROLL) + wxFLAGS_MEMBER(wxHSCROLL) + +wxEND_FLAGS( wxPanelStyle ) + +IMPLEMENT_DYNAMIC_CLASS_XTI(wxPanel, wxWindow,"wx/panel.h") + +wxBEGIN_PROPERTIES_TABLE(wxPanel) + wxPROPERTY_FLAGS( WindowStyle , wxPanelStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style +// style wxTAB_TRAVERSAL +wxEND_PROPERTIES_TABLE() + +wxBEGIN_HANDLERS_TABLE(wxPanel) +wxEND_HANDLERS_TABLE() + +wxCONSTRUCTOR_5( wxPanel , wxWindow* , Parent , wxWindowID , Id , wxPoint , Position , wxSize , Size , long , WindowStyle ) + +#else +IMPLEMENT_DYNAMIC_CLASS(wxPanel, wxWindow) +#endif + +BEGIN_EVENT_TABLE(wxPanel, wxWindow) + EVT_SIZE(wxPanel::OnSize) + + WX_EVENT_TABLE_CONTROL_CONTAINER(wxPanel) +END_EVENT_TABLE() + +// ============================================================================ +// implementation +// ============================================================================ + +WX_DELEGATE_TO_CONTROL_CONTAINER(wxPanel, wxWindow) + +// ---------------------------------------------------------------------------- +// wxPanel creation +// ---------------------------------------------------------------------------- + +void wxPanel::Init() +{ + m_container.SetContainerWindow(this); +} + +bool wxPanel::Create(wxWindow *parent, wxWindowID id, + const wxPoint& pos, + const wxSize& size, + long style, + const wxString& name) +{ + if ( !wxWindow::Create(parent, id, pos, size, style, name) ) + return false; + + // so that non-solid background renders correctly under GTK+: + SetThemeEnabled(true); + +#if defined(__WXWINCE__) && (defined(__POCKETPC__) || defined(__SMARTPHONE__)) + // Required to get solid control backgrounds under WinCE + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW)); +#endif + + return true; +} + +wxPanel::~wxPanel() +{ +} + +void wxPanel::InitDialog() +{ + wxInitDialogEvent event(GetId()); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +void wxPanel::OnSize(wxSizeEvent& event) +{ + if (GetAutoLayout()) + Layout(); +#if wxUSE_CONSTRAINTS +#if defined(__WXPM__) && 0 + else + { + // Need to properly move child windows under OS/2 + + PSWP pWinSwp = GetSwp(); + + if (pWinSwp->cx == 0 && pWinSwp->cy == 0 && pWinSwp->fl == 0) + { + // Uninitialized + + ::WinQueryWindowPos(GetHWND(), pWinSwp); + } + else + { + SWP vSwp; + int nYDiff; + + ::WinQueryWindowPos(GetHWND(), &vSwp); + nYDiff = pWinSwp->cy - vSwp.cy; + MoveChildren(nYDiff); + pWinSwp->cx = vSwp.cx; + pWinSwp->cy = vSwp.cy; + } + } +#endif +#endif // wxUSE_CONSTRAINTS + + event.Skip(); +} diff --git a/Source/3rd Party/wx/src/msw/slider95.cpp b/Source/3rd Party/wx/src/msw/slider95.cpp new file mode 100644 index 000000000..19565b1c3 --- /dev/null +++ b/Source/3rd Party/wx/src/msw/slider95.cpp @@ -0,0 +1,686 @@ +///////////////////////////////////////////////////////////////////////////// +// Name: src/msw/slider.cpp +// Purpose: wxSlider, using the Win95 (and later) trackbar control +// Author: Julian Smart +// Modified by: +// Created: 04/01/98 +// RCS-ID: $Id: slider95.cpp 41054 2006-09-07 19:01:45Z ABX $ +// Copyright: (c) Julian Smart 1998 +// Vadim Zeitlin 2004 +// Licence: wxWindows licence +///////////////////////////////////////////////////////////////////////////// + +// ============================================================================ +// declarations +// ============================================================================ + +// ---------------------------------------------------------------------------- +// headers +// ---------------------------------------------------------------------------- + +// For compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_SLIDER + +#include "wx/slider.h" + +#ifndef WX_PRECOMP + #include "wx/msw/wrapcctl.h" // include "properly" + #include "wx/brush.h" +#endif + +#include "wx/msw/subwin.h" + +// ---------------------------------------------------------------------------- +// constants +// ---------------------------------------------------------------------------- + +// indices of labels in wxSlider::m_labels +enum +{ + SliderLabel_Min, + SliderLabel_Max, + SliderLabel_Value, + SliderLabel_Last +}; + +// the gap between the slider and the labels, in pixels +static const int HGAP = 5; + +// ---------------------------------------------------------------------------- +// XTI +// ---------------------------------------------------------------------------- + +#if wxUSE_EXTENDED_RTTI +WX_DEFINE_FLAGS( wxSliderStyle ) + +wxBEGIN_FLAGS( wxSliderStyle ) + // new style border flags, we put them first to + // use them for streaming out + wxFLAGS_MEMBER(wxBORDER_SIMPLE) + wxFLAGS_MEMBER(wxBORDER_SUNKEN) + wxFLAGS_MEMBER(wxBORDER_DOUBLE) + wxFLAGS_MEMBER(wxBORDER_RAISED) + wxFLAGS_MEMBER(wxBORDER_STATIC) + wxFLAGS_MEMBER(wxBORDER_NONE) + + // old style border flags + wxFLAGS_MEMBER(wxSIMPLE_BORDER) + wxFLAGS_MEMBER(wxSUNKEN_BORDER) + wxFLAGS_MEMBER(wxDOUBLE_BORDER) + wxFLAGS_MEMBER(wxRAISED_BORDER) + wxFLAGS_MEMBER(wxSTATIC_BORDER) + wxFLAGS_MEMBER(wxBORDER) + + // standard window styles + wxFLAGS_MEMBER(wxTAB_TRAVERSAL) + wxFLAGS_MEMBER(wxCLIP_CHILDREN) + wxFLAGS_MEMBER(wxTRANSPARENT_WINDOW) + wxFLAGS_MEMBER(wxWANTS_CHARS) + wxFLAGS_MEMBER(wxFULL_REPAINT_ON_RESIZE) + wxFLAGS_MEMBER(wxALWAYS_SHOW_SB ) + wxFLAGS_MEMBER(wxVSCROLL) + wxFLAGS_MEMBER(wxHSCROLL) + + wxFLAGS_MEMBER(wxSL_HORIZONTAL) + wxFLAGS_MEMBER(wxSL_VERTICAL) + wxFLAGS_MEMBER(wxSL_AUTOTICKS) + wxFLAGS_MEMBER(wxSL_LABELS) + wxFLAGS_MEMBER(wxSL_LEFT) + wxFLAGS_MEMBER(wxSL_TOP) + wxFLAGS_MEMBER(wxSL_RIGHT) + wxFLAGS_MEMBER(wxSL_BOTTOM) + wxFLAGS_MEMBER(wxSL_BOTH) + wxFLAGS_MEMBER(wxSL_SELRANGE) + wxFLAGS_MEMBER(wxSL_INVERSE) + +wxEND_FLAGS( wxSliderStyle ) + +IMPLEMENT_DYNAMIC_CLASS_XTI(wxSlider, wxControl,"wx/slider.h") + +wxBEGIN_PROPERTIES_TABLE(wxSlider) + wxEVENT_RANGE_PROPERTY( Scroll , wxEVT_SCROLL_TOP , wxEVT_SCROLL_CHANGED , wxScrollEvent ) + wxEVENT_PROPERTY( Updated , wxEVT_COMMAND_SLIDER_UPDATED , wxCommandEvent ) + + wxPROPERTY( Value , int , SetValue, GetValue , 0, 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( Minimum , int , SetMin, GetMin, 0 , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( Maximum , int , SetMax, GetMax, 0 , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( PageSize , int , SetPageSize, GetLineSize, 1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( LineSize , int , SetLineSize, GetLineSize, 1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY( ThumbLength , int , SetThumbLength, GetThumbLength, 1 , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) + wxPROPERTY_FLAGS( WindowStyle , wxSliderStyle , long , SetWindowStyleFlag , GetWindowStyleFlag , EMPTY_MACROVALUE , 0 /*flags*/ , wxT("Helpstring") , wxT("group")) // style +wxEND_PROPERTIES_TABLE() + +wxBEGIN_HANDLERS_TABLE(wxSlider) +wxEND_HANDLERS_TABLE() + +wxCONSTRUCTOR_8( wxSlider , wxWindow* , Parent , wxWindowID , Id , int , Value , int , Minimum , int , Maximum , wxPoint , Position , wxSize , Size , long , WindowStyle ) +#else +IMPLEMENT_DYNAMIC_CLASS(wxSlider, wxControl) +#endif + +// ============================================================================ +// wxSlider implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// construction +// ---------------------------------------------------------------------------- + +void wxSlider::Init() +{ + m_labels = NULL; + + m_pageSize = 1; + m_lineSize = 1; + m_rangeMax = 0; + m_rangeMin = 0; + m_tickFreq = 0; + + m_isDragging = false; +} + +bool +wxSlider::Create(wxWindow *parent, + wxWindowID id, + int value, + int minValue, + int maxValue, + const wxPoint& pos, + const wxSize& size, + long style, + const wxValidator& validator, + const wxString& name) +{ + // our styles are redundant: wxSL_LEFT/RIGHT imply wxSL_VERTICAL and + // wxSL_TOP/BOTTOM imply wxSL_HORIZONTAL, but for backwards compatibility + // reasons we can't really change it, instead try to infer the orientation + // from the flags given to us here + switch ( style & (wxSL_LEFT | wxSL_RIGHT | wxSL_TOP | wxSL_BOTTOM) ) + { + case wxSL_LEFT: + case wxSL_RIGHT: + style |= wxSL_VERTICAL; + break; + + case wxSL_TOP: + case wxSL_BOTTOM: + style |= wxSL_HORIZONTAL; + break; + + case 0: + // no specific direction, do we have at least the orientation? + if ( !(style & (wxSL_HORIZONTAL | wxSL_VERTICAL)) ) + { + // no, choose default + style |= wxSL_BOTTOM | wxSL_HORIZONTAL; + } + }; + + wxASSERT_MSG( !(style & wxSL_VERTICAL) || !(style & wxSL_HORIZONTAL), + _T("incompatible slider direction and orientation") ); + + + // initialize everything + if ( !CreateControl(parent, id, pos, size, style, validator, name) ) + return false; + + // ensure that we have correct values for GetLabelsSize() + m_rangeMin = minValue; + m_rangeMax = maxValue; + + // create the labels first, so that our DoGetBestSize() could take them + // into account + // + // note that we could simply create 3 wxStaticTexts here but it could + // result in some observable side effects at wx level (e.g. the parent of + // wxSlider would have 3 more children than expected) and so we prefer not + // to do it like this + if ( m_windowStyle & wxSL_LABELS ) + { + m_labels = new wxSubwindows(SliderLabel_Last); + + HWND hwndParent = GetHwndOf(parent); + for ( size_t n = 0; n < SliderLabel_Last; n++ ) + { + (*m_labels)[n] = ::CreateWindow + ( + wxT("STATIC"), + NULL, + WS_CHILD | WS_VISIBLE | SS_CENTER, + 0, 0, 0, 0, + hwndParent, + (HMENU)NewControlId(), + wxGetInstance(), + NULL + ); + } + + m_labels->SetFont(GetFont()); + } + + // now create the main control too + if ( !MSWCreateControl(TRACKBAR_CLASS, wxEmptyString, pos, size) ) + return false; + + // and initialize everything + SetRange(minValue, maxValue); + SetValue(value); + SetPageSize((maxValue - minValue)/10); + + // we need to position the labels correctly if we have them and if + // SetSize() hadn't been called before (when best size was determined by + // MSWCreateControl()) as in this case they haven't been put in place yet + if ( m_labels && size.x != wxDefaultCoord && size.y != wxDefaultCoord ) + { + SetSize(size); + } + + return true; +} + +WXDWORD wxSlider::MSWGetStyle(long style, WXDWORD *exstyle) const +{ + WXDWORD msStyle = wxControl::MSWGetStyle(style, exstyle); + + // TBS_HORZ, TBS_RIGHT and TBS_BOTTOM are 0 but do include them for clarity + msStyle |= style & wxSL_VERTICAL ? TBS_VERT : TBS_HORZ; + + if ( style & wxSL_BOTH ) + { + // this fully specifies the style combined with TBS_VERT/HORZ above + msStyle |= TBS_BOTH; + } + else // choose one direction + { + if ( style & wxSL_LEFT ) + msStyle |= TBS_LEFT; + else if ( style & wxSL_RIGHT ) + msStyle |= TBS_RIGHT; + else if ( style & wxSL_TOP ) + msStyle |= TBS_TOP; + else if ( style & wxSL_BOTTOM ) + msStyle |= TBS_BOTTOM; + } + + if ( style & wxSL_AUTOTICKS ) + msStyle |= TBS_AUTOTICKS; + else + msStyle |= TBS_NOTICKS; + + if ( style & wxSL_SELRANGE ) + msStyle |= TBS_ENABLESELRANGE; + + return msStyle; +} + +wxSlider::~wxSlider() +{ + delete m_labels; +} + +// ---------------------------------------------------------------------------- +// event handling +// ---------------------------------------------------------------------------- + +bool wxSlider::MSWOnScroll(int WXUNUSED(orientation), + WXWORD wParam, + WXWORD WXUNUSED(pos), + WXHWND control) +{ + wxEventType scrollEvent; + switch ( wParam ) + { + case SB_TOP: + scrollEvent = wxEVT_SCROLL_TOP; + break; + + case SB_BOTTOM: + scrollEvent = wxEVT_SCROLL_BOTTOM; + break; + + case SB_LINEUP: + scrollEvent = wxEVT_SCROLL_LINEUP; + break; + + case SB_LINEDOWN: + scrollEvent = wxEVT_SCROLL_LINEDOWN; + break; + + case SB_PAGEUP: + scrollEvent = wxEVT_SCROLL_PAGEUP; + break; + + case SB_PAGEDOWN: + scrollEvent = wxEVT_SCROLL_PAGEDOWN; + break; + + case SB_THUMBTRACK: + scrollEvent = wxEVT_SCROLL_THUMBTRACK; + m_isDragging = true; + break; + + case SB_THUMBPOSITION: + if ( m_isDragging ) + { + scrollEvent = wxEVT_SCROLL_THUMBRELEASE; + m_isDragging = false; + } + else + { + // this seems to only happen when the mouse wheel is used: in + // this case, as it might be unexpected to get THUMBRELEASE + // without preceding THUMBTRACKs, we don't generate it at all + // but generate CHANGED event because the control itself does + // not send us SB_ENDSCROLL for whatever reason when mouse + // wheel is used + scrollEvent = wxEVT_SCROLL_CHANGED; + } + break; + + case SB_ENDSCROLL: + scrollEvent = wxEVT_SCROLL_CHANGED; + break; + + default: + // unknown scroll event? + return false; + } + + int newPos = ValueInvertOrNot((int) ::SendMessage((HWND) control, TBM_GETPOS, 0, 0)); + if ( (newPos < GetMin()) || (newPos > GetMax()) ) + { + // out of range - but we did process it + return true; + } + + SetValue(newPos); + + wxScrollEvent event(scrollEvent, m_windowId); + event.SetPosition(newPos); + event.SetEventObject( this ); + GetEventHandler()->ProcessEvent(event); + + wxCommandEvent cevent( wxEVT_COMMAND_SLIDER_UPDATED, GetId() ); + cevent.SetInt( newPos ); + cevent.SetEventObject( this ); + + return GetEventHandler()->ProcessEvent( cevent ); +} + +void wxSlider::Command (wxCommandEvent & event) +{ + SetValue (event.GetInt()); + ProcessCommand (event); +} + +// ---------------------------------------------------------------------------- +// geometry stuff +// ---------------------------------------------------------------------------- + +wxRect wxSlider::GetBoundingBox() const +{ + // take care not to call our own functions which would call us recursively + int x, y, w, h; + wxSliderBase::DoGetPosition(&x, &y); + wxSliderBase::DoGetSize(&w, &h); + + wxRect rect(x, y, w, h); + if ( m_labels ) + { + wxRect lrect = m_labels->GetBoundingBox(); + GetParent()->ScreenToClient(&lrect.x, &lrect.y); + rect.Union(lrect); + } + + return rect; +} + +void wxSlider::DoGetSize(int *width, int *height) const +{ + wxRect rect = GetBoundingBox(); + + if ( width ) + *width = rect.width; + if ( height ) + *height = rect.height; +} + +void wxSlider::DoGetPosition(int *x, int *y) const +{ + wxRect rect = GetBoundingBox(); + + if ( x ) + *x = rect.x; + if ( y ) + *y = rect.y; +} + +int wxSlider::GetLabelsSize(int *width) const +{ + int cy; + + if ( width ) + { + // find the max label width + int wLabelMin, wLabelMax; + GetTextExtent(Format(m_rangeMin), &wLabelMin, &cy); + GetTextExtent(Format(m_rangeMax), &wLabelMax, &cy); + + *width = wxMax(wLabelMin, wLabelMax); + } + else + { + cy = GetCharHeight(); + } + + return EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy); +} + +void wxSlider::DoMoveWindow(int x, int y, int width, int height) +{ + // all complications below are because we need to position the labels, + // without them everything is easy + if ( !m_labels ) + { + wxSliderBase::DoMoveWindow(x, y, width, height); + return; + } + + // be careful to position the slider itself after moving the labels as + // otherwise our GetBoundingBox(), which is called from WM_SIZE handler, + // would return a wrong result and wrong size would be cached internally + if ( HasFlag(wxSL_VERTICAL) ) + { + int wLabel; + int hLabel = GetLabelsSize(&wLabel); + + int xLabel = HasFlag(wxSL_LEFT) ? x + width - wLabel : x; + + // position all labels: min at the top, value in the middle and max at + // the bottom + DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min], + xLabel, y, wLabel, hLabel); + + DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value], + xLabel, y + (height - hLabel)/2, wLabel, hLabel); + + DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max], + xLabel, y + height - hLabel, wLabel, hLabel); + + // position the slider itself along the left/right edge + wxSliderBase::DoMoveWindow(HasFlag(wxSL_LEFT) ? x : x + wLabel + HGAP, + y + hLabel/2, + width - wLabel - HGAP, + height - hLabel); + } + else // horizontal + { + int wLabel; + int hLabel = GetLabelsSize(&wLabel); + + int yLabel = HasFlag(wxSL_TOP) ? y + height - hLabel : y; + + // position all labels: min on the left, value in the middle and max to + // the right + DoMoveSibling((HWND)(*m_labels)[SliderLabel_Min], + x, yLabel, wLabel, hLabel); + + DoMoveSibling((HWND)(*m_labels)[SliderLabel_Value], + x + (width - wLabel)/2, yLabel, wLabel, hLabel); + + DoMoveSibling((HWND)(*m_labels)[SliderLabel_Max], + x + width - wLabel, yLabel, wLabel, hLabel); + + // position the slider itself along the top/bottom edge + wxSliderBase::DoMoveWindow(x, + HasFlag(wxSL_TOP) ? y : y + hLabel, + width, + height - hLabel); + } +} + +wxSize wxSlider::DoGetBestSize() const +{ + // these values are arbitrary + static const int length = 100; + static const int thumb = 24; + static const int ticks = 8; + + int *width; + wxSize size; + if ( HasFlag(wxSL_VERTICAL) ) + { + size.x = thumb; + size.y = length; + width = &size.x; + + if ( m_labels ) + { + int wLabel; + int hLabel = GetLabelsSize(&wLabel); + + // account for the labels + size.x += HGAP + wLabel; + + // labels are indented relative to the slider itself + size.y += hLabel; + } + } + else // horizontal + { + size.x = length; + size.y = thumb; + width = &size.y; + + if ( m_labels ) + { + // labels add extra height + size.y += GetLabelsSize(); + } + } + + // need extra space to show ticks + if ( HasFlag(wxSL_TICKS) ) + { + *width += ticks; + + // and maybe twice as much if we show them on both sides + if ( HasFlag(wxSL_BOTH) ) + *width += ticks; + } + + return size; +} + +// ---------------------------------------------------------------------------- +// slider-specific methods +// ---------------------------------------------------------------------------- + +int wxSlider::GetValue() const +{ + return ValueInvertOrNot(::SendMessage(GetHwnd(), TBM_GETPOS, 0, 0)); +} + +void wxSlider::SetValue(int value) +{ + ::SendMessage(GetHwnd(), TBM_SETPOS, (WPARAM)TRUE, (LPARAM)ValueInvertOrNot(value)); + + if ( m_labels ) + { + ::SetWindowText((*m_labels)[SliderLabel_Value], Format(value)); + } +} + +void wxSlider::SetRange(int minValue, int maxValue) +{ + m_rangeMin = minValue; + m_rangeMax = maxValue; + + ::SendMessage(GetHwnd(), TBM_SETRANGEMIN, TRUE, m_rangeMin); + ::SendMessage(GetHwnd(), TBM_SETRANGEMAX, TRUE, m_rangeMax); + + if ( m_labels ) + { + ::SetWindowText((*m_labels)[SliderLabel_Min], Format(ValueInvertOrNot(m_rangeMin))); + ::SetWindowText((*m_labels)[SliderLabel_Max], Format(ValueInvertOrNot(m_rangeMax))); + } +} + +void wxSlider::SetTickFreq(int n, int pos) +{ + m_tickFreq = n; + ::SendMessage( GetHwnd(), TBM_SETTICFREQ, (WPARAM) n, (LPARAM) pos ); +} + +void wxSlider::SetPageSize(int pageSize) +{ + ::SendMessage( GetHwnd(), TBM_SETPAGESIZE, (WPARAM) 0, (LPARAM) pageSize ); + m_pageSize = pageSize; +} + +int wxSlider::GetPageSize() const +{ + return m_pageSize; +} + +void wxSlider::ClearSel() +{ + ::SendMessage(GetHwnd(), TBM_CLEARSEL, (WPARAM) TRUE, (LPARAM) 0); +} + +void wxSlider::ClearTicks() +{ + ::SendMessage(GetHwnd(), TBM_CLEARTICS, (WPARAM) TRUE, (LPARAM) 0); +} + +void wxSlider::SetLineSize(int lineSize) +{ + m_lineSize = lineSize; + ::SendMessage(GetHwnd(), TBM_SETLINESIZE, (WPARAM) 0, (LPARAM) lineSize); +} + +int wxSlider::GetLineSize() const +{ + return (int)::SendMessage(GetHwnd(), TBM_GETLINESIZE, 0, 0); +} + +int wxSlider::GetSelEnd() const +{ + return (int)::SendMessage(GetHwnd(), TBM_GETSELEND, 0, 0); +} + +int wxSlider::GetSelStart() const +{ + return (int)::SendMessage(GetHwnd(), TBM_GETSELSTART, 0, 0); +} + +void wxSlider::SetSelection(int minPos, int maxPos) +{ + ::SendMessage(GetHwnd(), TBM_SETSEL, + (WPARAM) TRUE /* redraw */, + (LPARAM) MAKELONG( minPos, maxPos) ); +} + +void wxSlider::SetThumbLength(int len) +{ + ::SendMessage(GetHwnd(), TBM_SETTHUMBLENGTH, (WPARAM) len, (LPARAM) 0); +} + +int wxSlider::GetThumbLength() const +{ + return (int)::SendMessage( GetHwnd(), TBM_GETTHUMBLENGTH, 0, 0); +} + +void wxSlider::SetTick(int tickPos) +{ + ::SendMessage( GetHwnd(), TBM_SETTIC, (WPARAM) 0, (LPARAM) tickPos ); +} + +// ---------------------------------------------------------------------------- +// composite control methods +// ---------------------------------------------------------------------------- + +WXHWND wxSlider::GetStaticMin() const +{ + return m_labels ? (WXHWND)(*m_labels)[SliderLabel_Min] : NULL; +} + +WXHWND wxSlider::GetStaticMax() const +{ + return m_labels ? (WXHWND)(*m_labels)[SliderLabel_Max] : NULL; +} + +WXHWND wxSlider::GetEditValue() const +{ + return m_labels ? (WXHWND)(*m_labels)[SliderLabel_Value] : NULL; +} + +WX_FORWARD_STD_METHODS_TO_SUBWINDOWS(wxSlider, wxSliderBase, m_labels) + +#endif // wxUSE_SLIDER diff --git a/Source/3rd Party/wx/src/msw/statbr95.cpp b/Source/3rd Party/wx/src/msw/statbr95.cpp new file mode 100644 index 000000000..4288885f0 --- /dev/null +++ b/Source/3rd Party/wx/src/msw/statbr95.cpp @@ -0,0 +1,417 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: src/msw/statbr95.cpp +// Purpose: native implementation of wxStatusBar +// Author: Vadim Zeitlin +// Modified by: +// Created: 04.04.98 +// RCS-ID: $Id: statbr95.cpp 48670 2007-09-14 07:15:51Z JS $ +// Copyright: (c) 1998 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +// for compilers that support precompilation, includes "wx.h". +#include "wx/wxprec.h" + +#ifdef __BORLANDC__ + #pragma hdrstop +#endif + +#if wxUSE_STATUSBAR && wxUSE_NATIVE_STATUSBAR + +#include "wx/statusbr.h" + +#ifndef WX_PRECOMP + #include "wx/msw/wrapcctl.h" // include "properly" + #include "wx/frame.h" + #include "wx/settings.h" + #include "wx/dcclient.h" + #include "wx/intl.h" + #include "wx/log.h" +#endif + +#include "wx/msw/private.h" +#include + +#if wxUSE_UXTHEME + #include "wx/msw/uxtheme.h" +#endif + +// ---------------------------------------------------------------------------- +// macros +// ---------------------------------------------------------------------------- + +// windowsx.h and commctrl.h don't define those, so we do it here +#define StatusBar_SetParts(h, n, w) SendMessage(h, SB_SETPARTS, (WPARAM)n, (LPARAM)w) +#define StatusBar_SetText(h, n, t) SendMessage(h, SB_SETTEXT, (WPARAM)n, (LPARAM)(LPCTSTR)t) +#define StatusBar_GetTextLen(h, n) LOWORD(SendMessage(h, SB_GETTEXTLENGTH, (WPARAM)n, 0)) +#define StatusBar_GetText(h, n, s) LOWORD(SendMessage(h, SB_GETTEXT, (WPARAM)n, (LPARAM)(LPTSTR)s)) + +// ============================================================================ +// implementation +// ============================================================================ + +// ---------------------------------------------------------------------------- +// wxStatusBar95 class +// ---------------------------------------------------------------------------- + +wxStatusBar95::wxStatusBar95() +{ + SetParent(NULL); + m_hWnd = 0; + m_windowId = 0; +} + +bool wxStatusBar95::Create(wxWindow *parent, + wxWindowID id, + long style, + const wxString& name) +{ + wxCHECK_MSG( parent, false, wxT("status bar must have a parent") ); + + // Avoid giving the status bar a themed window + style = (style & ~wxBORDER_MASK) | wxBORDER_NONE; + + SetName(name); + SetWindowStyleFlag(style); + SetParent(parent); + + parent->AddChild(this); + + m_windowId = id == wxID_ANY ? NewControlId() : id; + + DWORD wstyle = WS_CHILD | WS_VISIBLE; + + if ( style & wxCLIP_SIBLINGS ) + wstyle |= WS_CLIPSIBLINGS; + + // setting SBARS_SIZEGRIP is perfectly useless: it's always on by default + // (at least in the version of comctl32.dll I'm using), and the only way to + // turn it off is to use CCS_TOP style - as we position the status bar + // manually anyhow (see DoMoveWindow), use CCS_TOP style if wxST_SIZEGRIP + // is not given + if ( !(style & wxST_SIZEGRIP) ) + { + wstyle |= CCS_TOP; + } + else + { +#ifndef __WXWINCE__ + // may be some versions of comctl32.dll do need it - anyhow, it won't + // do any harm + wstyle |= SBARS_SIZEGRIP; +#endif + } + + m_hWnd = (WXHWND)CreateStatusWindow(wstyle, + wxEmptyString, + GetHwndOf(parent), + m_windowId); + if ( m_hWnd == 0 ) + { + wxLogSysError(_("Failed to create a status bar.")); + + return false; + } + + SetFieldsCount(1); + SubclassWin(m_hWnd); + InheritAttributes(); + + SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_MENUBAR)); + + // we must refresh the frame size when the statusbar is created, because + // its client area might change + wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); + if ( frame ) + { + frame->SendSizeEvent(); + } + + return true; +} + +wxStatusBar95::~wxStatusBar95() +{ + // we must refresh the frame size when the statusbar is deleted but the + // frame is not - otherwise statusbar leaves a hole in the place it used to + // occupy + wxFrame *frame = wxDynamicCast(GetParent(), wxFrame); + if ( frame && !frame->IsBeingDeleted() ) + { + frame->SendSizeEvent(); + } +} + +void wxStatusBar95::SetFieldsCount(int nFields, const int *widths) +{ + // this is a Windows limitation + wxASSERT_MSG( (nFields > 0) && (nFields < 255), _T("too many fields") ); + + wxStatusBarBase::SetFieldsCount(nFields, widths); + + SetFieldsWidth(); +} + +void wxStatusBar95::SetStatusWidths(int n, const int widths[]) +{ + wxStatusBarBase::SetStatusWidths(n, widths); + + SetFieldsWidth(); +} + +void wxStatusBar95::SetFieldsWidth() +{ + if ( !m_nFields ) + return; + + int aBorders[3]; + SendMessage(GetHwnd(), SB_GETBORDERS, 0, (LPARAM)aBorders); + + int extraWidth = aBorders[2]; // space between fields + + wxArrayInt widthsAbs = + CalculateAbsWidths(GetClientSize().x - extraWidth*(m_nFields - 1)); + + int *pWidths = new int[m_nFields]; + + int nCurPos = 0; + for ( int i = 0; i < m_nFields; i++ ) { + nCurPos += widthsAbs[i] + extraWidth; + pWidths[i] = nCurPos; + } + + if ( !StatusBar_SetParts(GetHwnd(), m_nFields, pWidths) ) { + wxLogLastError(wxT("StatusBar_SetParts")); + } + + delete [] pWidths; +} + +void wxStatusBar95::SetStatusText(const wxString& strText, int nField) +{ + wxCHECK_RET( (nField >= 0) && (nField < m_nFields), + _T("invalid statusbar field index") ); + + if ( strText == GetStatusText(nField) ) + { + // don't call StatusBar_SetText() to avoid flicker + return; + } + + // Get field style, if any + int style; + if (m_statusStyles) + { + switch(m_statusStyles[nField]) + { + case wxSB_RAISED: + style = SBT_POPOUT; + break; + case wxSB_FLAT: + style = SBT_NOBORDERS; + break; + case wxSB_NORMAL: + default: + style = 0; + break; + } + } + else + style = 0; + + // Pass both field number and style. MSDN library doesn't mention + // that nField and style have to be 'ORed' + if ( !StatusBar_SetText(GetHwnd(), nField | style, strText) ) + { + wxLogLastError(wxT("StatusBar_SetText")); + } +} + +wxString wxStatusBar95::GetStatusText(int nField) const +{ + wxCHECK_MSG( (nField >= 0) && (nField < m_nFields), wxEmptyString, + _T("invalid statusbar field index") ); + + wxString str; + int len = StatusBar_GetTextLen(GetHwnd(), nField); + if ( len > 0 ) + { + StatusBar_GetText(GetHwnd(), nField, wxStringBuffer(str, len)); + } + + return str; +} + +int wxStatusBar95::GetBorderX() const +{ + int aBorders[3]; + SendMessage(GetHwnd(), SB_GETBORDERS, 0, (LPARAM)aBorders); + + return aBorders[0]; +} + +int wxStatusBar95::GetBorderY() const +{ + int aBorders[3]; + SendMessage(GetHwnd(), SB_GETBORDERS, 0, (LPARAM)aBorders); + + return aBorders[1]; +} + +void wxStatusBar95::SetMinHeight(int height) +{ + SendMessage(GetHwnd(), SB_SETMINHEIGHT, height + 2*GetBorderY(), 0); + + // have to send a (dummy) WM_SIZE to redraw it now + SendMessage(GetHwnd(), WM_SIZE, 0, 0); +} + +bool wxStatusBar95::GetFieldRect(int i, wxRect& rect) const +{ + wxCHECK_MSG( (i >= 0) && (i < m_nFields), false, + _T("invalid statusbar field index") ); + + RECT r; + if ( !::SendMessage(GetHwnd(), SB_GETRECT, i, (LPARAM)&r) ) + { + wxLogLastError(wxT("SendMessage(SB_GETRECT)")); + } + +#if wxUSE_UXTHEME + wxUxThemeHandle theme((wxStatusBar95 *)this, L"Status"); // const_cast + if ( theme ) + { + // by default Windows has a 2 pixel border to the right of the left + // divider (or it could be a bug) but it looks wrong so remove it + if ( i != 0 ) + { + r.left -= 2; + } + + wxUxThemeEngine::Get()->GetThemeBackgroundContentRect(theme, NULL, + 1 /* SP_PANE */, 0, + &r, &r); + } +#endif + + wxCopyRECTToRect(r, rect); + + return true; +} + +void wxStatusBar95::DoMoveWindow(int x, int y, int width, int height) +{ + if ( GetParent()->IsSizeDeferred() ) + { + wxWindowMSW::DoMoveWindow(x, y, width, height); + } + else + { + // parent pos/size isn't deferred so do it now but don't send + // WM_WINDOWPOSCHANGING since we don't want to change pos/size later + // we must use SWP_NOCOPYBITS here otherwise it paints incorrectly + // if other windows are size deferred + ::SetWindowPos(GetHwnd(), NULL, x, y, width, height, + SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE +#ifndef __WXWINCE__ + | SWP_NOCOPYBITS | SWP_NOSENDCHANGING +#endif + ); + } + + // adjust fields widths to the new size + SetFieldsWidth(); + + // we have to trigger wxSizeEvent if there are children window in status + // bar because GetFieldRect returned incorrect (not updated) values up to + // here, which almost certainly resulted in incorrectly redrawn statusbar + if ( m_children.GetCount() > 0 ) + { + wxSizeEvent event(GetClientSize(), m_windowId); + event.SetEventObject(this); + GetEventHandler()->ProcessEvent(event); + } +} + +void wxStatusBar95::SetStatusStyles(int n, const int styles[]) +{ + wxStatusBarBase::SetStatusStyles(n, styles); + + if (n != m_nFields) + return; + + for (int i = 0; i < n; i++) + { + int style; + switch(styles[i]) + { + case wxSB_RAISED: + style = SBT_POPOUT; + break; + case wxSB_FLAT: + style = SBT_NOBORDERS; + break; + case wxSB_NORMAL: + default: + style = 0; + break; + } + // The SB_SETTEXT message is both used to set the field's text as well as + // the fields' styles. MSDN library doesn't mention + // that nField and style have to be 'ORed' + wxString text = GetStatusText(i); + if (!StatusBar_SetText(GetHwnd(), style | i, text)) + { + wxLogLastError(wxT("StatusBar_SetText")); + } + } +} + +WXLRESULT +wxStatusBar95::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam) +{ +#ifndef __WXWINCE__ + if ( nMsg == WM_WINDOWPOSCHANGING ) + { + WINDOWPOS *lpPos = (WINDOWPOS *)lParam; + int x, y, w, h; + GetPosition(&x, &y); + GetSize(&w, &h); + + // we need real window coords and not wx client coords + AdjustForParentClientOrigin(x, y); + + lpPos->x = x; + lpPos->y = y; + lpPos->cx = w; + lpPos->cy = h; + + return 0; + } + + if ( nMsg == WM_NCLBUTTONDOWN ) + { + // if hit-test is on gripper then send message to TLW to begin + // resizing. It is possible to send this message to any window. + if ( wParam == HTBOTTOMRIGHT ) + { + wxWindow *win; + + for ( win = GetParent(); win; win = win->GetParent() ) + { + if ( win->IsTopLevel() ) + { + SendMessage(GetHwndOf(win), WM_NCLBUTTONDOWN, + wParam, lParam); + + return 0; + } + } + } + } +#endif + + return wxStatusBarBase::MSWWindowProc(nMsg, wParam, lParam); +} + +#endif // wxUSE_STATUSBAR && wxUSE_NATIVE_STATUSBAR diff --git a/Source/3rd Party/wx/src/zlib/crc32.c b/Source/3rd Party/wx/src/zlib/crc32.c index 43759b16b..21eb9b630 100644 --- a/Source/3rd Party/wx/src/zlib/crc32.c +++ b/Source/3rd Party/wx/src/zlib/crc32.c @@ -25,7 +25,6 @@ # define DYNAMIC_CRC_TABLE # endif /* !DYNAMIC_CRC_TABLE */ #endif /* MAKECRCH */ - #include "zutil.h" /* for STDC and FAR definitions */ #define local static diff --git a/Source/3rd Party/wx/src/zlib/zutil.h b/Source/3rd Party/wx/src/zlib/zutil.h index 938e6d105..7b71242f2 100644 --- a/Source/3rd Party/wx/src/zlib/zutil.h +++ b/Source/3rd Party/wx/src/zlib/zutil.h @@ -196,7 +196,7 @@ extern const char * const z_errmsg[10]; /* indexed by 2-zlib_error */ # endif # ifdef WIN32 /* In Win32, vsnprintf is available as the "non-ANSI" _vsnprintf. */ -# if !defined(vsnprintf) && !defined(NO_vsnprintf) +# if !defined(vsnprintf) && !defined(NO_vsnprintf) && defined(_MSC_VER) && _MSC_VER > 1500 # define vsnprintf _vsnprintf # endif # endif diff --git a/Source/3rd Party/wx/wx_base.vcproj b/Source/3rd Party/wx/wx_base.vcproj index c3fe5d048..7bb4facf2 100644 --- a/Source/3rd Party/wx/wx_base.vcproj +++ b/Source/3rd Party/wx/wx_base.vcproj @@ -41,6 +41,7 @@ PreprocessorDefinitions="_LIB;__WXMSW__;WXBUILDING;wxUSE_GUI=0;wxUSE_BASE=1" PrecompiledHeaderThrough="wx/wxprec.h" DisableSpecificWarnings="4005" + UndefinePreprocessorDefinitions="WIN32_LEAN_AND_MEAN" /> - - @@ -154,14 +151,6 @@ RelativePath="src\common\archive.cpp" > - - - - @@ -179,11 +168,11 @@ > - - @@ -310,10 +295,6 @@ RelativePath="src\common\fs_mem.cpp" > - - @@ -334,10 +315,6 @@ RelativePath="src\common\ipcbase.cpp" > - - @@ -370,10 +347,6 @@ RelativePath="src\common\mstream.cpp" > - - @@ -402,10 +375,6 @@ RelativePath="src\common\stdpbase.cpp" > - - @@ -422,18 +391,6 @@ RelativePath="src\common\string.cpp" > - - - - - - @@ -450,42 +407,18 @@ RelativePath="src\common\textfile.cpp" > - - - - - - - - - - - - @@ -499,15 +432,7 @@ > - - - - - - - - @@ -602,10 +519,6 @@ RelativePath="src\msw\thread.cpp" > - - @@ -660,10 +573,6 @@ - - + + @@ -1244,6 +1249,10 @@ RelativePath="src\generic\numdlgg.cpp" > + + @@ -3729,11 +3738,11 @@ > diff --git a/Source/GlideHQ/TxImage.cpp b/Source/GlideHQ/TxImage.cpp index 27bb4d1a3..aaed3f775 100644 --- a/Source/GlideHQ/TxImage.cpp +++ b/Source/GlideHQ/TxImage.cpp @@ -133,7 +133,7 @@ TxImage::readPNG(FILE* fp, int* width, int* height, uint16* format) /* expand 1,2,4 bit gray scale to 8 bit gray scale */ if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_expand_gray_1_2_4_to_8(png_ptr); + png_set_expand(png_ptr); /* convert gray scale or gray scale + alpha to rgb color */ if (color_type == PNG_COLOR_TYPE_GRAY ||