1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/common/fontmap.cpp 
   3 // Purpose:     wxFontMapper class 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 1999-2003 Vadim Zeitlin <vadim@wxwindows.org> 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 // For compilers that support precompilation, includes "wx.h". 
  21 #include "wx/wxprec.h" 
  29 #include "wx/fontmap.h" 
  35     #include "wx/msgdlg.h" 
  39     #include "wx/config.h" 
  40 #endif // wxUSE_CONFIG 
  42 #if defined(__WXMSW__) 
  43   #include  "wx/msw/private.h"  // includes windows.h for LOGFONT 
  44   #include  "wx/msw/winundef.h" 
  47 #include "wx/fmappriv.h" 
  48 #include "wx/fontutil.h" 
  49 #include "wx/fontdlg.h" 
  50 #include "wx/choicdlg.h" 
  51 #include "wx/encinfo.h" 
  53 #include "wx/encconv.h" 
  55 #if wxUSE_EXTENDED_RTTI 
  57 wxBEGIN_ENUM( wxFontEncoding 
) 
  58     wxENUM_MEMBER( wxFONTENCODING_SYSTEM 
) 
  59     wxENUM_MEMBER( wxFONTENCODING_DEFAULT 
) 
  61     wxENUM_MEMBER( wxFONTENCODING_ISO8859_1 
) 
  62     wxENUM_MEMBER( wxFONTENCODING_ISO8859_2 
) 
  63     wxENUM_MEMBER( wxFONTENCODING_ISO8859_3 
) 
  64     wxENUM_MEMBER( wxFONTENCODING_ISO8859_4 
) 
  65     wxENUM_MEMBER( wxFONTENCODING_ISO8859_5 
) 
  66     wxENUM_MEMBER( wxFONTENCODING_ISO8859_6 
) 
  67     wxENUM_MEMBER( wxFONTENCODING_ISO8859_7 
) 
  68     wxENUM_MEMBER( wxFONTENCODING_ISO8859_8 
) 
  69     wxENUM_MEMBER( wxFONTENCODING_ISO8859_9 
) 
  70     wxENUM_MEMBER( wxFONTENCODING_ISO8859_10 
) 
  71     wxENUM_MEMBER( wxFONTENCODING_ISO8859_11 
) 
  72     wxENUM_MEMBER( wxFONTENCODING_ISO8859_12 
) 
  73     wxENUM_MEMBER( wxFONTENCODING_ISO8859_13 
) 
  74     wxENUM_MEMBER( wxFONTENCODING_ISO8859_14 
) 
  75     wxENUM_MEMBER( wxFONTENCODING_ISO8859_15 
) 
  76     wxENUM_MEMBER( wxFONTENCODING_ISO8859_MAX 
) 
  77     wxENUM_MEMBER( wxFONTENCODING_KOI8 
) 
  78     wxENUM_MEMBER( wxFONTENCODING_KOI8_U 
) 
  79     wxENUM_MEMBER( wxFONTENCODING_ALTERNATIVE 
) 
  80     wxENUM_MEMBER( wxFONTENCODING_BULGARIAN 
) 
  81     wxENUM_MEMBER( wxFONTENCODING_CP437 
) 
  82     wxENUM_MEMBER( wxFONTENCODING_CP850 
) 
  83     wxENUM_MEMBER( wxFONTENCODING_CP852 
) 
  84     wxENUM_MEMBER( wxFONTENCODING_CP855 
) 
  85     wxENUM_MEMBER( wxFONTENCODING_CP866 
) 
  87     wxENUM_MEMBER( wxFONTENCODING_CP874 
) 
  88     wxENUM_MEMBER( wxFONTENCODING_CP932 
) 
  89     wxENUM_MEMBER( wxFONTENCODING_CP936 
) 
  90     wxENUM_MEMBER( wxFONTENCODING_CP949 
) 
  91     wxENUM_MEMBER( wxFONTENCODING_CP950 
) 
  92     wxENUM_MEMBER( wxFONTENCODING_CP1250 
) 
  93     wxENUM_MEMBER( wxFONTENCODING_CP1251 
) 
  94     wxENUM_MEMBER( wxFONTENCODING_CP1252 
) 
  95     wxENUM_MEMBER( wxFONTENCODING_CP1253 
) 
  96     wxENUM_MEMBER( wxFONTENCODING_CP1254 
) 
  97     wxENUM_MEMBER( wxFONTENCODING_CP1255 
) 
  98     wxENUM_MEMBER( wxFONTENCODING_CP1256 
) 
  99     wxENUM_MEMBER( wxFONTENCODING_CP1257 
) 
 100     wxENUM_MEMBER( wxFONTENCODING_CP12_MAX 
) 
 101     wxENUM_MEMBER( wxFONTENCODING_UTF7 
) 
 102     wxENUM_MEMBER( wxFONTENCODING_UTF8 
) 
 103     wxENUM_MEMBER( wxFONTENCODING_GB2312 
) 
 104     wxENUM_MEMBER( wxFONTENCODING_BIG5 
) 
 105     wxENUM_MEMBER( wxFONTENCODING_SHIFT_JIS 
) 
 106     wxENUM_MEMBER( wxFONTENCODING_EUC_JP 
) 
 107     wxENUM_MEMBER( wxFONTENCODING_UNICODE 
) 
 108 wxEND_ENUM( wxFontEncoding 
) 
 111 // ---------------------------------------------------------------------------- 
 113 // ---------------------------------------------------------------------------- 
 115 // the config paths we use 
 118 static const wxChar
