1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        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 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  21     #pragma implementation "fontmap.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  40     #include "wx/config.h" 
  41 #endif // wxUSE_CONFIG 
  43 #if defined(__WXMSW__) 
  44   #include  "wx/msw/private.h"  // includes windows.h for LOGFONT 
  45   #include  "wx/msw/winundef.h" 
  48 #include "wx/fontmap.h" 
  49 #include "wx/fmappriv.h" 
  50 #include "wx/fontutil.h" 
  51 #include "wx/msgdlg.h" 
  52 #include "wx/fontdlg.h" 
  53 #include "wx/choicdlg.h" 
  55 #include "wx/encconv.h" 
  57 #if wxUSE_EXTENDED_RTTI 
  59 wxBEGIN_ENUM( wxFontEncoding 
) 
  60     wxENUM_MEMBER( wxFONTENCODING_SYSTEM 
) 
  61     wxENUM_MEMBER( wxFONTENCODING_DEFAULT 
) 
  63     wxENUM_MEMBER( wxFONTENCODING_ISO8859_1 
) 
  64     wxENUM_MEMBER( wxFONTENCODING_ISO8859_2 
) 
  65     wxENUM_MEMBER( wxFONTENCODING_ISO8859_3 
) 
  66     wxENUM_MEMBER( wxFONTENCODING_ISO8859_4 
) 
  67     wxENUM_MEMBER( wxFONTENCODING_ISO8859_5 
) 
  68     wxENUM_MEMBER( wxFONTENCODING_ISO8859_6 
) 
  69     wxENUM_MEMBER( wxFONTENCODING_ISO8859_7 
) 
  70     wxENUM_MEMBER( wxFONTENCODING_ISO8859_8 
) 
  71     wxENUM_MEMBER( wxFONTENCODING_ISO8859_9 
) 
  72     wxENUM_MEMBER( wxFONTENCODING_ISO8859_10 
) 
  73     wxENUM_MEMBER( wxFONTENCODING_ISO8859_11 
) 
  74     wxENUM_MEMBER( wxFONTENCODING_ISO8859_12 
) 
  75     wxENUM_MEMBER( wxFONTENCODING_ISO8859_13 
) 
  76     wxENUM_MEMBER( wxFONTENCODING_ISO8859_14 
) 
  77     wxENUM_MEMBER( wxFONTENCODING_ISO8859_15 
) 
  78     wxENUM_MEMBER( wxFONTENCODING_ISO8859_MAX 
) 
  79     wxENUM_MEMBER( wxFONTENCODING_KOI8 
) 
  80     wxENUM_MEMBER( wxFONTENCODING_KOI8_U 
) 
  81     wxENUM_MEMBER( wxFONTENCODING_ALTERNATIVE 
) 
  82     wxENUM_MEMBER( wxFONTENCODING_BULGARIAN 
) 
  83     wxENUM_MEMBER( wxFONTENCODING_CP437 
) 
  84     wxENUM_MEMBER( wxFONTENCODING_CP850 
) 
  85     wxENUM_MEMBER( wxFONTENCODING_CP852 
) 
  86     wxENUM_MEMBER( wxFONTENCODING_CP855 
) 
  87     wxENUM_MEMBER( wxFONTENCODING_CP866 
) 
  89     wxENUM_MEMBER( wxFONTENCODING_CP874 
) 
  90     wxENUM_MEMBER( wxFONTENCODING_CP932 
) 
  91     wxENUM_MEMBER( wxFONTENCODING_CP936 
) 
  92     wxENUM_MEMBER( wxFONTENCODING_CP949 
) 
  93     wxENUM_MEMBER( wxFONTENCODING_CP950 
) 
  94     wxENUM_MEMBER( wxFONTENCODING_CP1250 
) 
  95     wxENUM_MEMBER( wxFONTENCODING_CP1251 
) 
  96     wxENUM_MEMBER( wxFONTENCODING_CP1252 
) 
  97     wxENUM_MEMBER( wxFONTENCODING_CP1253 
) 
  98     wxENUM_MEMBER( wxFONTENCODING_CP1254 
) 
  99     wxENUM_MEMBER( wxFONTENCODING_CP1255 
) 
 100     wxENUM_MEMBER( wxFONTENCODING_CP1256 
) 
 101     wxENUM_MEMBER( wxFONTENCODING_CP1257 
) 
 102     wxENUM_MEMBER( wxFONTENCODING_CP12_MAX 
) 
 103     wxENUM_MEMBER( wxFONTENCODING_UTF7 
) 
 104     wxENUM_MEMBER( wxFONTENCODING_UTF8 
) 
 105     wxENUM_MEMBER( wxFONTENCODING_GB2312 
) 
 106     wxENUM_MEMBER( wxFONTENCODING_BIG5 
) 
 107     wxENUM_MEMBER( wxFONTENCODING_SHIFT_JIS 
) 
 108     wxENUM_MEMBER( wxFONTENCODING_EUC_JP 
) 
 109     wxENUM_MEMBER( wxFONTENCODING_UNICODE 
) 
 110 wxEND_ENUM( wxFontEncoding 
) 
 113 // ---------------------------------------------------------------------------- 
 115 // ---------------------------------------------------------------------------- 
 117 // the config paths we use 
 120 static const wxChar
