home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / common / fontmap.cpp < prev    next >
C/C++ Source or Header  |  2002-06-04  |  30KB  |  963 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 2002/05/18 11:05:58 JS 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. };
  108.  
  109. // the descriptions for them
  110. static const wxChar* gs_encodingDescs[] =
  111. {
  112.     wxTRANSLATE( "Western European (ISO-8859-1)" ),
  113.     wxTRANSLATE( "Central European (ISO-8859-2)" ),
  114.     wxTRANSLATE( "Esperanto (ISO-8859-3)" ),
  115.     wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ),
  116.     wxTRANSLATE( "Cyrillic (ISO-8859-5)" ),
  117.     wxTRANSLATE( "Arabic (ISO-8859-6)" ),
  118.     wxTRANSLATE( "Greek (ISO-8859-7)" ),
  119.     wxTRANSLATE( "Hebrew (ISO-8859-8)" ),
  120.     wxTRANSLATE( "Turkish (ISO-8859-9)" ),
  121.     wxTRANSLATE( "Nordic (ISO-8859-10)" ),
  122.     wxTRANSLATE( "Thai (ISO-8859-11)" ),
  123.     wxTRANSLATE( "Indian (ISO-8859-12)" ),
  124.     wxTRANSLATE( "Baltic (ISO-8859-13)" ),
  125.     wxTRANSLATE( "Celtic (ISO-8859-14)" ),
  126.     wxTRANSLATE( "Western European with Euro (ISO-8859-15)" ),
  127.     wxTRANSLATE( "KOI8-R" ),
  128.     wxTRANSLATE( "Windows Japanese (CP 932)" ),
  129.     wxTRANSLATE( "Windows Chinese Simplified (CP 936)" ),
  130.     wxTRANSLATE( "Windows Korean (CP 949)" ),
  131.     wxTRANSLATE( "Windows Chinese Traditional (CP 950)" ),
  132.     wxTRANSLATE( "Windows Central European (CP 1250)" ),
  133.     wxTRANSLATE( "Windows Cyrillic (CP 1251)" ),
  134.     wxTRANSLATE( "Windows Western European (CP 1252)" ),
  135.     wxTRANSLATE( "Windows Greek (CP 1253)" ),
  136.     wxTRANSLATE( "Windows Turkish (CP 1254)" ),
  137.     wxTRANSLATE( "Windows Hebrew (CP 1255)" ),
  138.     wxTRANSLATE( "Windows Arabic (CP 1256)" ),
  139.     wxTRANSLATE( "Windows Baltic (CP 1257)" ),
  140.     wxTRANSLATE( "Windows/DOS OEM (CP 437)" ),
  141.     wxTRANSLATE( "Unicode 7 bit (UTF-7)" ),
  142.     wxTRANSLATE( "Unicode 8 bit (UTF-8)" ),
  143. };
  144.  
  145. // and the internal names (these are not translated on purpose!)
  146. static const wxChar* gs_encodingNames[] =
  147. {
  148.     wxT( "iso-8859-1" ),
  149.     wxT( "iso-8859-2" ),
  150.     wxT( "iso-8859-3" ),
  151.     wxT( "iso-8859-4" ),
  152.     wxT( "iso-8859-5" ),
  153.     wxT( "iso-8859-6" ),
  154.     wxT( "iso-8859-7" ),
  155.     wxT( "iso-8859-8" ),
  156.     wxT( "iso-8859-9" ),
  157.     wxT( "iso-8859-10" ),
  158.     wxT( "iso-8859-11" ),
  159.     wxT( "iso-8859-12" ),
  160.     wxT( "iso-8859-13" ),
  161.     wxT( "iso-8859-14" ),
  162.     wxT( "iso-8859-15" ),
  163.     wxT( "koi8-r" ),
  164.     wxT( "windows-932" ),
  165.     wxT( "windows-936" ),
  166.     wxT( "windows-949" ),
  167.     wxT( "windows-950" ),
  168.     wxT( "windows-1250" ),
  169.     wxT( "windows-1251" ),
  170.     wxT( "windows-1252" ),
  171.     wxT( "windows-1253" ),
  172.     wxT( "windows-1254" ),
  173.     wxT( "windows-1255" ),
  174.     wxT( "windows-1256" ),
  175.     wxT( "windows-1257" ),
  176.     wxT( "windows-437" ),
  177.     wxT( "utf-7" ),
  178.     wxT( "utf-8" ),
  179. };
  180.  
  181.  
  182. // ----------------------------------------------------------------------------
  183. // private classes
  184. // ----------------------------------------------------------------------------
  185.  
  186. // change the config path during the lifetime of this object
  187. class wxFontMapperPathChanger
  188. {
  189. public:
  190.     wxFontMapperPathChanger(wxFontMapper *fontMapper, const wxString& path)
  191.     {
  192.         m_fontMapper = fontMapper;
  193.         m_ok = m_fontMapper->ChangePath(path, &m_pathOld);
  194.     }
  195.  
  196.     bool IsOk() const { return m_ok; }
  197.  
  198.     ~wxFontMapperPathChanger()
  199.     {
  200.         if ( IsOk() )
  201.             m_fontMapper->RestorePath(m_pathOld);
  202.     }
  203.  
  204. private:
  205.     wxFontMapper *m_fontMapper;
  206.     bool          m_ok;
  207.     wxString      m_pathOld;
  208. };
  209.  
  210. // ============================================================================
  211. // implementation
  212. // ============================================================================
  213.  
  214. // ----------------------------------------------------------------------------
  215. // ctor and dtor
  216. // ----------------------------------------------------------------------------
  217.  
  218. wxFontMapper::wxFontMapper()
  219. {
  220. #if wxUSE_CONFIG
  221.     m_config = NULL;
  222.     m_configIsDummy = FALSE;
  223. #endif // wxUSE_CONFIG
  224.  
  225. #if wxUSE_GUI
  226.     m_windowParent = NULL;
  227. #endif // wxUSE_GUI
  228. }
  229.  
  230. wxFontMapper::~wxFontMapper()
  231. {
  232. #if wxUSE_CONFIG
  233.     if ( m_configIsDummy )
  234.         delete m_config;
  235. #endif // wxUSE_CONFIG
  236. }
  237.  
  238. wxFontMapper *wxFontMapper::sm_instance = NULL;
  239.  
  240. /*static*/ wxFontMapper *wxFontMapper::Get()
  241. {
  242.     if ( !sm_instance )
  243.         sm_instance = new wxFontMapper;
  244.     return sm_instance;
  245. }
  246.  
  247. /*static*/ wxFontMapper *wxFontMapper::Set(wxFontMapper *mapper)
  248. {
  249.     wxFontMapper *old = sm_instance;
  250.     sm_instance = mapper;
  251.     return old;
  252. }
  253.  
  254. class wxFontMapperModule: public wxModule
  255. {
  256. public:
  257.     wxFontMapperModule() : wxModule() {}
  258.     virtual bool OnInit() { return TRUE; }
  259.     virtual void OnExit() { delete wxFontMapper::Set(NULL); }
  260.  
  261.     DECLARE_DYNAMIC_CLASS(wxFontMapperModule)
  262. };
  263.  
  264. IMPLEMENT_DYNAMIC_CLASS(wxFontMapperModule, wxModule)
  265.  
  266. // ----------------------------------------------------------------------------
  267. // customisation
  268. // ----------------------------------------------------------------------------
  269.  
  270. #if wxUSE_CONFIG
  271.  
  272. /* static */ const wxChar *wxFontMapper::GetDefaultConfigPath()
  273. {
  274.     return FONTMAPPER_ROOT_PATH;
  275. }
  276.  
  277. void wxFontMapper::SetConfigPath(const wxString& prefix)
  278. {
  279.     wxCHECK_RET( !prefix.IsEmpty() && prefix[0] == wxCONFIG_PATH_SEPARATOR,
  280.                  wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") );
  281.  
  282.     m_configRootPath = prefix;
  283. }
  284.  
  285. // ----------------------------------------------------------------------------
  286. // get config object and path for it
  287. // ----------------------------------------------------------------------------
  288.  
  289. wxConfigBase *wxFontMapper::GetConfig()
  290. {
  291.     if ( !m_config )
  292.     {
  293.         // try the default
  294.         m_config = wxConfig::Get(FALSE /*don't create on demand*/ );
  295.  
  296.         if ( !m_config )
  297.         {
  298.             // we still want to have a config object because otherwise we would
  299.             // keep asking the user the same questions in the interactive mode,
  300.             // so create a dummy config which won't write to any files/registry
  301.             // but will allow us to remember the results of the questions at
  302.             // least during this run
  303.             m_config = new wxMemoryConfig;
  304.             m_configIsDummy = TRUE;
  305.             // VS: we can't call wxConfig::Set(m_config) here because that would
  306.             //     disable automatic wxConfig instance creation if this code was
  307.             //     called before wxApp::OnInit (this happens in wxGTK -- it sets
  308.             //     default wxFont encoding in wxApp::Initialize())
  309.         }
  310.     }
  311.  
  312.     if ( m_configIsDummy && wxConfig::Get(FALSE) != NULL )
  313.     {
  314.         // VS: in case we created dummy m_config (see above), we want to switch back
  315.         //     to the real one as soon as one becomes available.
  316.         delete m_config;
  317.         m_config = wxConfig::Get(FALSE);
  318.         m_configIsDummy = FALSE;
  319.         // FIXME: ideally, we should add keys from dummy config to the real one now,
  320.         //        but it is a low-priority task because typical wxWin application
  321.         //        either doesn't use wxConfig at all or creates wxConfig object in
  322.         //        wxApp::OnInit(), before any real interaction with the user takes
  323.         //        place...
  324.     }
  325.  
  326.     return m_config;
  327. }
  328.  
  329. const wxString& wxFontMapper::GetConfigPath()
  330. {
  331.     if ( !m_configRootPath )
  332.     {
  333.         // use the default
  334.         m_configRootPath = GetDefaultConfigPath();
  335.     }
  336.  
  337.     return m_configRootPath;
  338. }
  339. #endif
  340.  
  341. bool wxFontMapper::ChangePath(const wxString& pathNew, wxString *pathOld)
  342. {
  343. #if wxUSE_CONFIG
  344.     wxConfigBase *config = GetConfig();
  345.     if ( !config )
  346.         return FALSE;
  347.  
  348.     *pathOld = config->GetPath();
  349.  
  350.     wxString path = GetConfigPath();
  351.     if ( path.IsEmpty() || path.Last() != wxCONFIG_PATH_SEPARATOR )
  352.     {
  353.         path += wxCONFIG_PATH_SEPARATOR;
  354.     }
  355.  
  356.     wxASSERT_MSG( !pathNew || (pathNew[0] != wxCONFIG_PATH_SEPARATOR),
  357.                   wxT("should be a relative path") );
  358.  
  359.     path += pathNew;
  360.  
  361.     config->SetPath(path);
  362.  
  363.     return TRUE;
  364. #else
  365.     return FALSE;
  366. #endif
  367. }
  368.  
  369. void wxFontMapper::RestorePath(const wxString& pathOld)
  370. {
  371. #if wxUSE_CONFIG
  372.     GetConfig()->SetPath(pathOld);
  373. #else
  374. #endif
  375. }
  376.  
  377. // ----------------------------------------------------------------------------
  378. // charset/encoding correspondence
  379. // ----------------------------------------------------------------------------
  380.  
  381. /* static */
  382. wxString wxFontMapper::GetEncodingDescription(wxFontEncoding encoding)
  383. {
  384.     if ( encoding == wxFONTENCODING_DEFAULT )
  385.     {
  386.         return _("Default encoding");
  387.     }
  388.  
  389.     size_t count = WXSIZEOF(gs_encodingDescs);
  390.  
  391.     wxASSERT_MSG( count == WXSIZEOF(gs_encodings),
  392.                   wxT("inconsitency detected - forgot to update one of the arrays?") );
  393.  
  394.     for ( size_t i = 0; i < count; i++ )
  395.     {
  396.         if ( gs_encodings[i] == encoding )
  397.         {
  398.             return wxGetTranslation(gs_encodingDescs[i]);
  399.         }
  400.     }
  401.  
  402.     wxString str;
  403.     str.Printf(_("Unknown encoding (%d)"), encoding);
  404.  
  405.     return str;
  406. }
  407.  
  408. /* static */
  409. wxString wxFontMapper::GetEncodingName(wxFontEncoding encoding)
  410. {
  411.     if ( encoding == wxFONTENCODING_DEFAULT )
  412.     {
  413.         return _("default");
  414.     }
  415.  
  416.     size_t count = WXSIZEOF(gs_encodingNames);
  417.  
  418.     wxASSERT_MSG( count == WXSIZEOF(gs_encodings),
  419.                   wxT("inconsistency detected - forgot to update one of the arrays?") );
  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("KOI8-R") ||
  525.                   cs == wxT("KOI8-U") ||
  526.                   cs == wxT("KOI8-RU") )
  527.         {
  528.             // although koi8-ru is not strictly speaking the same as koi8-r,
  529.             // they are similar enough to make mapping it to koi8 better than
  530.             // not reckognizing it at all
  531.             encoding = wxFONTENCODING_KOI8;
  532.         }
  533.         else if ( cs.Left(3) == wxT("ISO") )
  534.         {
  535.             // the dash is optional (or, to be exact, it is not, but
  536.             // several brokenmails "forget" it)
  537.             const wxChar *p = cs.c_str() + 3;
  538.             if ( *p == wxT('-') )
  539.                 p++;
  540.  
  541.             unsigned int value;
  542.             if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
  543.             {
  544.                 // make it 0 based and check that it is strictly positive in
  545.                 // the process (no such thing as iso8859-0 encoding)
  546.                 if ( (value-- > 0) &&
  547.                      (value < wxFONTENCODING_ISO8859_MAX -
  548.                               wxFONTENCODING_ISO8859_1) )
  549.                 {
  550.                     // it's a valid ISO8859 encoding
  551.                     value += wxFONTENCODING_ISO8859_1;
  552.                     encoding = (wxFontEncoding)value;
  553.                 }
  554.             }
  555.         }
  556.         else // check for Windows charsets
  557.         {
  558.             size_t len;
  559.             if ( cs.Left(7) == wxT("WINDOWS") )
  560.             {
  561.                 len = 7;
  562.             }
  563.             else if ( cs.Left(2) == wxT("CP") )
  564.             {
  565.                 len = 2;
  566.             }
  567.             else // not a Windows encoding
  568.             {
  569.                 len = 0;
  570.             }
  571.  
  572.             if ( len )
  573.             {
  574.                 const wxChar *p = cs.c_str() + len;
  575.                 if ( *p == wxT('-') )
  576.                     p++;
  577.  
  578.                 int value;
  579.                 if ( wxSscanf(p, wxT("%u"), &value) == 1 )
  580.                 {
  581.                     if ( value >= 1250 )
  582.                     {
  583.                         value -= 1250;
  584.                         if ( value < wxFONTENCODING_CP12_MAX -
  585.                                      wxFONTENCODING_CP1250 )
  586.                         {
  587.                             // a valid Windows code page
  588.                             value += wxFONTENCODING_CP1250;
  589.                             encoding = (wxFontEncoding)value;
  590.                         }
  591.                     }
  592.  
  593.                     switch ( value )
  594.                     {
  595.                         case 932:
  596.                             encoding = wxFONTENCODING_CP932;
  597.                             break;
  598.  
  599.                         case 936:
  600.                             encoding = wxFONTENCODING_CP936;
  601.                             break;
  602.  
  603.                         case 949:
  604.                             encoding = wxFONTENCODING_CP949;
  605.                             break;
  606.  
  607.                         case 950:
  608.                             encoding = wxFONTENCODING_CP950;
  609.                             break;
  610.                     }
  611.                 }
  612.             }
  613.         }
  614.         //else: unknown
  615.     }
  616.  
  617. #if wxUSE_GUI
  618.     // if still no luck, ask the user - unless disabled
  619.     if ( (encoding == wxFONTENCODING_SYSTEM) && interactive )
  620.     {
  621.         // prepare the dialog data
  622.  
  623.         // the dialog title
  624.         wxString title(m_titleDialog);
  625.         if ( !title )
  626.             title << wxTheApp->GetAppName() << _(": unknown charset");
  627.  
  628.         // the message
  629.         wxString msg;
  630.         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());
  631.  
  632.         // the list of choices
  633.         size_t count = WXSIZEOF(gs_encodingDescs);
  634.  
  635.         wxASSERT_MSG( count == WXSIZEOF(gs_encodings),
  636.                       wxT("inconsitency detected - forgot to update one of the arrays?") );
  637.  
  638.         wxString *encodingNamesTranslated = new wxString[count];
  639.  
  640.         for ( size_t i = 0; i < count; i++ )
  641.         {
  642.             encodingNamesTranslated[i] = wxGetTranslation(gs_encodingDescs[i]);
  643.         }
  644.  
  645.         // the parent window
  646.         wxWindow *parent = m_windowParent;
  647.         if ( !parent )
  648.             parent = wxTheApp->GetTopWindow();
  649.  
  650.         // do ask the user and get back the index in encodings table
  651.         int n = wxGetSingleChoiceIndex(msg, title,
  652.                                        count,
  653.                                        encodingNamesTranslated,
  654.                                        parent);
  655.  
  656.         delete [] encodingNamesTranslated;
  657.  
  658.         if ( n != -1 )
  659.         {
  660.             encoding = gs_encodings[n];
  661.         }
  662.  
  663. #if wxUSE_CONFIG
  664.         // save the result in the config now
  665.         if ( ChangePath(FONTMAPPER_CHARSET_PATH, &pathOld) )
  666.         {
  667.             wxConfigBase *config = GetConfig();
  668.  
  669.             // remember the alt encoding for this charset - or remember that
  670.             // we don't know it
  671.             long value = n == -1 ? wxFONTENCODING_UNKNOWN : (long)encoding;
  672.             if ( !config->Write(charset, value) )
  673.             {
  674.                 wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset.c_str());
  675.             }
  676.  
  677.             RestorePath(pathOld);
  678.         }
  679. #endif // wxUSE_CONFIG
  680.     }
  681. #endif // wxUSE_GUI
  682.  
  683.     return encoding;
  684. }
  685.  
  686. // ----------------------------------------------------------------------------
  687. // support for unknown encodings: we maintain a map between the
  688. // (platform-specific) strings identifying them and our wxFontEncodings they
  689. // correspond to which is used by GetFontForEncoding() function
  690. // ----------------------------------------------------------------------------
  691.  
  692. #if wxUSE_GUI
  693.  
  694. bool wxFontMapper::TestAltEncoding(const wxString& configEntry,
  695.                                    wxFontEncoding encReplacement,
  696.                                    wxNativeEncodingInfo *info)
  697. {
  698.     if ( wxGetNativeFontEncoding(encReplacement, info) &&
  699.          wxTestFontEncoding(*info) )
  700.     {
  701. #if wxUSE_CONFIG
  702.         // remember the mapping in the config
  703.         wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH);
  704.  
  705.         if ( path.IsOk() )
  706.         {
  707.             GetConfig()->Write(configEntry, info->ToString());
  708.         }
  709. #endif // wxUSE_CONFIG
  710.         return TRUE;
  711.     }
  712.  
  713.     return FALSE;
  714. }
  715.  
  716. #if wxUSE_GUI
  717. class ReentrancyBlocker
  718. {
  719. public:
  720.     ReentrancyBlocker(bool& b) : m_b(b) { m_b = TRUE; }
  721.     ~ReentrancyBlocker() { m_b = FALSE; }
  722.  
  723. private:
  724.     bool& m_b;
  725. };
  726. #endif
  727.  
  728. bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
  729.                                      wxNativeEncodingInfo *info,
  730.                                      const wxString& facename,
  731.                                      bool interactive)
  732. {
  733. #if wxUSE_GUI
  734.     // we need a flag to prevent infinite recursion which happens, for
  735.     // example, when GetAltForEncoding() is called from an OnPaint() handler:
  736.     // in this case, wxYield() which is called from wxMessageBox() we use here
  737.     // will lead to another call of OnPaint() and hence to another call of
  738.     // GetAltForEncoding() - and it is impossible to catch this from the user
  739.     // code because we are called from wxFont ctor implicitly.
  740.  
  741.     // assume we're always called from the main thread, so that it is safe to
  742.     // use a static var
  743.     static bool s_inGetAltForEncoding = FALSE;
  744.  
  745.     if ( interactive && s_inGetAltForEncoding )
  746.         return FALSE;
  747.  
  748.     ReentrancyBlocker blocker(s_inGetAltForEncoding);
  749. #endif // wxUSE_GUI
  750.  
  751.     wxCHECK_MSG( info, FALSE, wxT("bad pointer in GetAltForEncoding") );
  752.  
  753.     info->facename = facename;
  754.  
  755.     if ( encoding == wxFONTENCODING_DEFAULT )
  756.     {
  757.         encoding = wxFont::GetDefaultEncoding();
  758.     }
  759.  
  760.     // if we failed to load the system default encoding, something is really
  761.     // wrong and we'd better stop now - otherwise we will go into endless
  762.     // recursion trying to create the font in the msg box with the error
  763.     // message
  764.     if ( encoding == wxFONTENCODING_SYSTEM )
  765.     {
  766.         wxLogFatalError(_("can't load any font, aborting"));
  767.  
  768.         // wxLogFatalError doesn't return
  769.     }
  770.  
  771.     wxString configEntry,
  772.              encName = GetEncodingName(encoding);
  773.     if ( !!facename )
  774.     {
  775.         configEntry = facename + _T("_");
  776.     }
  777.     configEntry += encName;
  778.  
  779. #if wxUSE_CONFIG
  780.     // do we have a font spec for this encoding?
  781.     wxString pathOld;
  782.     if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
  783.     {
  784.         wxConfigBase *config = GetConfig();
  785.  
  786.         wxString fontinfo = config->Read(configEntry);
  787.  
  788.         RestorePath(pathOld);
  789.  
  790.         // this special value means that we don't know of fonts for this
  791.         // encoding but, moreover, have already asked the user as well and he
  792.         // didn't specify any font neither
  793.         if ( fontinfo == FONTMAPPER_FONT_DONT_ASK )
  794.         {
  795.             interactive = FALSE;
  796.         }
  797.         else // use the info entered the last time
  798.         {
  799.             if ( !!fontinfo && !!facename )
  800.             {
  801.                 // we tried to find a match with facename - now try without it
  802.                 fontinfo = config->Read(encName);
  803.             }
  804.  
  805.             if ( !!fontinfo )
  806.             {
  807.                 if ( info->FromString(fontinfo) )
  808.                 {
  809.                     if ( wxTestFontEncoding(*info) )
  810.                     {
  811.                         // ok, got something
  812.                         return TRUE;
  813.                     }
  814.                     //else: no such fonts, look for something else
  815.                     //      (should we erase the outdated value?)
  816.                 }
  817.                 else
  818.                 {
  819.                     wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"),
  820.                                fontinfo.c_str());
  821.                 }
  822.             }
  823.             //else: there is no information in config about this encoding
  824.         }
  825.     }
  826. #endif // wxUSE_CONFIG
  827.  
  828.     // now try to map this encoding to a compatible one which we have on this
  829.     // system
  830.     wxFontEncodingArray equiv = wxEncodingConverter::GetAllEquivalents(encoding);
  831.     size_t count = equiv.GetCount();
  832.     bool foundEquivEncoding = FALSE;
  833.     wxFontEncoding equivEncoding = wxFONTENCODING_SYSTEM;
  834.     if ( count )
  835.     {
  836.         for ( size_t i = 0; i < count && !foundEquivEncoding; i++ )
  837.         {
  838.             // don't test for encoding itself, we already know we don't have it
  839.             if ( equiv[i] == encoding )
  840.                 continue;
  841.  
  842.             if ( TestAltEncoding(configEntry, equiv[i], info) )
  843.             {
  844.                 equivEncoding = equiv[i];
  845.  
  846.                 foundEquivEncoding = TRUE;
  847.             }
  848.         }
  849.     }
  850.  
  851.     // ask the user
  852. #if wxUSE_FONTDLG
  853.     if ( interactive )
  854.     {
  855.         wxString title(m_titleDialog);
  856.         if ( !title )
  857.             title << wxTheApp->GetAppName() << _(": unknown encoding");
  858.  
  859.         // built the message
  860.         wxString encDesc = GetEncodingDescription(encoding),
  861.                  msg;
  862.         if ( foundEquivEncoding )
  863.         {
  864.             // ask the user if he wants to override found alternative encoding
  865.             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)?"),
  866.                        encDesc.c_str(), GetEncodingDescription(equivEncoding).c_str());
  867.         }
  868.         else
  869.         {
  870.             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)?"),
  871.                        encDesc.c_str());
  872.         }
  873.  
  874.         // the question is different in 2 cases so the answer has to be
  875.         // interpreted differently as well
  876.         int answer = foundEquivEncoding ? wxNO : wxYES;
  877.  
  878.         if ( wxMessageBox(msg, title,
  879.                           wxICON_QUESTION | wxYES_NO,
  880.                           m_windowParent) == answer )
  881.         {
  882.             wxFontData data;
  883.             data.SetEncoding(encoding);
  884.             data.EncodingInfo() = *info;
  885.             wxFontDialog dialog(m_windowParent, data);
  886.             if ( dialog.ShowModal() == wxID_OK )
  887.             {
  888.                 wxFontData retData = dialog.GetFontData();
  889.                 wxFont font = retData.GetChosenFont();
  890.  
  891.                 *info = retData.EncodingInfo();
  892.                 info->encoding = retData.GetEncoding();
  893.  
  894. #if wxUSE_CONFIG
  895.                 // remember this in the config
  896.                 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
  897.                 {
  898.                     GetConfig()->Write(configEntry, info->ToString());
  899.  
  900.                     RestorePath(pathOld);
  901.                 }
  902. #endif // wxUSE_CONFIG
  903.  
  904.                 return TRUE;
  905.             }
  906.             //else: the user canceled the font selection dialog
  907.         }
  908.         else
  909.         {
  910.             // the user doesn't want to select a font for this encoding
  911.             // or selected to use equivalent encoding
  912.             //
  913.             // remember it to avoid asking the same question again later
  914. #if wxUSE_CONFIG
  915.             if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
  916.             {
  917.                 GetConfig()->Write
  918.                              (
  919.                                 configEntry,
  920.                                 foundEquivEncoding ? info->ToString().c_str()
  921.                                                    : FONTMAPPER_FONT_DONT_ASK
  922.                              );
  923.  
  924.                 RestorePath(pathOld);
  925.             }
  926. #endif // wxUSE_CONFIG
  927.         }
  928.     }
  929.     //else: we're in non-interactive mode
  930. #endif // wxUSE_FONTDLG
  931.  
  932.     return foundEquivEncoding;
  933. }
  934.  
  935. bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
  936.                                      wxFontEncoding *alt_encoding,
  937.                                      const wxString& facename,
  938.                                      bool interactive)
  939. {
  940.     wxNativeEncodingInfo info;
  941.     bool r = GetAltForEncoding(encoding, &info, facename, interactive);
  942.     *alt_encoding = info.encoding;
  943.     return r;
  944. }
  945.  
  946. bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding,
  947.                                        const wxString& facename)
  948. {
  949.     wxNativeEncodingInfo info;
  950.  
  951.     if (wxGetNativeFontEncoding(encoding, &info))
  952.     {
  953.         info.facename = facename;
  954.         return wxTestFontEncoding(info);
  955.     }
  956.  
  957.     return FALSE;
  958. }
  959.  
  960. #endif // wxUSE_GUI
  961.  
  962. #endif // wxUSE_FONTMAP
  963.