* FONTMAPPER_FONT_FROM_ENCODING_PATH 
= wxT("Encodings"); 
 119 static const wxChar
* FONTMAPPER_FONT_DONT_ASK 
= wxT("none"); 
 121 #endif // wxUSE_CONFIG 
 123 // ---------------------------------------------------------------------------- 
 125 // ---------------------------------------------------------------------------- 
 127 // it may happen that while we're showing a dialog asking the user about 
 128 // something, another request for an encoding mapping arrives: in this case it 
 129 // is best to not do anything because otherwise we risk to enter an infinite 
 130 // loop so we create an object of this class on stack to test for this in all 
 131 // interactive functions 
 132 class ReentrancyBlocker
 
 135     ReentrancyBlocker(bool& flag
) : m_flagOld(flag
), m_flag(flag
) 
 137     ~ReentrancyBlocker() { m_flag 
= m_flagOld
; } 
 143     DECLARE_NO_COPY_CLASS(ReentrancyBlocker
) 
 146 // ============================================================================ 
 148 // ============================================================================ 
 150 // ---------------------------------------------------------------------------- 
 152 // ---------------------------------------------------------------------------- 
 154 wxFontMapper::wxFontMapper() 
 156     m_windowParent 
= NULL
; 
 159 wxFontMapper::~wxFontMapper() 
 163 bool wxFontMapper::IsWxFontMapper() 
 167 wxFontMapper 
*wxFontMapper::Get() 
 169     wxFontMapperBase 
*fontmapper 
= wxFontMapperBase::Get(); 
 170     wxASSERT_MSG(fontmapper
->IsWxFontMapper(), wxT("GUI code requested a wxFontMapper but we only have a wxFontMapperBase.")); 
 171     // Now return it anyway because there's a chance the GUI code might just 
 172     // only want to call wxFontMapperBase functions. 
 173     return (wxFontMapper
*)fontmapper
; 
 177 wxFontMapper::CharsetToEncoding(const wxString
& charset
, bool interactive
) 
 179     // try the ways not needing the users intervention first 
 180     int encoding 
= wxFontMapperBase::NonInteractiveCharsetToEncoding(charset
); 
 182     // if we failed to find the encoding, ask the user -- unless disabled 
 183     if ( encoding 
== wxFONTENCODING_UNKNOWN 
) 
 185         // this is the special value which disables asking the user (he had 
 186         // chosen to suppress this the last time) 
 187         encoding 
= wxFONTENCODING_SYSTEM
; 
 190     else if ( (encoding 
== wxFONTENCODING_SYSTEM
) && interactive 
) 
 192         // prepare the dialog data 
 195         wxString 
title(m_titleDialog
); 
 197             title 
<< wxTheApp
->GetAppName() << _(": unknown charset"); 
 201         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()); 
 203         // the list of choices 
 204         const size_t count 
= GetSupportedEncodingsCount(); 
 206         wxString 
*encodingNamesTranslated 
= new wxString
[count
]; 
 208         for ( size_t i 
= 0; i 
< count
; i
++ ) 
 210             encodingNamesTranslated
[i
] = GetEncodingDescription(GetEncoding(i
)); 
 214         wxWindow 
*parent 
= m_windowParent
; 
 216             parent 
= wxTheApp
->GetTopWindow(); 
 218         // do ask the user and get back the index in encodings table 
 219         int n 