* FONTMAPPER_FONT_FROM_ENCODING_PATH 
= wxT("Encodings"); 
 121 static const wxChar
* FONTMAPPER_FONT_DONT_ASK 
= wxT("none"); 
 123 #endif // wxUSE_CONFIG 
 125 // ---------------------------------------------------------------------------- 
 127 // ---------------------------------------------------------------------------- 
 129 // it may happen that while we're showing a dialog asking the user about 
 130 // something, another request for an encoding mapping arrives: in this case it 
 131 // is best to not do anything because otherwise we risk to enter an infinite 
 132 // loop so we create an object of this class on stack to test for this in all 
 133 // interactive functions 
 134 class ReentrancyBlocker
 
 137     ReentrancyBlocker(bool& flag
) : m_flagOld(flag
), m_flag(flag
) 
 139     ~ReentrancyBlocker() { m_flag 
= m_flagOld
; } 
 145     DECLARE_NO_COPY_CLASS(ReentrancyBlocker
) 
 148 // ============================================================================ 
 150 // ============================================================================ 
 152 // ---------------------------------------------------------------------------- 
 154 // ---------------------------------------------------------------------------- 
 156 wxFontMapper::wxFontMapper() 
 158     m_windowParent 
= NULL
; 
 161 wxFontMapper::~wxFontMapper() 
 166 wxFontMapper::CharsetToEncoding(const wxString
& charset
, bool interactive
) 
 168     // try the ways not needing the users intervention first 
 169     int encoding 
= wxFontMapperBase::NonInteractiveCharsetToEncoding(charset
); 
 171     // if we failed to find the encoding, ask the user -- unless disabled 
 172     if ( encoding 
== wxFONTENCODING_UNKNOWN 
) 
 174         // this is the special value which disables asking the user (he had 
 175         // chosen to suppress this the last time) 
 176         encoding 
= wxFONTENCODING_SYSTEM
; 
 179     else if ( (encoding 
== wxFONTENCODING_SYSTEM
) && interactive 
) 
 181         // prepare the dialog data 
 184         wxString 
title(m_titleDialog
); 
 186             title 
<< wxTheApp
->GetAppName() << _(": unknown charset"); 
 190         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()); 
 192         // the list of choices 
 193         const size_t count 
= GetSupportedEncodingsCount(); 
 195         wxString 
*encodingNamesTranslated 
= new wxString
[count
]; 
 197         for ( size_t i 
= 0; i 
< count
; i
++ ) 
 199             encodingNamesTranslated
[i
] = GetEncodingDescription(GetEncoding(i
)); 
 203         wxWindow 
*parent 
= m_windowParent
; 
 205             parent 
= wxTheApp
->GetTopWindow(); 
 207         // do ask the user and get back the index in encodings table 
 208         int n 
