home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2240.zip / wxWindows-2.4.0 / src / common / fontmap.cpp < prev    next >
C/C++ Source or Header  |  2002-11-04  |  32KB  |  1,004 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        common/fontmap.cpp
  3. // Purpose:     wxFontMapper class
  4. // Author:      Vadim Zeitlin
  5. // Modified by:
  6. // Created:     04.11.99
  7. // RCS-ID:      $Id: fontmap.cpp,v 1.46.2.5 2002/11/03 00:25:51 VZ Exp $
  8. // Copyright:   (c) Vadim Zeitlin
  9. // Licence:     wxWindows license
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. // ============================================================================
  13. // declarations
  14. // ============================================================================
  15.  
  16. // ----------------------------------------------------------------------------
  17. // headers
  18. // ----------------------------------------------------------------------------
  19.  
  20. #ifdef __GNUG__
  21.     #pragma implementation "fontmap.h"
  22. #endif
  23.  
  24. // For compilers that support precompilation, includes "wx.h".
  25. #include "wx/wxprec.h"
  26.  
  27. #ifdef __BORLANDC__
  28.     #pragma hdrstop
  29. #endif
  30.  
  31. #if wxUSE_FONTMAP
  32.  
  33. #ifndef WX_PRECOMP
  34.     #include "wx/app.h"
  35.     #include "wx/log.h"
  36.     #include "wx/intl.h"
  37. #endif // PCH
  38.  
  39. #include "wx/module.h"
  40. #include "wx/fontmap.h"
  41.  
  42. #if wxUSE_CONFIG
  43.     #include "wx/config.h"
  44.     #include "wx/memconf.h"
  45. #endif
  46.  
  47. #if wxUSE_GUI
  48.     #include "wx/fontutil.h"
  49.     #include "wx/msgdlg.h"
  50.     #include "wx/fontdlg.h"
  51.     #include "wx/choicdlg.h"
  52. #endif // wxUSE_GUI
  53.  
  54. #include "wx/encconv.h"
  55.  
  56. // ----------------------------------------------------------------------------
  57. // constants
  58. // ----------------------------------------------------------------------------
  59.  
  60. // the config paths we use
  61. #if wxUSE_CONFIG
  62. static const wxChar* FONTMAPPER_ROOT_PATH = wxT("/wxWindows/FontMapper");
  63. static const wxChar* FONTMAPPER_CHARSET_PATH = wxT("Charsets");
  64. static const wxChar* FONTMAPPER_CHARSET_ALIAS_PATH = wxT("Aliases");
  65.  
  66. // we only ask questions in GUI mode
  67. #if wxUSE_GUI
  68.     static const wxChar* FONTMAPPER_FONT_FROM_ENCODING_PATH = wxT("Encodings");
  69.     static const wxChar* FONTMAPPER_FONT_DONT_ASK = wxT("none");
  70. #endif // wxUSE_GUI
  71. #endif // wxUSE_CONFIG
  72.  
  73. // encodings supported by GetEncodingDescription
  74. static wxFontEncoding gs_encodings[] =
  75. {
  76.     wxFONTENCODING_ISO8859_1,
  77.     wxFONTENCODING_ISO8859_2,
  78.     wxFONTENCODING_ISO8859_3,
  79.     wxFONTENCODING_ISO8859_4,
  80.     wxFONTENCODING_ISO8859_5,
  81.     wxFONTENCODING_ISO8859_6,
  82.     wxFONTENCODING_ISO8859_7,
  83.     wxFONTENCODING_ISO8859_8,
  84.     wxFONTENCODING_ISO8859_9,
  85.     wxFONTENCODING_ISO8859_10,
  86.     wxFONTENCODING_ISO8859_11,
  87.     wxFONTENCODING_ISO8859_12,
  88.     wxFONTENCODING_ISO8859_13,
  89.     wxFONTENCODING_ISO8859_14,
  90.     wxFONTENCODING_ISO8859_15,
  91.     wxFONTENCODING_KOI8,
  92.     wxFONTENCODING_CP932,
  93.     wxFONTENCODING_CP936,
  94.     wxFONTENCODING_CP949,
  95.     wxFONTENCODING_CP950,
  96.     wxFONTENCODING_CP1250,
  97.     wxFONTENCODING_CP1251,
  98.     wxFONTENCODING_CP1252,
  99.     wxFONTENCODING_CP1253,
  100.     wxFONTENCODING_CP1254,
  101.     wxFONTENCODING_CP1255,
  102.     wxFONTENCODING_CP1256,
  103.     wxFONTENCODING_CP1257,
  104.     wxFONTENCODING_CP437,
  105.     wxFONTENCODING_UTF7,
  106.     wxFONTENCODING_UTF8,
  107.     wxFONTENCODING_EUC_JP,
  108. };
  109.  
  110. // the descriptions for them
  111. static const wxChar* gs_encodingDescs[] =
  112. {
  113.     wxTRANSLATE( "Western European (ISO-8859-1)" ),
  114.     wxTRANSLATE( "Central European (ISO-8859-2)" ),
  115.     wxTRANSLATE( "Esperanto (ISO-8859-3)" ),
  116.     wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ),
  117.     wxTRANSLATE( "Cyrillic (ISO-8859-5)" ),
  118.     wxTRANSLATE( "Arabic (ISO-8859-6)" ),
  119.     wxTRANSLATE( "Greek (ISO-8859-7)" ),
  120.     wxTRANSLATE( "Hebrew (ISO-8859-8)" ),
  121.     wxTRANSLATE( "Turkish (ISO-8859-9)" ),
  122.     wxTRANSLATE( "Nordic (ISO-8859-10)" ),
  123.     wxTRANSLATE( "Thai (ISO-8859-11)" ),
  124.     wxTRANSLATE( "Indian (ISO-8859-12)" ),
  125.     wxTRANSLATE( "Baltic (ISO-8859-13)" ),
  126.     wxTRANSLATE( "Celtic (ISO-8859-14)" ),
  127.     wxTRANSLATE( "Western European with Euro (ISO-8859-15)" ),
  128.     wxTRANSLATE( "KOI8-R" ),
  129.     wxTRANSLATE( "Windows Japanese (CP 932)" ),
  130.     wxTRANSLATE( "Windows Chinese Simplified (CP 936)" ),
  131.     wxTRANSLATE( "Windows Korean (CP 949)" ),
  132.     wxTRANSLATE( "Windows Chinese Traditional (CP 950)" ),
  133.     wxTRANSLATE( "Windows Central European (CP 1250)" ),
  134.     wxTRANSLATE( "Windows Cyrillic (CP 1251)" ),
  135.     wxTRANSLATE( "Windows Western European (CP 1252)" ),
  136.     wxTRANSLATE( "Windows Greek (CP 1253)" ),
  137.     wxTRANSLATE( "Windows Turkish (CP 1254)" ),
  138.     wxTRANSLATE( "Windows Hebrew (CP 1255)" ),
  139.     wxTRANSLATE( "Windows Arabic (CP 1256)" ),
  140.     wxTRANSLATE( "Windows Baltic (CP 1257)" ),
  141.     wxTRANSLATE( "Windows/DOS OEM (CP 437)" ),
  142.     wxTRANSLATE( "Unicode 7 bit (UTF-7)" ),
  143.     wxTRANSLATE( "Unicode 8 bit (UTF-8)" ),
  144.     wxTRANSLATE( "Extended Unix Codepage for Japanese (EUC-JP)" ),
  145. };
  146.  
  147. // and the internal names (these are not translated on purpose!)
  148. static const wxChar* gs_encodingNames[] =
  149. {
  150.     wxT( "iso-8859-1" ),
  151.     wxT( "iso-8859-2" ),
  152.     wxT( "iso-8859-3" ),
  153.     wxT( "iso-8859-4" ),
  154.     wxT( "iso-8859-5" ),
  155.     wxT( "iso-8859-6" ),
  156.     wxT( "iso-8859-7" ),
  157.     wxT( "iso-8859-8" ),
  158.     wxT( "iso-8859-9" ),
  159.     wxT( "iso-8859-10" ),
  160.     wxT( "iso-8859-11" ),
  161.     wxT( "iso-8859-12" ),
  162.     wxT( "iso-8859-13" ),
  163.     wxT( "iso-8859-14" ),
  164.     wxT( "iso-8859-15" ),
  165.     wxT( "koi8-r" ),
  166.     wxT( "windows-932" ),
  167.     wxT( "windows-936" ),
  168.     wxT( "windows-949" ),
  169.     wxT( "windows-950" ),
  170.     wxT( "windows-1250" ),
  171.     wxT( "windows-1251" ),
  172.     wxT( "windows-1252" ),
  173.     wxT( "windows-1253" ),
  174.     wxT( "windows-1254" ),
  175.     wxT( "windows-1255" ),
  176.     wxT( "windows-1256" ),
  177.     wxT( "windows-1257" ),
  178.     wxT( "windows-437" ),
  179.     wxT( "utf-7" ),
  180.     wxT( "utf-8" ),
  181.     wxT( "euc-jp" ),
  182. };
  183.  
  184. wxCOMPILE_TIME_ASSERT( WXSIZEOF(gs_encodingDescs) == WXSIZEOF(gs_encodings) &&
  185.                        WXSIZEOF(gs_encodingNames) == WXSIZEOF(gs_encodings),
  186.                        EncodingsArraysNotInSync );
  187.  
  188. // ----------------------------------------------------------------------------
  189. // private classes
  190. // ----------------------------------------------------------------------------
  191.  
  192. // change the config path during the lifetime of this object
  193. class wxFontMapperPathChanger
  194. {
  195. public:
  196.     wxFontMapperPathChanger(wxFontMapper *fontMapper, const wxString& path)
  197.     {
  198.         m_fontMapper = fontMapper;
  199.         m_ok = m_fontMapper->ChangePath(path, &m_pathOld);
  200.     }
  201.  
  202.     bool IsOk() const { return m_ok; }
  203.  
  204.     ~wxFontMapperPathChanger()
  205.     {
  206.         if ( IsOk() )
  207.             m_fontMapper->RestorePath(m_pathOld);
  208.     }
  209.  
  210. private:
  211.     wxFontMapper *m_fontMapper;
  212.     bool          m_ok;
  213.     wxString      m_pathOld;
  214. };
  215.  
  216. // ============================================================================
  217. // implementation
  218. // ============================================================================
  219.  
  220. // ----------------------------------------------------------------------------
  221. // ctor and dtor
  222. // ----------------------------------------------------------------------------
  223.  
  224. wxFontMapper::wxFontMapper()
  225. {
  226. #if wxUSE_CONFIG
  227.     m_config = NULL;
  228.     m_configIsDummy = FALSE;
  229. #endif // wxUSE_CONFIG
  230.  
  231. #if wxUSE_GUI
  232.     m_windowParent = NULL;
  233. #endif // wxUSE_GUI
  234. }
  235.  
  236. wxFontMapper::~wxFontMapper()
  237. {
  238. #if wxUSE_CONFIG
  239.     if ( m_configIsDummy )
  240.         delete m_config;
  241. #endif // wxUSE_CONFIG
  242. }
  243.  
  244. wxFontMapper *wxFontMapper::sm_instance = NULL;
  245.  
  246. /*static*/ wxFontMapper *wxFontMapper::Get()
  247. {
  248.     if ( !sm_instance )
  249.         sm_instance = new wxFontMapper;
  250.     return sm_instance;
  251. }
  252.  
  253. /*static*/ wxFontMapper *wxFontMapper::Set(wxFontMapper *mapper)
  254. {
  255.     wxFontMapper *old = sm_instance;
  256.     sm_instance = mapper;
  257.     return old;
  258. }
  259.  
  260. class wxFontMapperModule: public wxModule
  261. {
  262. public:
  263.     wxFontMapperModule() : wxModule() {}
  264.     virtual bool OnInit() { return TRUE; }
  265.     virtual void OnExit() { delete wxFontMapper::Set(NULL); }
  266.  
  267.     DECLARE_DYNAMIC_CLASS(wxFontMapperModule)
  268. };
  269.  
  270. IMPLEMENT_DYNAMIC_CLASS(wxFontMapperModule, wxModule)
  271.  
  272. // ----------------------------------------------------------------------------
  273. // customisation
  274. // ----------------------------------------------------------------------------
  275.  
  276. #if wxUSE_CONFIG
  277.  
  278. /* static */ const wxChar *wxFontMapper::GetDefaultConfigPath()
  279. {
  280.     return FONTMAPPER_ROOT_PATH;
  281. }
  282.  
  283. void wxFontMapper::SetConfigPath(const wxString& prefix)
  284. {
  285.     wxCHECK_RET( !prefix.IsEmpty() && prefix[0] == wxCONFIG_PATH_SEPARATOR,
  286.                  wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") );
  287.  
  288.     m_configRootPath = prefix;
  289. }
  290.  
  291. // ----------------------------------------------------------------------------
  292. // get config object and path for it
  293. // ----------------------------------------------------------------------------
  294.  
  295. wxConfigBase *wxFontMapper::GetConfig()
  296. {
  297.     if ( !m_config )
  298.     {
  299.         // try the default
  300.         m_config = wxConfig::Get(FALSE /*don't create on demand*/ );
  301.  
  302.         if ( !m_config )
  303.         {
  304.             // we still want to have a config object because otherwise we would
  305.             // keep asking the user the same questions in the interactive mode,
  306.             // so create a dummy config which won't write to any files/registry
  307.             // but will allow us to remember the results of the questions at
  308.             // least during this run
  309.             m_config = new wxMemoryConfig;
  310.             m_configIsDummy = TRUE;
  311.             // VS: we can't call wxConfig::Set(m_config) here because that would
  312.             //     disable automatic wxConfig instance creation if this code was
  313.             //     called before wxApp::OnInit (this happens in wxGTK -- it sets
  314.             //     default wxFont encoding in wxApp::Initialize())
  315.         }
  316.     }
  317.  
  318.     if ( m_configIsDummy && wxConfig::Get(FALSE) != NULL )
  319.     {
  320.         // VS: in case we created dummy m_config (see above), we want to switch back
  321.         //     to the real one as soon as one becomes available.
  322.         delete m_config;
  323.         m_config = wxConfig::Get(FALSE);
  324.         m_configIsDummy = FALSE;
  325.         // FIXME: ideally, we should add keys from dummy config to the real one now,
  326.         //        but it is a low-priority task because typical wxWin application
  327.         //        either doesn't use wxConfig at all or creates wxConfig object in
  328.         //        wxApp::OnInit(), before any real interaction with the user takes
  329.         //        place...
  330.     }
  331.  
  332.     return m_config;
  333. }
  334.  
  335. const wxString& wxFontMapper::GetConfigPath()
  336. {
  337.     if ( !m_configRootPath )
  338.     {
  339.         // use the default
  340.         m_configRootPath = GetDefaultConfigPath();
  341.     }
  342.  
  343.     return m_configRootPath;
  344. }
  345. #endif
  346.  
  347. bool wxFontMapper::ChangePath(const wxString& pathNew, wxString *pathOld)
  348. {
  349. #if wxUSE_CONFIG
  350.     wxConfigBase *config = GetConfig();
  351.     if ( !config )
  352.         return FALSE;
  353.  
  354.     *pathOld = config->GetPath();
  355.  
  356.     wxString path = GetConfigPath();
  357.     if ( path.IsEmpty() || path.Last() != wxCONFIG_PATH_SEPARATOR )
  358.     {
  359.         path += wxCONFIG_PATH_SEPARATOR;
  360.     }
  361.  
  362.     wxASSERT_MSG( !pathNew || (pathNew[0] != wxCONFIG_PATH_SEPARATOR),
  363.                   wxT("should be a relative path") );
  364.  
  365.     path += pathNew;
  366.  
  367.     config->SetPath(path);
  368.  
  369.     return TRUE;
  370. #else
  371.     return FALSE;
  372. #endif
  373. }
  374.  
  375. void wxFontMapper::RestorePath(const wxString& pathOld)
  376. {
  377. #if wxUSE_CONFIG
  378.     GetConfig()->SetPath(pathOld);
  379. #else
  380. #endif
  381. }
  382.  
  383. // ----------------------------------------------------------------------------
  384. // charset/encoding correspondence
  385. // ----------------------------------------------------------------------------
  386.  
  387. /* static */
  388. wxString wxFontMapper::GetEncodingDescription(wxFontEncoding encoding)
  389. {
  390.     if ( encoding == wxFONTENCODING_DEFAULT )
  391.     {
  392.         return _("Default encoding");
  393.     }
  394.  
  395.     const size_t count = WXSIZEOF(gs_encodingDescs);
  396.  
  397.     for ( size_t i = 0; i < count; i++ )
  398.     {
  399.         if ( gs_encodings[i] == encoding )
  400.         {
  401.             return wxGetTranslation(gs_encodingDescs[i]);
  402.         }
  403.     }
  404.  
  405.     wxString str;
  406.     str.Printf(_("Unknown encoding (%d)"), encoding);
  407.  
  408.     return str;
  409. }
  410.  
  411. /* static */
  412. wxString wxFontMapper::GetEncodingName(wxFontEncoding encoding)
  413. {
  414.     if ( encoding == wxFONTENCODING_DEFAULT )
  415.     {
  416.         return _("default");
  417.     }
  418.  
  419.     const size_t count = WXSIZEOF(gs_encodingNames);
  420.  
  421.     for ( size_t i = 0; i < count; i++ )
  422.     {
  423.         if ( gs_encodings[i] == encoding )
  424.         {
  425.             return gs_encodingNames[i];
  426.         }
  427.     }
  428.  
  429.     wxString str;
  430.     str.Printf(_("unknown-%d"), encoding);
  431.  
  432.     return str;
  433. }
  434.  
  435. wxFontEncoding wxFontMapper::CharsetToEncoding(const wxString& charset,
  436.                                                bool interactive)
  437. {
  438.     // a special pseudo encoding which means "don't ask me about this charset
  439.     // any more" - we need it to avoid driving the user crazy with asking him
  440.     // time after time about the same charset which he [presumably] doesn't
  441.     // have the fonts fot
  442.     static const int wxFONTENCODING_UNKNOWN = -2;
  443.  
  444.     wxFontEncoding encoding = wxFONTENCODING_SYSTEM;
  445.  
  446.     // we're going to modify it, make a copy
  447.     wxString cs = charset;
  448.  
  449. #if wxUSE_CONFIG
  450.     // first try the user-defined settings
  451.     wxString pathOld;
  452.     if ( ChangePath(FONTMAPPER_CHARSET_PATH, &pathOld) )
  453.     {
  454.         wxConfigBase *config = GetConfig();
  455.  
  456.         // do we have an encoding for this charset?
  457.         long value = config->Read(charset, -1l);
  458.         if ( value != -1 )
  459.         {
  460.             if ( value == wxFONTENCODING_UNKNOWN )
  461.             {
  462.                 // don't try to find it, in particular don't ask the user
  463.                 return wxFONTENCODING_SYSTEM;
  464.             }
  465.  
  466.             if ( value >= 0 && value <= wxFONTENCODING_MAX )
  467.             {
  468.                 encoding = (wxFontEncoding)value;
  469.             }
  470.             else
  471.             {
  472.                 wxLogDebug(wxT("corrupted config data: invalid encoding %ld for charset '%s' ignored"),
  473.                            value, charset.c_str());
  474.             }
  475.         }
  476.  
  477.         if ( encoding == wxFONTENCODING_SYSTEM )
  478.         {
  479.             // may be we have an alias?
  480.             config->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH);
  481.  
  482.             wxString alias = config->Read(charset);
  483.             if ( !!alias )
  484.             {
  485.                 // yes, we do - use it instead
  486.                 cs = alias;
  487.             }
  488.         }
  489.  
  490.         RestorePath(pathOld);
  491.     }
  492. #endif // wxUSE_CONFIG
  493.  
  494.     // if didn't find it there, try to recognize it ourselves
  495.     if ( encoding == wxFONTENCODING_SYSTEM )
  496.     {
  497.         // trim any spaces
  498.         cs.Trim(TRUE);
  499.         cs.Trim(FALSE);
  500.  
  501.         // discard the optional quotes
  502.         if ( !cs.empty() )
  503.         {
  504.             if ( cs[0u] == _T('"') && cs.Last() == _T('"') )
  505.             {
  506.                 cs = wxString(cs.c_str(), cs.length() - 1);
  507.             }
  508.         }
  509.  
  510.         cs.MakeUpper();
  511.  
  512.         if ( cs.empty() || cs == _T("US-ASCII") )
  513.         {
  514.             encoding = wxFONTENCODING_DEFAULT;
  515.         }
  516.         else if ( cs == wxT("UTF-7") )
  517.         {
  518.             encoding = wxFONTENCODING_UTF7;
  519.         }
  520.         else if ( cs == wxT("UTF-8") )
  521.         {
  522.             encoding = wxFONTENCODING_UTF8;
  523.         }
  524.         else if ( cs == wxT("GB2312") )
  525.         {
  526.             encoding = wxFONTENCODING_GB2312;
  527.         }
  528.         else if ( cs == wxT("BIG5") )
  529.         {
  530.             encoding = wxFONTENCODING_BIG5;
  531.         }
  532.         else if ( cs == wxT("SJIS") ||
  533.                   cs == wxT("SHIFT_JIS") ||
  534.                   cs == wxT("SHIFT-JIS") )
  535.         {
  536.             encoding = wxFONTENCODING_SHIFT_JIS;
  537.         }
  538.         else if ( cs == wxT("EUC-JP") ||
  539.                   cs == wxT("EUC_JP") )
  540.         {
  541.             encoding = wxFONTENCODING_EUC_JP;
  542.         }
  543.         else if ( cs == wxT("KOI8-R") ||
  544.                   cs == wxT("KOI8-U") ||
  545.                   cs == wxT("KOI8-RU") )
  546.         {
  547.             // although koi8-ru is not strictly speaking the same as koi8-r,
  548.             // they are similar enough to make mapping it to koi8 better than
  549.             // not reckognizing it at all
  550.             encoding = wxFONTENCODING_KOI8;
  551.         }
  552.         else if ( cs.Left(3) == wxT("ISO") )
  553.         {
  554.             // the dash is optional (or, to be exact, it is not, but
  555.             // several brokenmails "forget" it)
  556.             const wxChar *p = cs.c_str() + 3;
  557.             if ( *p == wxT('-') )
  558.                 p++;
  559.                 
  560.             // printf( "iso %s\n", (const char*) cs.ToAscii() );
  561.  
  562.             unsigned int value;
  563.             if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
  564.             {
  565.                 // printf( "value %d\n", (int)value );
  566.    
  567.                 // make it 0 based and check that it is strictly positive in
  568.                 // the process (no such thing as iso8859-0 encoding)
  569.                 if ( (value-- > 0) &&
  570.                      (value < wxFONTENCODING_ISO8859_MAX -
  571.                               wxFONTENCODING_ISO8859_1) )
  572.                 {
  573.                     // it's a valid ISO8859 encoding
  574.                     value += wxFONTENCODING_ISO8859_1;
  575.                     encoding = (wxFontEncoding)value;
  576.                 }
  577.             }
  578.         }
  579.         else if ( cs.Left(4) == wxT("8859") )
  580.         {
  581.             const wxChar *p = cs.c_str();
  582.             
  583.             unsigned int value;
  584.             if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
  585.             {
  586.                 // printf( "value %d\n", (int)value );
  587.    
  588.                 // make it 0 based and check that it is strictly positive in
  589.                 // the process (no such thing as iso8859-0 encoding)
  590.                 if ( (value-- > 0) &&
  591.                      (value < wxFONTENCODING_ISO8859_MAX -
  592.                               wxFONTENCODING_ISO8859_1) )
  593.                 {
  594.                     // it's a valid ISO8859 encoding
  595.                     value += wxFONTENCODING_ISO8859_1;
  596.                     encoding = (wxFontEncoding)value;
  597.                 }
  598.             }
  599.         }
  600.         else // check for Windows charsets
  601.         {
  602.             size_t len;
  603.             if ( cs.Left(7) == wxT("WINDOWS") )
  604.             {
  605.                 len = 7;
  606.             }
  607.             else if ( cs.Left(2) == wxT("CP") )
  608.             {
  609.                 len = 2;
  610.             }
  611.             else // not a Windows encoding
  612.             {
  613.                 len = 0;
  614.             }
  615.  
  616.             if ( len )
  617.             {
  618.                 const wxChar *p = cs.c_str() + len;
  619.                 if ( *p == wxT('-') )
  620.                     p++;
  621.  
  622.                 int value;
  623.                 if ( wxSscanf(p, wxT("%u"), &value) == 1 )
  624.                 {
  625.                     if ( value >= 1250 )
  626.                     {
  627.                         value -= 1250;
  628.                         if ( value < wxFONTENCODING_CP12_MAX -
  629.                                      wxFONTENCODING_CP1250 )
  630.                         {
  631.                             // a valid Windows code page
  632.                             value += wxFONTENCODING_CP1250;
  633.                             encoding = (wxFontEncoding)value;
  634.                         }
  635.                     }
  636.  
  637.                     switch ( value )
  638.                     {
  639.                         case 932:
  640.                             encoding = wxFONTENCODING_CP932;
  641.                             break;
  642.  
  643.                         case 936:
  644.                             encoding = wxFONTENCODING_CP936;
  645.                             break;
  646.  
  647.                         case 949:
  648.                             encoding = wxFONTENCODING_CP949;
  649.                             break;
  650.  
  651.                         case 950:
  652.                             encoding = wxFONTENCODING_CP950;
  653.                             break;
  654.                     }
  655.                 }
  656.             }
  657.         }
  658.         //else: unknown
  659.     }
  660.  
  661. #if wxUSE_GUI
  662.     // if still no luck, ask the user - unless disabled
  663.     if ( (encoding == wxFONTENCODING_SYSTEM) && interactive )
  664.     {
  665.         // prepare the dialog data
  666.  
  667.         // the dialog title
  668.         wxString title(m_titleDialog);
  669.         if ( !title )
  670.             title << wxTheApp->GetAppName() << _(": unknown charset");
  671.  
  672.         // the message
  673.         wxString msg;
  674.         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());
  675.  
  676.         // the list of choices
  677.         const size_t count = WXSIZEOF(gs_encodingDescs);
  678.  
  679.         wxString *encodingNamesTranslated = new wxString[count];
  680.  
  681.         for ( size_t i = 0; i < count; i++ )
  682.         {
  683.             encodingNamesTranslated[i] = wxGetTranslation(gs_encodingDescs[i]);
  684.         }
  685.  
  686.         // the parent window
  687.         wxWindow *parent = m_windowParent;
  688.         if ( !parent )
  689.             parent = wxTheApp->GetTopWindow();
  690.  
  691.         // do ask the user and get back the index in encodings table
  692.         int n = wxGetSingleChoiceIndex(msg, title,
  693.                                        count,
  694.                                        encodingNamesTranslated,
  695.                                        parent);
  696.  
  697.         delete [] encodingNamesTranslated;
  698.  
  699.         if ( n != -1 )
  700.         {
  701.             encoding = gs_encodings[n];
  702.         }
  703.  
  704. #if wxUSE_CONFIG
  705.         // save the result in the config now
  706.         if ( ChangePath(FONTMAPPER_CHARSET_PATH, &pathOld) )
  707.         {
  708.             wxConfigBase *config = GetConfig();
  709.  
  710.             // remember the alt encoding for this charset - or remember that
  711.             // we don't know it
  712.             long value = n == -1 ? wxFONTENCODING_UNKNOWN : (long)encoding;
  713.             if ( !config->Write(charset, value) )
  714.             {
  715.                 wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset.c_str());
  716.             }
  717.  
  718.             RestorePath(pathOld);
  719.         }
  720. #endif // wxUSE_CONFIG
  721.     }
  722. #endif // wxUSE_GUI
  723.  
  724.     return encoding;
  725. }
  726.  
  727. // ----------------------------------------------------------------------------
  728. // support for unknown encodings: we maintain a map between the
  729. // (platform-specific) strings identifying them and our wxFontEncodings they
  730. // correspond to which is used by GetFontForEncoding() function
  731. // ----------------------------------------------------------------------------
  732.  
  733. #if wxUSE_GUI
  734.  
  735. bool wxFontMapper::TestAltEncoding(const wxString& configEntry,
  736.                                    wxFontEncoding encReplacement,
  737.                                    wxNativeEncodingInfo *info)
  738. {
  739.     if ( wxGetNativeFontEncoding(encReplacement, info) &&
  740.          wxTestFontEncoding(*info) )
  741.     {
  742. #if wxUSE_CONFIG
  743.         // remember the mapping in the config
  744.         wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH);
  745.  
  746.         if ( path.IsOk() )
  747.         {
  748.             GetConfig()->Write(configEntry, info->ToString());
  749.         }
  750. #endif // wxUSE_CONFIG
  751.         return TRUE;
  752.     }
  753.  
  754.     return FALSE;
  755. }
  756.  
  757. #if wxUSE_GUI
  758. class ReentrancyBlocker
  759. {
  760. public:
  761.     ReentrancyBlocker(bool& b) : m_b(b) { m_b = TRUE; }
  762.     ~ReentrancyBlocker() { m_b = FALSE; }
  763.  
  764. private:
  765.     bool& m_b;
  766. };
  767. #endif
  768.  
  769. bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
  770.                                      wxNativeEncodingInfo *info,
  771.                                      const wxString& facename,
  772.                                      bool interactive)
  773. {
  774. #if wxUSE_GUI
  775.     // we need a flag to prevent infinite recursion which happens, for
  776.     // example, when GetAltForEncoding() is called from an OnPaint() handler:
  777.     // in this case, wxYield() which is called from wxMessageBox() we use here
  778.     // will lead to another call of OnPaint() and hence to another call of
  779.     // GetAltForEncoding() - and it is impossible to catch this from the user
  780.     // code because we are called from wxFont ctor implicitly.
  781.  
  782.     // assume we're always called from the main thread, so that it is safe to
  783.     // use a static var
  784.     static bool s_inGetAltForEncoding = FALSE;
  785.  
  786.     if ( interactive && s_inGetAltForEncoding )
  787.         return FALSE;
  788.  
  789.     ReentrancyBlocker blocker(s_inGetAltForEncoding);
  790. #endif // wxUSE_GUI
  791.  
  792.     wxCHECK_MSG( info, FALSE, wxT("bad pointer in GetAltForEncoding") );
  793.  
  794.     info->facename = facename;
  795.  
  796.     if ( encoding == wxFONTENCODING_DEFAULT )
  797.     {
  798.         encoding = wxFont::GetDefaultEncoding();
  799.     }
  800.  
  801.     // if we failed to load the system default encoding, something is really
  802.     // wrong and we'd better stop now - otherwise we will go into endless
  803.     // recursion trying to create the font in the msg box with the error
  804.     // message
  805.     if ( encoding == wxFONTENCODING_SYSTEM )
  806.     {
  807.         wxLogFatalError(_("can't load any font, aborting"));
  808.  
  809.         // wxLogFatalError doesn't return
  810.     }
  811.  
  812.     wxString configEntry,
  813.              encName = GetEncodingName(encoding);
  814.     if ( !!facename )
  815.     {
  816.         configEntry = facename + _T("_");
  817.     }
  818.     configEntry += encName;
  819.  
  820. #if wxUSE_CONFIG
  821.     // do we have a font spec for this encoding?
  822.     wxString pathOld;
  823.     if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
  824.     {
  825.         wxConfigBase *config = GetConfig();
  826.  
  827.         wxString fontinfo = config->Read(configEntry);
  828.  
  829.         RestorePath(pathOld);
  830.  
  831.         // this special value means that we don't know of fonts for this
  832.         // encoding but, moreover, have already asked the user as well and he
  833.         // didn't specify any font neither
  834.         if ( fontinfo == FONTMAPPER_FONT_DONT_ASK )
  835.         {
  836.             interactive = FALSE;
  837.         }
  838.         else // use the info entered the last time
  839.         {
  840.             if ( !!fontinfo && !!facename )
  841.             {
  842.                 // we tried to find a match with facename - now try without it
  843.                 fontinfo = config->Read(encName);
  844.             }
  845.  
  846.             if ( !!fontinfo )
  847.             {
  848.                 if ( info->FromString(fontinfo) )
  849.                 {
  850.                     if ( wxTestFontEncoding(*info) )
  851.                     {
  852.                         // ok, got something
  853.                         return TRUE;
  854.                     }
  855.                     //else: no such fonts, look for something else
  856.                     //      (should we erase the outdated value?)
  857.                 }
  858.                 else
  859.                 {
  860.                     wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"),
  861.                                fontinfo.c_str());
  862.                 }
  863.             }
  864.             //else: there is no information in config about this encoding
  865.         }
  866.     }
  867. #endif // wxUSE_CONFIG
  868.  
  869.     // now try to map this encoding to a compatible one which we have on this
  870.     // system
  871.     wxFontEncodingArray equiv = wxEncodingConverter::GetAllEquivalents(encoding);
  872.     size_t count = equiv.GetCount();
  873.     bool foundEquivEncoding = FALSE;
  874.     wxFontEncoding equivEncoding = wxFONTENCODING_SYSTEM;
  875.     if ( count )
  876.     {
  877.         for ( size_t i = 0; i < count && !foundEquivEncoding; i++ )
  878.         {
  879.             // don't test for encoding itself, we already know we don't have it
  880.             if ( equiv[i] == encoding )
  881.                 continue;
  882.  
  883.             if ( TestAltEncoding(configEntry, equiv[i], info) )
  884.             {
  885.                 equivEncoding = equiv[i];
  886.  
  887.                 foundEquivEncoding = TRUE;
  888.             }
  889.         }
  890.     }
  891.  
  892.     // ask the user
  893. #if wxUSE_FONTDLG
  894.     if ( interactive )
  895.     {
  896.         wxString title(m_titleDialog);
  897.         if ( !title )
  898.             title << wxTheApp->GetAppName() << _(": unknown encoding");
  899.  
  900.         // built the message
  901.         wxString encDesc = GetEncodingDescription(encoding),
  902.                  msg;
  903.         if ( foundEquivEncoding )
  904.         {
  905.             // ask the user if he wants to override found alternative encoding
  906.             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)?"),
  907.                        encDesc.c_str(), GetEncodingDescription(equivEncoding).c_str());
  908.         }
  909.         else
  910.         {
  911.             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)?"),
  912.                        encDesc.c_str());
  913.         }
  914.  
  915.         // the question is different in 2 cases so the answer has to be
  916.         // interpreted differently as well
  917.         int answer = foundEquivEncoding ? wxNO : wxYES;
  918.  
  919.         if ( wxMessageBox(msg, title,
  920.                           wxICON_QUESTION | wxYES_NO,
  921.                           m_windowParent) == answer )
  922.         {
  923.             wxFontData data;
  924.             data.SetEncoding(encoding);
  925.             data.EncodingInfo() = *info;
  926.             wxFontDialog dialog(m_windowParent, data);
  927.             if ( dialog.ShowModal() == wxID_OK )
  928.             {
  929.                 wxFontData retData = dialog.GetFontData();
  930.                 wxFont font = retData.GetChosenFont();
  931.  
  932.                 *info = retData.EncodingInfo();
  933.                 info->encoding = retData.GetEncoding();
  934.  
  935. #if wxUSE_CONFIG
  936.                 // remember this in the config
  937.                 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
  938.                 {
  939.                     GetConfig()->Write(configEntry, info->ToString());
  940.  
  941.                     RestorePath(pathOld);
  942.                 }
  943. #endif // wxUSE_CONFIG
  944.  
  945.                 return TRUE;
  946.             }
  947.             //else: the user canceled the font selection dialog
  948.         }
  949.         else
  950.         {
  951.             // the user doesn't want to select a font for this encoding
  952.             // or selected to use equivalent encoding
  953.             //
  954.             // remember it to avoid asking the same question again later
  955. #if wxUSE_CONFIG
  956.             if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
  957.             {
  958.                 GetConfig()->Write
  959.                              (
  960.                                 configEntry,
  961.                                 foundEquivEncoding ? info->ToString().c_str()
  962.                                                    : FONTMAPPER_FONT_DONT_ASK
  963.                              );
  964.  
  965.                 RestorePath(pathOld);
  966.             }
  967. #endif // wxUSE_CONFIG
  968.         }
  969.     }
  970.     //else: we're in non-interactive mode
  971. #endif // wxUSE_FONTDLG
  972.  
  973.     return foundEquivEncoding;
  974. }
  975.  
  976. bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
  977.                                      wxFontEncoding *alt_encoding,
  978.                                      const wxString& facename,
  979.                                      bool interactive)
  980. {
  981.     wxNativeEncodingInfo info;
  982.     bool r = GetAltForEncoding(encoding, &info, facename, interactive);
  983.     *alt_encoding = info.encoding;
  984.     return r;
  985. }
  986.  
  987. bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding,
  988.                                        const wxString& facename)
  989. {
  990.     wxNativeEncodingInfo info;
  991.  
  992.     if (wxGetNativeFontEncoding(encoding, &info))
  993.     {
  994.         info.facename = facename;
  995.         return wxTestFontEncoding(info);
  996.     }
  997.  
  998.     return FALSE;
  999. }
  1000.  
  1001. #endif // wxUSE_GUI
  1002.  
  1003. #endif // wxUSE_FONTMAP
  1004.