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
)
406 // discard the optional quotes
409 if ( cs
[0u] == _T('"') && cs
.Last() == _T('"') )
411 cs
= wxString(cs
.c_str(), cs
.length() - 1);
417 if ( !cs
|| cs
== wxT("US-ASCII") )
418 encoding
= wxFONTENCODING_DEFAULT
;
419 else if ( cs
== wxT("KOI8-R") || cs
== wxT("KOI8-U") )
420 encoding
= wxFONTENCODING_KOI8
;
421 else if ( cs
.Left(3) == wxT("ISO") )
423 // the dash is optional (or, to be exact, it is not, but
424 // several brokenmails "forget" it)
425 const wxChar
*p
= cs
.c_str() + 3;
426 if ( *p
== wxT('-') )
430 if ( wxSscanf(p
, wxT("8859-%u"), &value
) == 1 )
432 if ( value
< wxFONTENCODING_ISO8859_MAX
-
433 wxFONTENCODING_ISO8859_1
)
435 // it's a valid ISO8859 encoding
436 value
+= wxFONTENCODING_ISO8859_1
- 1;
437 encoding
= (wxFontEncoding
)value
;
441 else if ( cs
.Left(8) == wxT("WINDOWS-") )
444 if ( wxSscanf(cs
.c_str() + 8, wxT("%u"), &value
) == 1 )
449 if ( value
< wxFONTENCODING_CP12_MAX
-
450 wxFONTENCODING_CP1250
- 1 )
452 // a valid Windows code page
453 value
+= wxFONTENCODING_CP1250
;
454 encoding
= (wxFontEncoding
)value
;
463 // if still no luck, ask the user - unless disabled
464 if ( (encoding
== wxFONTENCODING_SYSTEM
) && interactive
)
466 // prepare the dialog data
469 wxString
title(m_titleDialog
);
471 title
<< wxTheApp
->GetAppName() << _(": unknown charset");
475 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());
477 // the list of choices
478 size_t count
= WXSIZEOF(gs_encodingDescs
);
480 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
481 wxT("inconsitency detected - forgot to update one of the arrays?") );
483 wxString
*encodingNamesTranslated
= new wxString
[count
];
485 for ( size_t i
= 0; i
< count
; i
++ )
487 encodingNamesTranslated
[i
] = wxGetTranslation(gs_encodingDescs
[i
]);
491 wxWindow
*parent
= m_windowParent
;
493 parent
= wxTheApp
->GetTopWindow();
495 // do ask the user and get back the index in encodings table
496 int n
= wxGetSingleChoiceIndex(msg
, title
,
498 encodingNamesTranslated
,
501 delete [] encodingNamesTranslated
;
505 encoding
= gs_encodings
[n
];
508 // save the result in the config now
509 if ( ChangePath(FONTMAPPER_CHARSET_PATH
, &pathOld
) )
511 wxConfigBase
*config
= GetConfig();
513 // remember the alt encoding for this charset
514 if ( !config
->Write(charset
, (long)encoding
) )
516 wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset
.c_str());
519 RestorePath(pathOld
);
521 #endif // wxUSE_CONFIG
530 // ----------------------------------------------------------------------------
531 // support for unknown encodings: we maintain a map between the
532 // (platform-specific) strings identifying them and our wxFontEncodings they
533 // correspond to which is used by GetFontForEncoding() function
534 // ----------------------------------------------------------------------------
538 bool wxFontMapper::TestAltEncoding(const wxString
& configEntry
,
539 wxFontEncoding encReplacement
,
540 wxNativeEncodingInfo
*info
)
542 if ( wxGetNativeFontEncoding(encReplacement
, info
) &&
543 wxTestFontEncoding(*info
) )
546 // remember the mapping in the config
547 wxFontMapperPathChanger
path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH
);
551 GetConfig()->Write(configEntry
, info
->ToString());
553 #endif // wxUSE_CONFIG
561 class ReentrancyBlocker
564 ReentrancyBlocker(bool& b
) : m_b(b
) { m_b
= TRUE
; }
565 ~ReentrancyBlocker() { m_b
= FALSE
; }
572 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
573 wxNativeEncodingInfo
*info
,
574 const wxString
& facename
,
578 // we need a flag to prevent infinite recursion which happens, for
579 // example, when GetAltForEncoding() is called from an OnPaint() handler:
580 // in this case, wxYield() which is called from wxMessageBox() we use here
581 // will lead to another call of OnPaint() and hence to another call of
582 // GetAltForEncoding() - and it is impossible to catch this from the user
583 // code because we are called from wxFont ctor implicitly.
585 // assume we're always called from the main thread, so that it is safe to
587 static bool s_inGetAltForEncoding
= FALSE
;
589 if ( interactive
&& s_inGetAltForEncoding
)
592 ReentrancyBlocker
blocker(s_inGetAltForEncoding
);
595 wxCHECK_MSG( info
, FALSE
, wxT("bad pointer in GetAltForEncoding") );
597 info
->facename
= facename
;
599 if ( encoding
== wxFONTENCODING_DEFAULT
)
601 encoding
= wxFont::GetDefaultEncoding();
604 // if we failed to load the system default encoding, something is really
605 // wrong and we'd better stop now - otherwise we will go into endless
606 // recursion trying to create the font in the msg box with the error
608 if ( encoding
== wxFONTENCODING_SYSTEM
)
610 wxFatalError(_("can't load any font, aborting"));
612 // wxFatalError doesn't return
615 wxString configEntry
, encName
= GetEncodingName(encoding
);
618 configEntry
= facename
+ _T("_");
620 configEntry
+= encName
;
623 // do we have a font spec for this encoding?
625 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
627 wxConfigBase
*config
= GetConfig();
629 wxString fontinfo
= config
->Read(configEntry
);
631 RestorePath(pathOld
);
633 if ( !!fontinfo
&& !!facename
)
635 // we tried to find a match with facename - now try without it
636 fontinfo
= config
->Read(encName
);
641 if ( info
->FromString(fontinfo
) )
643 if ( wxTestFontEncoding(*info
) )
648 //else: no such fonts, look for something else
652 wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"), fontinfo
.c_str());
655 //else: there is no information in config about this encoding
657 #endif // wxUSE_CONFIG
662 wxString
title(m_titleDialog
);
664 title
<< wxTheApp
->GetAppName() << _(": unknown encoding");
668 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)?"),
669 GetEncodingDescription(encoding
).c_str());
671 wxWindow
*parent
= m_windowParent
;
673 parent
= wxTheApp
->GetTopWindow();
675 if ( wxMessageBox(msg
, title
,
676 wxICON_QUESTION
| wxYES_NO
, parent
) == wxYES
)
679 data
.SetEncoding(encoding
);
680 data
.EncodingInfo() = *info
;
681 wxFontDialog
dialog(parent
, &data
);
682 if ( dialog
.ShowModal() == wxID_OK
)
684 wxFontData retData
= dialog
.GetFontData();
685 wxFont font
= retData
.GetChosenFont();
687 *info
= retData
.EncodingInfo();
688 info
-> encoding
= retData
.GetEncoding();
691 // remember this in the config
692 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
694 GetConfig()->Write(configEntry
, info
->ToString());
696 RestorePath(pathOld
);
702 //else: the user canceled the font selection dialog
704 //else: the user doesn't want to select a font
706 //else: we're in non-interactive mode
708 // now try the default mappings:
709 wxFontEncodingArray equiv
= wxEncodingConverter::GetAllEquivalents(encoding
);
710 size_t count
= equiv
.GetCount();
713 for ( size_t i
= (equiv
[0] == encoding
) ? 1 : 0; i
< count
; i
++ )
715 if ( TestAltEncoding(configEntry
, equiv
[i
], info
) )
723 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
724 wxFontEncoding
*alt_encoding
,
725 const wxString
& facename
,
728 wxNativeEncodingInfo info
;
729 bool r
= GetAltForEncoding(encoding
, &info
, facename
, interactive
);
730 *alt_encoding
= info
.encoding
;
734 bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding
,
735 const wxString
& facename
)
737 wxNativeEncodingInfo info
;
739 if (wxGetNativeFontEncoding(encoding
, &info
))
741 info
.facename
= facename
;
742 return wxTestFontEncoding(info
);