= wxGetSingleChoiceIndex(msg
, title
, 
 210                                        encodingNamesTranslated
, 
 213         delete [] encodingNamesTranslated
; 
 217             encoding 
= GetEncoding(n
); 
 220 #if wxUSE_CONFIG && wxUSE_FILECONFIG 
 221         // save the result in the config now 
 222         wxFontMapperPathChanger 
path(this, FONTMAPPER_CHARSET_PATH
); 
 225             wxConfigBase 
*config 
= GetConfig(); 
 227             // remember the alt encoding for this charset -- or remember that 
 229             long value 
= n 
== -1 ? wxFONTENCODING_UNKNOWN 
: (long)encoding
; 
 230             if ( !config
->Write(charset
, value
) ) 
 232                 wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset
.c_str()); 
 235 #endif // wxUSE_CONFIG 
 238     wxUnusedVar(interactive
); 
 239 #endif // wxUSE_CHOICEDLG 
 241     return (wxFontEncoding
)encoding
; 
 244 // ---------------------------------------------------------------------------- 
 245 // support for unknown encodings: we maintain a map between the 
 246 // (platform-specific) strings identifying them and our wxFontEncodings they 
 247 // correspond to which is used by GetFontForEncoding() function 
 248 // ---------------------------------------------------------------------------- 
 250 bool wxFontMapper::TestAltEncoding(const wxString
& configEntry
, 
 251                                    wxFontEncoding encReplacement
, 
 252                                    wxNativeEncodingInfo 
*info
) 
 254     if ( wxGetNativeFontEncoding(encReplacement
, info
) && 
 255          wxTestFontEncoding(*info
) ) 
 257 #if wxUSE_CONFIG && wxUSE_FILECONFIG 
 258         // remember the mapping in the config 
 259         wxFontMapperPathChanger 
path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH
); 
 263             GetConfig()->Write(configEntry
, info
->ToString()); 
 266         wxUnusedVar(configEntry
); 
 267 #endif // wxUSE_CONFIG 
 274 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
, 
 275                                      wxNativeEncodingInfo 
*info
, 
 276                                      const wxString
& facename
, 
 280     // we need a flag to prevent infinite recursion which happens, for 
 281     // example, when GetAltForEncoding() is called from an OnPaint() handler: 
 282     // in this case, wxYield() which is called from wxMessageBox() we use here 
 283     // will lead to another call of OnPaint() and hence to another call of 
 284     // GetAltForEncoding() -- and it is impossible to catch this from the user 
 285     // code because we are called from wxFont ctor implicitly. 
 287     // assume we're always called from the main thread, so that it is safe to 
 289     static bool s_inGetAltForEncoding 
= false; 
 291     if ( interactive 
&& s_inGetAltForEncoding 
) 
 294     ReentrancyBlocker 
blocker(s_inGetAltForEncoding
); 
 297     wxCHECK_MSG( info
, false, wxT("bad pointer in GetAltForEncoding") ); 
 299     info
->facename 
= facename
; 
 301     if ( encoding 
== wxFONTENCODING_DEFAULT 
) 
 303         encoding 
= wxFont::GetDefaultEncoding(); 
 306     // if we failed to load the system default encoding, something is really 
 307     // wrong and we'd better stop now -- otherwise we will go into endless 
 308     // recursion trying to create the font in the msg box with the error 
 310     if ( encoding 
== wxFONTENCODING_SYSTEM 
) 
 312         wxLogFatalError(_("can't load any font, aborting")); 
 314         // wxLogFatalError doesn't return 
 317     wxString configEntry
, 
 318              encName 
= GetEncodingName(encoding
); 
 319     if ( !facename
.IsEmpty() ) 
 321         configEntry 
= facename 
+ _T("_"); 
 323     configEntry 
+= encName
; 
 325 #if wxUSE_CONFIG && wxUSE_FILECONFIG 
 326     // do we have a font spec for this encoding? 
 328     wxFontMapperPathChanger 
path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH
); 
 331         fontinfo 
= GetConfig()->Read(configEntry
); 
 334     // this special value means that we don't know of fonts for this 
 335     // encoding but, moreover, have already asked the user as well and he 
 336     // didn't specify any font neither 
 337     if ( fontinfo 
== FONTMAPPER_FONT_DONT_ASK 
) 
 341     else // use the info entered the last time 
 343         if ( !fontinfo
.IsEmpty() && !facename
.IsEmpty() ) 
 345             // we tried to find a match with facename -- now try without it 
 346             fontinfo 
= GetConfig()->Read(encName
); 
 349         if ( !fontinfo
.IsEmpty() ) 
 351             if ( info
->FromString(fontinfo
) ) 
 353                 if ( wxTestFontEncoding(*info
) ) 
 358                 //else: no such fonts, look for something else 
 359                 //      (should we erase the outdated value?) 
 363                 wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"), 
 367         //else: there is no information in config about this encoding 
 369 #endif // wxUSE_CONFIG 
 371     // now try to map this encoding to a compatible one which we have on this 
 373     wxFontEncodingArray equiv 