= wxGetSingleChoiceIndex(msg
, title
, 
 221                                        encodingNamesTranslated
, 
 224         delete [] encodingNamesTranslated
; 
 228             encoding 
= GetEncoding(n
); 
 231 #if wxUSE_CONFIG && wxUSE_FILECONFIG 
 232         // save the result in the config now 
 233         wxFontMapperPathChanger 
path(this, FONTMAPPER_CHARSET_PATH
); 
 236             wxConfigBase 
*config 
= GetConfig(); 
 238             // remember the alt encoding for this charset -- or remember that 
 240             long value 
= n 
== -1 ? (long)wxFONTENCODING_UNKNOWN 
: (long)encoding
; 
 241             if ( !config
->Write(charset
, value
) ) 
 243                 wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset
.c_str()); 
 246 #endif // wxUSE_CONFIG 
 249     wxUnusedVar(interactive
); 
 250 #endif // wxUSE_CHOICEDLG 
 252     return (wxFontEncoding
)encoding
; 
 255 // ---------------------------------------------------------------------------- 
 256 // support for unknown encodings: we maintain a map between the 
 257 // (platform-specific) strings identifying them and our wxFontEncodings they 
 258 // correspond to which is used by GetFontForEncoding() function 
 259 // ---------------------------------------------------------------------------- 
 261 bool wxFontMapper::TestAltEncoding(const wxString
& configEntry
, 
 262                                    wxFontEncoding encReplacement
, 
 263                                    wxNativeEncodingInfo 
*info
) 
 265     if ( wxGetNativeFontEncoding(encReplacement
, info
) && 
 266          wxTestFontEncoding(*info
) ) 
 268 #if wxUSE_CONFIG && wxUSE_FILECONFIG 
 269         // remember the mapping in the config 
 270         wxFontMapperPathChanger 
path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH
); 
 274             GetConfig()->Write(configEntry
, info
->ToString()); 
 277         wxUnusedVar(configEntry
); 
 278 #endif // wxUSE_CONFIG 
 285 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
, 
 286                                      wxNativeEncodingInfo 
*info
, 
 287                                      const wxString
& facename
, 
 291     // we need a flag to prevent infinite recursion which happens, for 
 292     // example, when GetAltForEncoding() is called from an OnPaint() handler: 
 293     // in this case, wxYield() which is called from wxMessageBox() we use here 
 294     // will lead to another call of OnPaint() and hence to another call of 
 295     // GetAltForEncoding() -- and it is impossible to catch this from the user 
 296     // code because we are called from wxFont ctor implicitly. 
 298     // assume we're always called from the main thread, so that it is safe to 
 300     static bool s_inGetAltForEncoding 
= false; 
 302     if ( interactive 
&& s_inGetAltForEncoding 
) 
 305     ReentrancyBlocker 
blocker(s_inGetAltForEncoding
); 
 308     wxCHECK_MSG( info
, false, wxT("bad pointer in GetAltForEncoding") ); 
 310     info
->facename 
= facename
; 
 312     if ( encoding 
== wxFONTENCODING_DEFAULT 
) 
 314         encoding 
= wxFont::GetDefaultEncoding(); 
 317     // if we failed to load the system default encoding, something is really 
 318     // wrong and we'd better stop now -- otherwise we will go into endless 
 319     // recursion trying to create the font in the msg box with the error 
 321     if ( encoding 
== wxFONTENCODING_SYSTEM 
) 
 323         wxLogFatalError(_("can't load any font, aborting")); 
 325         // wxLogFatalError doesn't return 
 328     wxString configEntry
, 
 329              encName 
= GetEncodingName(encoding
); 
 330     if ( !facename
.empty() ) 
 332         configEntry 
= facename 
+ _T("_"); 
 334     configEntry 
+= encName
; 
 336 #if wxUSE_CONFIG && wxUSE_FILECONFIG 
 337     // do we have a font spec for this encoding? 
 339     wxFontMapperPathChanger 
path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH
); 
 342         fontinfo 
= GetConfig()->Read(configEntry
); 
 345     // this special value means that we don't know of fonts for this 
 346     // encoding but, moreover, have already asked the user as well and he 
 347     // didn't specify any font neither 
 348     if ( fontinfo 
== FONTMAPPER_FONT_DONT_ASK 
) 
 352     else // use the info entered the last time 
 354         if ( !fontinfo
.empty() && !facename
.empty() ) 
 356             // we tried to find a match with facename -- now try without it 
 357             fontinfo 
