1 /////////////////////////////////////////////////////////////////////////////
2 // Name: common/fontmap.cpp
3 // Purpose: wxFontMapper class
4 // Author: Vadim Zeitlin
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "fontmap.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
37 #include "wx/fontmap.h"
40 #include "wx/config.h"
41 #include "wx/memconf.h"
45 #include "wx/fontutil.h"
46 #include "wx/msgdlg.h"
47 #include "wx/fontdlg.h"
48 #include "wx/choicdlg.h"
51 #include "wx/encconv.h"
53 // ----------------------------------------------------------------------------
55 // ----------------------------------------------------------------------------
57 // the config paths we use
58 static const wxChar
* FONTMAPPER_ROOT_PATH
= wxT("/wxWindows/FontMapper");
59 static const wxChar
* FONTMAPPER_CHARSET_PATH
= wxT("Charsets");
60 static const wxChar
* FONTMAPPER_CHARSET_ALIAS_PATH
= wxT("Aliases");
62 static const wxChar
* FONTMAPPER_FONT_FROM_ENCODING_PATH
= wxT("Encodings");
65 // encodings supported by GetEncodingDescription
66 static wxFontEncoding gs_encodings
[] =
68 wxFONTENCODING_ISO8859_1
,
69 wxFONTENCODING_ISO8859_2
,
70 wxFONTENCODING_ISO8859_3
,
71 wxFONTENCODING_ISO8859_4
,
72 wxFONTENCODING_ISO8859_5
,
73 wxFONTENCODING_ISO8859_6
,
74 wxFONTENCODING_ISO8859_7
,
75 wxFONTENCODING_ISO8859_8
,
76 wxFONTENCODING_ISO8859_9
,
77 wxFONTENCODING_ISO8859_10
,
78 wxFONTENCODING_ISO8859_11
,
79 wxFONTENCODING_ISO8859_12
,
80 wxFONTENCODING_ISO8859_13
,
81 wxFONTENCODING_ISO8859_14
,
82 wxFONTENCODING_ISO8859_15
,
84 wxFONTENCODING_CP1250
,
85 wxFONTENCODING_CP1251
,
86 wxFONTENCODING_CP1252
,
87 wxFONTENCODING_CP1253
,
88 wxFONTENCODING_CP1254
,
89 wxFONTENCODING_CP1255
,
90 wxFONTENCODING_CP1256
,
91 wxFONTENCODING_CP1257
,
95 // the descriptions for them
96 static const wxChar
* gs_encodingDescs
[] =
98 wxTRANSLATE( "Western European (ISO-8859-1/Latin 1)" ),
99 wxTRANSLATE( "Central European (ISO-8859-2/Latin 2)" ),
100 wxTRANSLATE( "Esperanto (ISO-8859-3)" ),
101 wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ),
102 wxTRANSLATE( "Cyrillic (Latin 5)" ),
103 wxTRANSLATE( "Arabic (ISO-8859-6)" ),
104 wxTRANSLATE( "Greek (ISO-8859-7)" ),
105 wxTRANSLATE( "Hebrew (ISO-8859-8)" ),
106 wxTRANSLATE( "Turkish (ISO-8859-9)" ),
107 wxTRANSLATE( "Nordic (ISO-8859-10)" ),
108 wxTRANSLATE( "Thai (ISO-8859-11)" ),
109 wxTRANSLATE( "Indian (ISO-8859-12)" ),
110 wxTRANSLATE( "Baltic (ISO-8859-13)" ),
111 wxTRANSLATE( "Celtic (ISO-8859-14)" ),
112 wxTRANSLATE( "Western European with Euro (ISO-8859-15/Latin 0)" ),
113 wxTRANSLATE( "KOI8-R" ),
114 wxTRANSLATE( "Windows Central European (CP 1250)" ),
115 wxTRANSLATE( "Windows Cyrillic (CP 1251)" ),
116 wxTRANSLATE( "Windows Western European (CP 1252)" ),
117 wxTRANSLATE( "Windows Greek (CP 1253)" ),
118 wxTRANSLATE( "Windows Turkish (CP 1254)" ),
119 wxTRANSLATE( "Windows Hebrew (CP 1255)" ),
120 wxTRANSLATE( "Windows Arabic (CP 1256)" ),
121 wxTRANSLATE( "Windows Baltic (CP 1257)" ),
122 wxTRANSLATE( "Windows/DOS OEM (CP 437)" ),
125 // and the internal names
126 static const wxChar
* gs_encodingNames
[] =
144 wxT( "windows1250" ),
145 wxT( "windows1251" ),
146 wxT( "windows1252" ),
147 wxT( "windows1253" ),
148 wxT( "windows1254" ),
149 wxT( "windows1255" ),
150 wxT( "windows1256" ),
151 wxT( "windows1257" ),
155 // ----------------------------------------------------------------------------
157 // ----------------------------------------------------------------------------
160 static wxFontMapper gs_fontMapper
;
162 // and public pointer
163 wxFontMapper
* wxTheFontMapper
= &gs_fontMapper
;
165 // ----------------------------------------------------------------------------
167 // ----------------------------------------------------------------------------
169 // change the config path during the lifetime of this object
170 class wxFontMapperPathChanger
173 wxFontMapperPathChanger(wxFontMapper
*fontMapper
, const wxString
& path
)
175 m_fontMapper
= fontMapper
;
176 m_ok
= m_fontMapper
->ChangePath(path
, &m_pathOld
);
179 bool IsOk() const { return m_ok
; }
181 ~wxFontMapperPathChanger()
184 m_fontMapper
->RestorePath(m_pathOld
);
188 wxFontMapper
*m_fontMapper
;
193 // ============================================================================
195 // ============================================================================
197 // ----------------------------------------------------------------------------
199 // ----------------------------------------------------------------------------
201 wxFontMapper::wxFontMapper()
205 #endif // wxUSE_CONFIG
208 m_windowParent
= NULL
;
212 wxFontMapper::~wxFontMapper()
216 // ----------------------------------------------------------------------------
218 // ----------------------------------------------------------------------------
222 /* static */ const wxChar
*wxFontMapper::GetDefaultConfigPath()
224 return FONTMAPPER_ROOT_PATH
;
227 void wxFontMapper::SetConfigPath(const wxString
& prefix
)
229 wxCHECK_RET( !prefix
.IsEmpty() && prefix
[0] == wxCONFIG_PATH_SEPARATOR
,
230 wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") );
232 m_configRootPath
= prefix
;
235 // ----------------------------------------------------------------------------
236 // get config object and path for it
237 // ----------------------------------------------------------------------------
239 wxConfigBase
*wxFontMapper::GetConfig()
244 m_config
= wxConfig::Get(FALSE
/*don't create on demand*/ );
248 // we still want to have a config object because otherwise we would
249 // keep asking the user the same questions in the interactive mode,
250 // so create a dummy config which won't write to any files/registry
251 // but will allow us to remember the results of the questions at
252 // least during this run
253 m_config
= new wxMemoryConfig
;
254 wxConfig::Set(m_config
);
261 const wxString
& wxFontMapper::GetConfigPath()
263 if ( !m_configRootPath
)
266 m_configRootPath
= GetDefaultConfigPath();
269 return m_configRootPath
;
273 bool wxFontMapper::ChangePath(const wxString
& pathNew
, wxString
*pathOld
)
276 wxConfigBase
*config
= GetConfig();
280 *pathOld
= config
->GetPath();
282 wxString path
= GetConfigPath();
283 if ( path
.IsEmpty() || path
.Last() != wxCONFIG_PATH_SEPARATOR
)
285 path
+= wxCONFIG_PATH_SEPARATOR
;
288 wxASSERT_MSG( !pathNew
|| (pathNew
[0] != wxCONFIG_PATH_SEPARATOR
),
289 wxT("should be a relative path") );
293 config
->SetPath(path
);
301 void wxFontMapper::RestorePath(const wxString
& pathOld
)
304 GetConfig()->SetPath(pathOld
);
309 // ----------------------------------------------------------------------------
310 // charset/encoding correspondence
311 // ----------------------------------------------------------------------------
314 wxString
wxFontMapper::GetEncodingDescription(wxFontEncoding encoding
)
316 size_t count
= WXSIZEOF(gs_encodingDescs
);
318 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
319 wxT("inconsitency detected - forgot to update one of the arrays?") );
321 for ( size_t i
= 0; i
< count
; i
++ )
323 if ( gs_encodings
[i
] == encoding
)
325 return wxGetTranslation(gs_encodingDescs
[i
]);
330 str
.Printf(_("Unknown encoding (%d)"), encoding
);
336 wxString
wxFontMapper::GetEncodingName(wxFontEncoding encoding
)
338 size_t count
= WXSIZEOF(gs_encodingNames
);
340 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
341 wxT("inconsistency detected - forgot to update one of the arrays?") );
343 for ( size_t i
= 0; i
< count
; i
++ )
345 if ( gs_encodings
[i
] == encoding
)
347 return wxGetTranslation(gs_encodingNames
[i
]);
352 str
.Printf(_("unknown-%d"), encoding
);
357 wxFontEncoding
wxFontMapper::CharsetToEncoding(const wxString
& charset
,
360 wxFontEncoding encoding
= wxFONTENCODING_SYSTEM
;
362 // we're going to modify it, make a copy
363 wxString cs
= charset
;
366 // first try the user-defined settings
368 if ( ChangePath(FONTMAPPER_CHARSET_PATH
, &pathOld
) )
370 wxConfigBase
*config
= GetConfig();
372 // do we have an encoding for this charset?
373 long value
= config
->Read(charset
, -1l);
376 if ( value
>= 0 && value
<= wxFONTENCODING_MAX
)
378 encoding
= (wxFontEncoding
)value
;
382 wxLogDebug(wxT("corrupted config data: invalid encoding %ld for charset '%s' ignored"),
383 value
, charset
.c_str());
387 if ( encoding
== wxFONTENCODING_SYSTEM
)
389 // may be we have an alias?
390 config
->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH
);
392 wxString alias
= config
->Read(charset
);
395 // yes, we do - use it instead
400 RestorePath(pathOld
);
404 // if didn't find it there, try to reckognise it ourselves
405 if ( encoding
== wxFONTENCODING_SYSTEM
)
407 // discard the optional quotes
410 if ( cs
[0u] == _T('"') && cs
.Last() == _T('"') )
412 cs
= wxString(cs
.c_str(), cs
.length() - 1);
418 if ( !cs
|| cs
== wxT("US-ASCII") )
419 encoding
= wxFONTENCODING_DEFAULT
;
420 else if ( cs
== wxT("KOI8-R") || cs
== wxT("KOI8-U") )
421 encoding
= wxFONTENCODING_KOI8
;
422 else if ( cs
.Left(3) == wxT("ISO") )
424 // the dash is optional (or, to be exact, it is not, but
425 // several brokenmails "forget" it)
426 const wxChar
*p
= cs
.c_str() + 3;
427 if ( *p
== wxT('-') )
431 if ( wxSscanf(p
, wxT("8859-%u"), &value
) == 1 )
433 if ( value
< wxFONTENCODING_ISO8859_MAX
-
434 wxFONTENCODING_ISO8859_1
)
436 // it's a valid ISO8859 encoding
437 value
+= wxFONTENCODING_ISO8859_1
- 1;
438 encoding
= (wxFontEncoding
)value
;
442 else if ( cs
.Left(8) == wxT("WINDOWS-") )
445 if ( wxSscanf(cs
.c_str() + 8, wxT("%u"), &value
) == 1 )
450 if ( value
< wxFONTENCODING_CP12_MAX
-
451 wxFONTENCODING_CP1250
)
453 // a valid Windows code page
454 value
+= wxFONTENCODING_CP1250
;
455 encoding
= (wxFontEncoding
)value
;
464 // if still no luck, ask the user - unless disabled
465 if ( (encoding
== wxFONTENCODING_SYSTEM
) && interactive
)
467 // prepare the dialog data
470 wxString
title(m_titleDialog
);
472 title
<< wxTheApp
->GetAppName() << _(": unknown charset");
476 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());
478 // the list of choices
479 size_t count
= WXSIZEOF(gs_encodingDescs
);
481 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
482 wxT("inconsitency detected - forgot to update one of the arrays?") );
484 wxString
*encodingNamesTranslated
= new wxString
[count
];
486 for ( size_t i
= 0; i
< count
; i
++ )
488 encodingNamesTranslated
[i
] = wxGetTranslation(gs_encodingDescs
[i
]);
492 wxWindow
*parent
= m_windowParent
;
494 parent
= wxTheApp
->GetTopWindow();
496 // do ask the user and get back the index in encodings table
497 int n
= wxGetSingleChoiceIndex(msg
, title
,
499 encodingNamesTranslated
,
502 delete [] encodingNamesTranslated
;
506 encoding
= gs_encodings
[n
];
509 // save the result in the config now
510 if ( ChangePath(FONTMAPPER_CHARSET_PATH
, &pathOld
) )
512 wxConfigBase
*config
= GetConfig();
514 // remember the alt encoding for this charset
515 if ( !config
->Write(charset
, (long)encoding
) )
517 wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset
.c_str());
520 RestorePath(pathOld
);
522 #endif // wxUSE_CONFIG
531 // ----------------------------------------------------------------------------
532 // support for unknown encodings: we maintain a map between the
533 // (platform-specific) strings identifying them and our wxFontEncodings they
534 // correspond to which is used by GetFontForEncoding() function
535 // ----------------------------------------------------------------------------
539 bool wxFontMapper::TestAltEncoding(const wxString
& configEntry
,
540 wxFontEncoding encReplacement
,
541 wxNativeEncodingInfo
*info
)
543 if ( wxGetNativeFontEncoding(encReplacement
, info
) &&
544 wxTestFontEncoding(*info
) )
547 // remember the mapping in the config
548 wxFontMapperPathChanger
path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH
);
552 GetConfig()->Write(configEntry
, info
->ToString());
554 #endif // wxUSE_CONFIG
562 class ReentrancyBlocker
565 ReentrancyBlocker(bool& b
) : m_b(b
) { m_b
= TRUE
; }
566 ~ReentrancyBlocker() { m_b
= FALSE
; }
573 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
574 wxNativeEncodingInfo
*info
,
575 const wxString
& facename
,
579 // we need a flag to prevent infinite recursion which happens, for
580 // example, when GetAltForEncoding() is called from an OnPaint() handler:
581 // in this case, wxYield() which is called from wxMessageBox() we use here
582 // will lead to another call of OnPaint() and hence to another call of
583 // GetAltForEncoding() - and it is impossible to catch this from the user
584 // code because we are called from wxFont ctor implicitly.
586 // assume we're always called from the main thread, so that it is safe to
588 static bool s_inGetAltForEncoding
= FALSE
;
590 if ( interactive
&& s_inGetAltForEncoding
)
593 ReentrancyBlocker
blocker(s_inGetAltForEncoding
);
596 wxCHECK_MSG( info
, FALSE
, wxT("bad pointer in GetAltForEncoding") );
598 info
->facename
= facename
;
600 if ( encoding
== wxFONTENCODING_DEFAULT
)
602 encoding
= wxFont::GetDefaultEncoding();
605 // if we failed to load the system default encoding, something is really
606 // wrong and we'd better stop now - otherwise we will go into endless
607 // recursion trying to create the font in the msg box with the error
609 if ( encoding
== wxFONTENCODING_SYSTEM
)
611 wxFatalError(_("can't load any font, aborting"));
613 // wxFatalError doesn't return
616 wxString configEntry
, encName
= GetEncodingName(encoding
);
619 configEntry
= facename
+ _T("_");
621 configEntry
+= encName
;
624 // do we have a font spec for this encoding?
626 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
628 wxConfigBase
*config
= GetConfig();
630 wxString fontinfo
= config
->Read(configEntry
);
632 RestorePath(pathOld
);
634 if ( !!fontinfo
&& !!facename
)
636 // we tried to find a match with facename - now try without it
637 fontinfo
= config
->Read(encName
);
642 if ( info
->FromString(fontinfo
) )
644 if ( wxTestFontEncoding(*info
) )
649 //else: no such fonts, look for something else
653 wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"), fontinfo
.c_str());
656 //else: there is no information in config about this encoding
658 #endif // wxUSE_CONFIG
663 wxString
title(m_titleDialog
);
665 title
<< wxTheApp
->GetAppName() << _(": unknown encoding");
669 msg
.Printf(_("The encoding '%s' is unknown.\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)?"),
670 GetEncodingDescription(encoding
).c_str());
672 wxWindow
*parent
= m_windowParent
;
674 parent
= wxTheApp
->GetTopWindow();
676 if ( wxMessageBox(msg
, title
,
677 wxICON_QUESTION
| wxYES_NO
, parent
) == wxYES
)
680 data
.SetEncoding(encoding
);
681 data
.EncodingInfo() = *info
;
682 wxFontDialog
dialog(parent
, &data
);
683 if ( dialog
.ShowModal() == wxID_OK
)
685 wxFontData retData
= dialog
.GetFontData();
686 wxFont font
= retData
.GetChosenFont();
688 *info
= retData
.EncodingInfo();
689 info
->encoding
= retData
.GetEncoding();
692 // remember this in the config
693 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
695 GetConfig()->Write(configEntry
, info
->ToString());
697 RestorePath(pathOld
);
703 //else: the user canceled the font selection dialog
705 //else: the user doesn't want to select a font
707 //else: we're in non-interactive mode
709 // now try the default mappings:
710 wxFontEncodingArray equiv
= wxEncodingConverter::GetAllEquivalents(encoding
);
711 size_t count
= equiv
.GetCount();
714 for ( size_t i
= (equiv
[0] == encoding
) ? 1 : 0; i
< count
; i
++ )
716 if ( TestAltEncoding(configEntry
, equiv
[i
], info
) )
724 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
725 wxFontEncoding
*alt_encoding
,
726 const wxString
& facename
,
729 wxNativeEncodingInfo info
;
730 bool r
= GetAltForEncoding(encoding
, &info
, facename
, interactive
);
731 *alt_encoding
= info
.encoding
;
735 bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding
,
736 const wxString
& facename
)
738 wxNativeEncodingInfo info
;
740 if (wxGetNativeFontEncoding(encoding
, &info
))
742 info
.facename
= facename
;
743 return wxTestFontEncoding(info
);