= wxEncodingConverter::GetAllEquivalents(encoding
); 
 374     size_t count 
= equiv
.GetCount(); 
 375     bool foundEquivEncoding 
= false; 
 376     wxFontEncoding equivEncoding 
= wxFONTENCODING_SYSTEM
; 
 379         for ( size_t i 
= 0; i 
< count 
&& !foundEquivEncoding
; i
++ ) 
 381             // don't test for encoding itself, we already know we don't have it 
 382             if ( equiv
[i
] == encoding 
) 
 385             if ( TestAltEncoding(configEntry
, equiv
[i
], info
) ) 
 387                 equivEncoding 
= equiv
[i
]; 
 389                 foundEquivEncoding 
= true; 
 398         wxString 
title(m_titleDialog
); 
 400             title 
<< wxTheApp
->GetAppName() << _(": unknown encoding"); 
 403         wxString encDesc 
= GetEncodingDescription(encoding
), 
 405         if ( foundEquivEncoding 
) 
 407             // ask the user if he wants to override found alternative encoding 
 408             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)?"), 
 409                        encDesc
.c_str(), GetEncodingDescription(equivEncoding
).c_str()); 
 413             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)?"), 
 417         // the question is different in 2 cases so the answer has to be 
 418         // interpreted differently as well 
 419         int answer 
= foundEquivEncoding 
? wxNO 
: wxYES
; 
 421         if ( wxMessageBox(msg
, title
, 
 422                           wxICON_QUESTION 
| wxYES_NO
, 
 423                           m_windowParent
) == answer 
) 
 426             data
.SetEncoding(encoding
); 
 427             data
.EncodingInfo() = *info
; 
 428             wxFontDialog 
dialog(m_windowParent
, data
); 
 429             if ( dialog
.ShowModal() == wxID_OK 
) 
 431                 wxFontData retData 
= dialog
.GetFontData(); 
 432                 wxFont font 
= retData
.GetChosenFont(); 
 434                 *info 
= retData
.EncodingInfo(); 
 435                 info
->encoding 
= retData
.GetEncoding(); 
 437 #if wxUSE_CONFIG && wxUSE_FILECONFIG 
 438                 // remember this in the config 
 439                 wxFontMapperPathChanger 
path(this, 
 440                                              FONTMAPPER_FONT_FROM_ENCODING_PATH
); 
 443                     GetConfig()->Write(configEntry
, info
->ToString()); 
 445 #endif // wxUSE_CONFIG 
 449             //else: the user canceled the font selection dialog 
 453             // the user doesn't want to select a font for this encoding 
 454             // or selected to use equivalent encoding 
 456             // remember it to avoid asking the same question again later 
 457 #if wxUSE_CONFIG && wxUSE_FILECONFIG 
 458             wxFontMapperPathChanger 
path(this, 
 459                                          FONTMAPPER_FONT_FROM_ENCODING_PATH
); 
 465                                 foundEquivEncoding 
? info
->ToString().c_str() 
 466                                                    : FONTMAPPER_FONT_DONT_ASK
 
 469 #endif // wxUSE_CONFIG 
 472     //else: we're in non-interactive mode 
 474     wxUnusedVar(equivEncoding
); 
 475 #endif // wxUSE_FONTDLG 
 477     return foundEquivEncoding
; 
 480 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
, 
 481                                      wxFontEncoding 
*encodingAlt
, 
 482                                      const wxString
& facename
, 
 485     wxNativeEncodingInfo info
; 
 486     if ( !GetAltForEncoding(encoding
, &info
, facename
, interactive
) ) 
 489     wxCHECK_MSG( encodingAlt
, false, 
 490                     _T("wxFontEncoding::GetAltForEncoding(): NULL pointer") ); 
 492     *encodingAlt 
= info
.encoding
; 
 497 bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding
, 
 498                                        const wxString
& facename
) 
 500     wxNativeEncodingInfo info
; 
 502     if ( !wxGetNativeFontEncoding(encoding
, &info
) ) 
 505     info
.facename 
= facename
; 
 506     return wxTestFontEncoding(info
); 
 509 #endif // wxUSE_FONTMAP