= GetConfig()->Read(encName
); 
 360         if ( !fontinfo
.empty() ) 
 362             if ( info
->FromString(fontinfo
) ) 
 364                 if ( wxTestFontEncoding(*info
) ) 
 369                 //else: no such fonts, look for something else 
 370                 //      (should we erase the outdated value?) 
 374                 wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"), 
 378         //else: there is no information in config about this encoding 
 380 #endif // wxUSE_CONFIG 
 382     // now try to map this encoding to a compatible one which we have on this 
 384     wxFontEncodingArray equiv 
= wxEncodingConverter::GetAllEquivalents(encoding
); 
 385     size_t count 
= equiv
.GetCount(); 
 386     bool foundEquivEncoding 
= false; 
 387     wxFontEncoding equivEncoding 
= wxFONTENCODING_SYSTEM
; 
 390         for ( size_t i 
= 0; i 
< count 
&& !foundEquivEncoding
; i
++ ) 
 392             // don't test for encoding itself, we already know we don't have it 
 393             if ( equiv
[i
] == encoding 
) 
 396             if ( TestAltEncoding(configEntry
, equiv
[i
], info
) ) 
 398                 equivEncoding 
= equiv
[i
]; 
 400                 foundEquivEncoding 
= true; 
 409         wxString 
title(m_titleDialog
); 
 411             title 
<< wxTheApp
->GetAppName() << _(": unknown encoding"); 
 414         wxString encDesc 
= GetEncodingDescription(encoding
), 
 416         if ( foundEquivEncoding 
) 
 418             // ask the user if he wants to override found alternative encoding 
 419             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)?"), 
 420                        encDesc
.c_str(), GetEncodingDescription(equivEncoding
).c_str()); 
 424             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)?"), 
 428         // the question is different in 2 cases so the answer has to be 
 429         // interpreted differently as well 
 430         int answer 
= foundEquivEncoding 
? wxNO 
: wxYES
; 
 432         if ( wxMessageBox(msg
, title
, 
 433                           wxICON_QUESTION 
| wxYES_NO
, 
 434                           m_windowParent
) == answer 
) 
 437             data
.SetEncoding(encoding
); 
 438             data
.EncodingInfo() = *info
; 
 439             wxFontDialog 
dialog(m_windowParent
, data
); 
 440             if ( dialog
.ShowModal() == wxID_OK 
) 
 442                 wxFontData retData 
= dialog
.GetFontData(); 
 444                 *info 
= retData
.EncodingInfo(); 
 445                 info
->encoding 
= retData
.GetEncoding(); 
 447 #if wxUSE_CONFIG && wxUSE_FILECONFIG 
 448                 // remember this in the config 
 449                 wxFontMapperPathChanger 
path2(this, 
 450                                               FONTMAPPER_FONT_FROM_ENCODING_PATH
); 
 453                     GetConfig()->Write(configEntry
, info
->ToString()); 
 455 #endif // wxUSE_CONFIG 
 459             //else: the user canceled the font selection dialog 
 463             // the user doesn't want to select a font for this encoding 
 464             // or selected to use equivalent encoding 
 466             // remember it to avoid asking the same question again later 
 467 #if wxUSE_CONFIG && wxUSE_FILECONFIG 
 468             wxFontMapperPathChanger 
path2(this, 
 469                                           FONTMAPPER_FONT_FROM_ENCODING_PATH
); 
 475                                 foundEquivEncoding 
? info
->ToString().c_str() 
 476                                                    : FONTMAPPER_FONT_DONT_ASK
 
 479 #endif // wxUSE_CONFIG 
 482     //else: we're in non-interactive mode 
 484     wxUnusedVar(equivEncoding
); 
 485 #endif // wxUSE_FONTDLG 
 487     return foundEquivEncoding
; 
 490 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
, 
 491                                      wxFontEncoding 
*encodingAlt
, 
 492                                      const wxString
& facename
, 
 495     wxCHECK_MSG( encodingAlt
, false, 
 496                     _T("wxFontEncoding::GetAltForEncoding(): NULL pointer") ); 
 498     wxNativeEncodingInfo info
; 
 499     if ( !GetAltForEncoding(encoding
, &info
, facename
, interactive
) ) 
 502     *encodingAlt 
= info
.encoding
; 
 507 bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding
, 
 508                                        const wxString
& facename
) 
 510     wxNativeEncodingInfo info
; 
 512     if ( !wxGetNativeFontEncoding(encoding
, &info
) ) 
 515     info
.facename 
= facename
; 
 516     return wxTestFontEncoding(info
); 
 519 #endif // wxUSE_FONTMAP