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/msgdlg.h"
46 #include "wx/fontdlg.h"
47 #include "wx/choicdlg.h"
50 #include "wx/encconv.h"
52 // ----------------------------------------------------------------------------
54 // ----------------------------------------------------------------------------
56 // the config paths we use
57 static const wxChar
* FONTMAPPER_ROOT_PATH
= wxT("wxWindows/FontMapper");
58 static const wxChar
* FONTMAPPER_CHARSET_PATH
= wxT("Charsets");
59 static const wxChar
* FONTMAPPER_CHARSET_ALIAS_PATH
= wxT("Aliases");
61 static const wxChar
* FONTMAPPER_FONT_FROM_ENCODING_PATH
= wxT("Encodings");
64 // encodings supported by GetEncodingDescription
65 static wxFontEncoding gs_encodings
[] =
67 wxFONTENCODING_ISO8859_1
,
68 wxFONTENCODING_ISO8859_2
,
69 wxFONTENCODING_ISO8859_3
,
70 wxFONTENCODING_ISO8859_4
,
71 wxFONTENCODING_ISO8859_5
,
72 wxFONTENCODING_ISO8859_6
,
73 wxFONTENCODING_ISO8859_7
,
74 wxFONTENCODING_ISO8859_8
,
75 wxFONTENCODING_ISO8859_9
,
76 wxFONTENCODING_ISO8859_10
,
77 wxFONTENCODING_ISO8859_11
,
78 wxFONTENCODING_ISO8859_12
,
79 wxFONTENCODING_ISO8859_13
,
80 wxFONTENCODING_ISO8859_14
,
81 wxFONTENCODING_ISO8859_15
,
83 wxFONTENCODING_CP1250
,
84 wxFONTENCODING_CP1251
,
85 wxFONTENCODING_CP1252
,
86 wxFONTENCODING_CP1253
,
87 wxFONTENCODING_CP1254
,
88 wxFONTENCODING_CP1255
,
89 wxFONTENCODING_CP1256
,
90 wxFONTENCODING_CP1257
,
94 // the descriptions for them
95 static const wxChar
* gs_encodingDescs
[] =
97 wxTRANSLATE( "West European (ISO-8859-1/Latin 1)" ),
98 wxTRANSLATE( "Central European (ISO-8859-2/Latin 2)" ),
99 wxTRANSLATE( "Esperanto (ISO-8859-3)" ),
100 wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ),
101 wxTRANSLATE( "Cyrillic (Latin 5)" ),
102 wxTRANSLATE( "Arabic (ISO-8859-6)" ),
103 wxTRANSLATE( "Greek (ISO-8859-7)" ),
104 wxTRANSLATE( "Hebrew (ISO-8859-8)" ),
105 wxTRANSLATE( "Turkish (ISO-8859-9)" ),
106 wxTRANSLATE( "Nordic (ISO-8859-10)" ),
107 wxTRANSLATE( "Thai (ISO-8859-11)" ),
108 wxTRANSLATE( "ISO-8859-12" ),
109 wxTRANSLATE( "Baltic (ISO-8859-13)" ),
110 wxTRANSLATE( "ISO-8859-14" ),
111 wxTRANSLATE( "West European new (ISO-8859-15/Latin 0)" ),
112 wxTRANSLATE( "KOI8-R" ),
113 wxTRANSLATE( "Windows Latin 2 (CP 1250)" ),
114 wxTRANSLATE( "Windows Cyrillic (CP 1251)" ),
115 wxTRANSLATE( "Windows Latin 1 (CP 1252)" ),
116 wxTRANSLATE( "Windows Greek (CP 1253)" ),
117 wxTRANSLATE( "Windows Turkish (CP 1254)" ),
118 wxTRANSLATE( "Windows Hebrew (CP 1255)" ),
119 wxTRANSLATE( "Windows Arabic (CP 1256)" ),
120 wxTRANSLATE( "Windows Baltic (CP 1257)" ),
121 wxTRANSLATE( "Windows/DOS OEM (CP 437)" ),
124 // and the internal names
125 static const wxChar
* gs_encodingNames
[] =
143 wxT( "windows1250" ),
144 wxT( "windows1251" ),
145 wxT( "windows1252" ),
146 wxT( "windows1253" ),
147 wxT( "windows1254" ),
148 wxT( "windows1255" ),
149 wxT( "windows1256" ),
150 wxT( "windows1257" ),
154 // ----------------------------------------------------------------------------
156 // ----------------------------------------------------------------------------
159 static wxFontMapper gs_fontMapper
;
161 // and public pointer
162 wxFontMapper
* wxTheFontMapper
= &gs_fontMapper
;
164 // ----------------------------------------------------------------------------
166 // ----------------------------------------------------------------------------
168 // change the config path during the lifetime of this object
169 class wxFontMapperPathChanger
172 wxFontMapperPathChanger(wxFontMapper
*fontMapper
, const wxString
& path
)
174 m_fontMapper
= fontMapper
;
175 m_ok
= m_fontMapper
->ChangePath(path
, &m_pathOld
);
178 bool IsOk() const { return m_ok
; }
180 ~wxFontMapperPathChanger()
183 m_fontMapper
->RestorePath(m_pathOld
);
187 wxFontMapper
*m_fontMapper
;
192 // ============================================================================
194 // ============================================================================
196 // ----------------------------------------------------------------------------
198 // ----------------------------------------------------------------------------
200 wxFontMapper::wxFontMapper()
204 #endif // wxUSE_CONFIG
207 m_windowParent
= NULL
;
211 wxFontMapper::~wxFontMapper()
215 // ----------------------------------------------------------------------------
217 // ----------------------------------------------------------------------------
221 /* static */ const wxChar
*wxFontMapper::GetDefaultConfigPath()
223 return FONTMAPPER_ROOT_PATH
;
226 void wxFontMapper::SetConfigPath(const wxString
& prefix
)
228 wxCHECK_RET( !prefix
.IsEmpty() && prefix
[0] == wxCONFIG_PATH_SEPARATOR
,
229 wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") );
231 m_configRootPath
= prefix
;
234 // ----------------------------------------------------------------------------
235 // get config object and path for it
236 // ----------------------------------------------------------------------------
238 wxConfigBase
*wxFontMapper::GetConfig()
243 m_config
= wxConfig::Get(FALSE
/*don't create on demand*/ );
247 // we still want to have a config object because otherwise we would
248 // keep asking the user the same questions in the interactive mode,
249 // so create a dummy config which won't write to any files/registry
250 // but will allow us to remember the results of the questions at
251 // least during this run
252 m_config
= new wxMemoryConfig
;
253 wxConfig::Set(m_config
);
260 const wxString
& wxFontMapper::GetConfigPath()
262 if ( !m_configRootPath
)
265 m_configRootPath
= GetDefaultConfigPath();
268 return m_configRootPath
;
272 bool wxFontMapper::ChangePath(const wxString
& pathNew
, wxString
*pathOld
)
275 wxConfigBase
*config
= GetConfig();
279 *pathOld
= config
->GetPath();
281 wxString path
= GetConfigPath();
282 if ( path
.IsEmpty() || path
.Last() != wxCONFIG_PATH_SEPARATOR
)
284 path
+= wxCONFIG_PATH_SEPARATOR
;
287 wxASSERT_MSG( !pathNew
|| (pathNew
[0] != wxCONFIG_PATH_SEPARATOR
),
288 wxT("should be a relative path") );
292 config
->SetPath(path
);
300 void wxFontMapper::RestorePath(const wxString
& pathOld
)
303 GetConfig()->SetPath(pathOld
);
308 // ----------------------------------------------------------------------------
309 // charset/encoding correspondence
310 // ----------------------------------------------------------------------------
313 wxString
wxFontMapper::GetEncodingDescription(wxFontEncoding encoding
)
315 size_t count
= WXSIZEOF(gs_encodingDescs
);
317 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
318 wxT("inconsitency detected - forgot to update one of the arrays?") );
320 for ( size_t i
= 0; i
< count
; i
++ )
322 if ( gs_encodings
[i
] == encoding
)
324 return wxGetTranslation(gs_encodingDescs
[i
]);
329 str
.Printf(_("Unknown encoding (%d)"), encoding
);
335 wxString
wxFontMapper::GetEncodingName(wxFontEncoding encoding
)
337 size_t count
= WXSIZEOF(gs_encodingNames
);
339 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
340 wxT("inconsistency detected - forgot to update one of the arrays?") );
342 for ( size_t i
= 0; i
< count
; i
++ )
344 if ( gs_encodings
[i
] == encoding
)
346 return wxGetTranslation(gs_encodingNames
[i
]);
351 str
.Printf(_("unknown-%d"), encoding
);
356 wxFontEncoding
wxFontMapper::CharsetToEncoding(const wxString
& charset
,
359 wxFontEncoding encoding
= wxFONTENCODING_SYSTEM
;
361 // we're going to modify it, make a copy
362 wxString cs
= charset
;
365 // first try the user-defined settings
367 if ( ChangePath(FONTMAPPER_CHARSET_PATH
, &pathOld
) )
369 wxConfigBase
*config
= GetConfig();
371 // do we have an encoding for this charset?
372 long value
= config
->Read(charset
, -1l);
375 if ( value
>= 0 && value
<= wxFONTENCODING_MAX
)
377 encoding
= (wxFontEncoding
)value
;
381 wxLogDebug(wxT("corrupted config data: invalid encoding %ld for charset '%s' ignored"),
382 value
, charset
.c_str());
386 if ( encoding
== wxFONTENCODING_SYSTEM
)
388 // may be we have an alias?
389 config
->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH
);
391 wxString alias
= config
->Read(charset
);
394 // yes, we do - use it instead
399 RestorePath(pathOld
);
403 // if didn't find it there, try to reckognise it ourselves
404 if ( encoding
== wxFONTENCODING_SYSTEM
)
408 if ( !cs
|| cs
== wxT("US-ASCII") )
409 encoding
= wxFONTENCODING_DEFAULT
;
410 else if ( cs
== wxT("KOI8-R") || cs
== wxT("KOI8-U") )
411 encoding
= wxFONTENCODING_KOI8
;
412 else if ( cs
.Left(3) == wxT("ISO") )
414 // the dash is optional (or, to be exact, it is not, but
415 // several brokenmails "forget" it)
416 const wxChar
*p
= cs
.c_str() + 3;
417 if ( *p
== wxT('-') )
421 if ( wxSscanf(p
, wxT("8859-%u"), &value
) == 1 )
423 if ( value
< wxFONTENCODING_ISO8859_MAX
-
424 wxFONTENCODING_ISO8859_1
)
426 // it's a valid ISO8859 encoding
427 value
+= wxFONTENCODING_ISO8859_1
- 1;
428 encoding
= (wxFontEncoding
)value
;
432 else if ( cs
.Left(8) == wxT("WINDOWS-") )
435 if ( wxSscanf(cs
.c_str() + 8, wxT("%u"), &value
) == 1 )
440 if ( value
< wxFONTENCODING_CP12_MAX
-
441 wxFONTENCODING_CP1250
- 1 )
443 // a valid Windows code page
444 value
+= wxFONTENCODING_CP1250
;
445 encoding
= (wxFontEncoding
)value
;
454 // if still no luck, ask the user - unless disabled
455 if ( (encoding
== wxFONTENCODING_SYSTEM
) && interactive
)
457 // prepare the dialog data
460 wxString
title(m_titleDialog
);
462 title
<< wxTheApp
->GetAppName() << _(": unknown charset");
466 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());
468 // the list of choices
469 size_t count
= WXSIZEOF(gs_encodingDescs
);
471 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
472 wxT("inconsitency detected - forgot to update one of the arrays?") );
474 wxString
*encodingNamesTranslated
= new wxString
[count
];
476 for ( size_t i
= 0; i
< count
; i
++ )
478 encodingNamesTranslated
[i
] = wxGetTranslation(gs_encodingDescs
[i
]);
482 wxWindow
*parent
= m_windowParent
;
484 parent
= wxTheApp
->GetTopWindow();
486 // do ask the user and get back the index in encodings table
487 int n
= wxGetSingleChoiceIndex(msg
, title
,
489 encodingNamesTranslated
,
492 delete [] encodingNamesTranslated
;
496 encoding
= gs_encodings
[n
];
499 // save the result in the config now
500 if ( ChangePath(FONTMAPPER_CHARSET_PATH
, &pathOld
) )
502 wxConfigBase
*config
= GetConfig();
504 // remember the alt encoding for this charset
505 if ( !config
->Write(charset
, (long)encoding
) )
507 wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset
.c_str());
510 RestorePath(pathOld
);
512 #endif // wxUSE_CONFIG
521 // ----------------------------------------------------------------------------
522 // support for unknown encodings: we maintain a map between the
523 // (platform-specific) strings identifying them and our wxFontEncodings they
524 // correspond to which is used by GetFontForEncoding() function
525 // ----------------------------------------------------------------------------
529 bool wxFontMapper::TestAltEncoding(const wxString
& configEntry
,
530 wxFontEncoding encReplacement
,
531 wxNativeEncodingInfo
*info
)
533 if ( wxGetNativeFontEncoding(encReplacement
, info
) &&
534 wxTestFontEncoding(*info
) )
537 // remember the mapping in the config
538 wxFontMapperPathChanger
path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH
);
542 GetConfig()->Write(configEntry
, info
->ToString());
544 #endif // wxUSE_CONFIG
552 class ReentrancyBlocker
555 ReentrancyBlocker(bool& b
) : m_b(b
) { m_b
= TRUE
; }
556 ~ReentrancyBlocker() { m_b
= FALSE
; }
563 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
564 wxNativeEncodingInfo
*info
,
565 const wxString
& facename
,
569 // we need a flag to prevent infinite recursion which happens, for
570 // example, when GetAltForEncoding() is called from an OnPaint() handler:
571 // in this case, wxYield() which is called from wxMessageBox() we use here
572 // will lead to another call of OnPaint() and hence to another call of
573 // GetAltForEncoding() - and it is impossible to catch this from the user
574 // code because we are called from wxFont ctor implicitly.
576 // assume we're always called from the main thread, so that it is safe to
578 static bool s_inGetAltForEncoding
= FALSE
;
580 if ( interactive
&& s_inGetAltForEncoding
)
583 ReentrancyBlocker
blocker(s_inGetAltForEncoding
);
586 wxCHECK_MSG( info
, FALSE
, wxT("bad pointer in GetAltForEncoding") );
588 info
->facename
= facename
;
590 if ( encoding
== wxFONTENCODING_DEFAULT
)
592 encoding
= wxFont::GetDefaultEncoding();
595 // if we failed to load the system default encoding, something is really
596 // wrong and we'd better stop now - otherwise we will go into endless
597 // recursion trying to create the font in the msg box with the error
599 if ( encoding
== wxFONTENCODING_SYSTEM
)
601 wxFatalError(_("can't load any font, aborting"));
603 // wxFatalError doesn't return
606 wxString configEntry
, encName
= GetEncodingName(encoding
);
609 configEntry
= facename
+ _T("_");
611 configEntry
+= encName
;
614 // do we have a font spec for this encoding?
616 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
618 wxConfigBase
*config
= GetConfig();
620 wxString fontinfo
= config
->Read(configEntry
);
622 RestorePath(pathOld
);
624 if ( !!fontinfo
&& !!facename
)
626 // we tried to find a match with facename - now try without it
627 fontinfo
= config
->Read(encName
);
632 if ( info
->FromString(fontinfo
) )
634 if ( wxTestFontEncoding(*info
) )
639 //else: no such fonts, look for something else
643 wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"), fontinfo
.c_str());
646 //else: there is no information in config about this encoding
648 #endif // wxUSE_CONFIG
653 wxString
title(m_titleDialog
);
655 title
<< wxTheApp
->GetAppName() << _(": unknown encoding");
659 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)?"),
660 GetEncodingDescription(encoding
).c_str());
662 wxWindow
*parent
= m_windowParent
;
664 parent
= wxTheApp
->GetTopWindow();
666 if ( wxMessageBox(msg
, title
,
667 wxICON_QUESTION
| wxYES_NO
, parent
) == wxYES
)
670 data
.SetEncoding(encoding
);
671 data
.EncodingInfo() = *info
;
672 wxFontDialog
dialog(parent
, &data
);
673 if ( dialog
.ShowModal() == wxID_OK
)
675 wxFontData retData
= dialog
.GetFontData();
676 wxFont font
= retData
.GetChosenFont();
678 *info
= retData
.EncodingInfo();
679 info
-> encoding
= retData
.GetEncoding();
682 // remember this in the config
683 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
685 GetConfig()->Write(configEntry
, info
->ToString());
687 RestorePath(pathOld
);
693 //else: the user canceled the font selection dialog
695 //else: the user doesn't want to select a font
697 //else: we're in non-interactive mode
699 // now try the default mappings:
700 wxFontEncodingArray equiv
= wxEncodingConverter::GetAllEquivalents(encoding
);
701 size_t count
= equiv
.GetCount();
702 for ( size_t i
= (equiv
[0] == encoding
) ? 1 : 0; i
< count
; i
++ )
704 if ( TestAltEncoding(configEntry
, equiv
[i
], info
) )
711 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
712 wxFontEncoding
*alt_encoding
,
713 const wxString
& facename
,
716 wxNativeEncodingInfo info
;
717 bool r
= GetAltForEncoding(encoding
, &info
, facename
, interactive
);
718 *alt_encoding
= info
.encoding
;
722 bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding
,
723 const wxString
& facename
)
725 wxNativeEncodingInfo info
;
727 if (wxGetNativeFontEncoding(encoding
, &info
))
729 info
.facename
= facename
;
730 return wxTestFontEncoding(info
);