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
,
97 // the descriptions for them
98 static const wxChar
* gs_encodingDescs
[] =
100 wxTRANSLATE( "Western European (ISO-8859-1)" ),
101 wxTRANSLATE( "Central European (ISO-8859-2)" ),
102 wxTRANSLATE( "Esperanto (ISO-8859-3)" ),
103 wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ),
104 wxTRANSLATE( "Cyrillic (ISO-8859-5)" ),
105 wxTRANSLATE( "Arabic (ISO-8859-6)" ),
106 wxTRANSLATE( "Greek (ISO-8859-7)" ),
107 wxTRANSLATE( "Hebrew (ISO-8859-8)" ),
108 wxTRANSLATE( "Turkish (ISO-8859-9)" ),
109 wxTRANSLATE( "Nordic (ISO-8859-10)" ),
110 wxTRANSLATE( "Thai (ISO-8859-11)" ),
111 wxTRANSLATE( "Indian (ISO-8859-12)" ),
112 wxTRANSLATE( "Baltic (ISO-8859-13)" ),
113 wxTRANSLATE( "Celtic (ISO-8859-14)" ),
114 wxTRANSLATE( "Western European with Euro (ISO-8859-15)" ),
115 wxTRANSLATE( "KOI8-R" ),
116 wxTRANSLATE( "Windows Central European (CP 1250)" ),
117 wxTRANSLATE( "Windows Cyrillic (CP 1251)" ),
118 wxTRANSLATE( "Windows Western European (CP 1252)" ),
119 wxTRANSLATE( "Windows Greek (CP 1253)" ),
120 wxTRANSLATE( "Windows Turkish (CP 1254)" ),
121 wxTRANSLATE( "Windows Hebrew (CP 1255)" ),
122 wxTRANSLATE( "Windows Arabic (CP 1256)" ),
123 wxTRANSLATE( "Windows Baltic (CP 1257)" ),
124 wxTRANSLATE( "Windows/DOS OEM (CP 437)" ),
125 wxTRANSLATE( "Unicode 7 bit (UTF-7)" ),
126 wxTRANSLATE( "Unicode 8 bit (UTF-8)" ),
129 // and the internal names
130 static const wxChar
* gs_encodingNames
[] =
148 wxT( "windows1250" ),
149 wxT( "windows1251" ),
150 wxT( "windows1252" ),
151 wxT( "windows1253" ),
152 wxT( "windows1254" ),
153 wxT( "windows1255" ),
154 wxT( "windows1256" ),
155 wxT( "windows1257" ),
161 // ----------------------------------------------------------------------------
163 // ----------------------------------------------------------------------------
166 static wxFontMapper gs_fontMapper
;
168 // and public pointer
169 wxFontMapper
* wxTheFontMapper
= &gs_fontMapper
;
171 // ----------------------------------------------------------------------------
173 // ----------------------------------------------------------------------------
175 // change the config path during the lifetime of this object
176 class wxFontMapperPathChanger
179 wxFontMapperPathChanger(wxFontMapper
*fontMapper
, const wxString
& path
)
181 m_fontMapper
= fontMapper
;
182 m_ok
= m_fontMapper
->ChangePath(path
, &m_pathOld
);
185 bool IsOk() const { return m_ok
; }
187 ~wxFontMapperPathChanger()
190 m_fontMapper
->RestorePath(m_pathOld
);
194 wxFontMapper
*m_fontMapper
;
199 // ============================================================================
201 // ============================================================================
203 // ----------------------------------------------------------------------------
205 // ----------------------------------------------------------------------------
207 wxFontMapper::wxFontMapper()
211 #endif // wxUSE_CONFIG
214 m_windowParent
= NULL
;
218 wxFontMapper::~wxFontMapper()
222 // ----------------------------------------------------------------------------
224 // ----------------------------------------------------------------------------
228 /* static */ const wxChar
*wxFontMapper::GetDefaultConfigPath()
230 return FONTMAPPER_ROOT_PATH
;
233 void wxFontMapper::SetConfigPath(const wxString
& prefix
)
235 wxCHECK_RET( !prefix
.IsEmpty() && prefix
[0] == wxCONFIG_PATH_SEPARATOR
,
236 wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") );
238 m_configRootPath
= prefix
;
241 // ----------------------------------------------------------------------------
242 // get config object and path for it
243 // ----------------------------------------------------------------------------
245 wxConfigBase
*wxFontMapper::GetConfig()
250 m_config
= wxConfig::Get(FALSE
/*don't create on demand*/ );
254 // we still want to have a config object because otherwise we would
255 // keep asking the user the same questions in the interactive mode,
256 // so create a dummy config which won't write to any files/registry
257 // but will allow us to remember the results of the questions at
258 // least during this run
259 m_config
= new wxMemoryConfig
;
260 wxConfig::Set(m_config
);
267 const wxString
& wxFontMapper::GetConfigPath()
269 if ( !m_configRootPath
)
272 m_configRootPath
= GetDefaultConfigPath();
275 return m_configRootPath
;
279 bool wxFontMapper::ChangePath(const wxString
& pathNew
, wxString
*pathOld
)
282 wxConfigBase
*config
= GetConfig();
286 *pathOld
= config
->GetPath();
288 wxString path
= GetConfigPath();
289 if ( path
.IsEmpty() || path
.Last() != wxCONFIG_PATH_SEPARATOR
)
291 path
+= wxCONFIG_PATH_SEPARATOR
;
294 wxASSERT_MSG( !pathNew
|| (pathNew
[0] != wxCONFIG_PATH_SEPARATOR
),
295 wxT("should be a relative path") );
299 config
->SetPath(path
);
307 void wxFontMapper::RestorePath(const wxString
& pathOld
)
310 GetConfig()->SetPath(pathOld
);
315 // ----------------------------------------------------------------------------
316 // charset/encoding correspondence
317 // ----------------------------------------------------------------------------
320 wxString
wxFontMapper::GetEncodingDescription(wxFontEncoding encoding
)
322 size_t count
= WXSIZEOF(gs_encodingDescs
);
324 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
325 wxT("inconsitency detected - forgot to update one of the arrays?") );
327 for ( size_t i
= 0; i
< count
; i
++ )
329 if ( gs_encodings
[i
] == encoding
)
331 return wxGetTranslation(gs_encodingDescs
[i
]);
336 str
.Printf(_("Unknown encoding (%d)"), encoding
);
342 wxString
wxFontMapper::GetEncodingName(wxFontEncoding encoding
)
344 size_t count
= WXSIZEOF(gs_encodingNames
);
346 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
347 wxT("inconsistency detected - forgot to update one of the arrays?") );
349 for ( size_t i
= 0; i
< count
; i
++ )
351 if ( gs_encodings
[i
] == encoding
)
353 return wxGetTranslation(gs_encodingNames
[i
]);
358 str
.Printf(_("unknown-%d"), encoding
);
363 wxFontEncoding
wxFontMapper::CharsetToEncoding(const wxString
& charset
,
366 wxFontEncoding encoding
= wxFONTENCODING_SYSTEM
;
368 // we're going to modify it, make a copy
369 wxString cs
= charset
;
372 // first try the user-defined settings
374 if ( ChangePath(FONTMAPPER_CHARSET_PATH
, &pathOld
) )
376 wxConfigBase
*config
= GetConfig();
378 // do we have an encoding for this charset?
379 long value
= config
->Read(charset
, -1l);
382 if ( value
>= 0 && value
<= wxFONTENCODING_MAX
)
384 encoding
= (wxFontEncoding
)value
;
388 wxLogDebug(wxT("corrupted config data: invalid encoding %ld for charset '%s' ignored"),
389 value
, charset
.c_str());
393 if ( encoding
== wxFONTENCODING_SYSTEM
)
395 // may be we have an alias?
396 config
->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH
);
398 wxString alias
= config
->Read(charset
);
401 // yes, we do - use it instead
406 RestorePath(pathOld
);
408 #endif // wxUSE_CONFIG
410 // if didn't find it there, try to reckognise it ourselves
411 if ( encoding
== wxFONTENCODING_SYSTEM
)
413 // discard the optional quotes
416 if ( cs
[0u] == _T('"') && cs
.Last() == _T('"') )
418 cs
= wxString(cs
.c_str(), cs
.length() - 1);
424 if ( !cs
|| cs
== wxT("US-ASCII") )
425 encoding
= wxFONTENCODING_DEFAULT
;
426 else if ( cs
== wxT("UTF-7") )
427 encoding
= wxFONTENCODING_UTF7
;
428 else if ( cs
== wxT("UTF-8") )
429 encoding
= wxFONTENCODING_UTF8
;
430 else if ( cs
== wxT("KOI8-R") || cs
== wxT("KOI8-U") )
431 encoding
= wxFONTENCODING_KOI8
;
432 else if ( cs
.Left(3) == wxT("ISO") )
434 // the dash is optional (or, to be exact, it is not, but
435 // several brokenmails "forget" it)
436 const wxChar
*p
= cs
.c_str() + 3;
437 if ( *p
== wxT('-') )
441 if ( wxSscanf(p
, wxT("8859-%u"), &value
) == 1 )
443 if ( value
< wxFONTENCODING_ISO8859_MAX
-
444 wxFONTENCODING_ISO8859_1
)
446 // it's a valid ISO8859 encoding
447 value
+= wxFONTENCODING_ISO8859_1
- 1;
448 encoding
= (wxFontEncoding
)value
;
452 else if ( cs
.Left(8) == wxT("WINDOWS-") )
455 if ( wxSscanf(cs
.c_str() + 8, wxT("%u"), &value
) == 1 )
460 if ( value
< wxFONTENCODING_CP12_MAX
-
461 wxFONTENCODING_CP1250
)
463 // a valid Windows code page
464 value
+= wxFONTENCODING_CP1250
;
465 encoding
= (wxFontEncoding
)value
;
474 // if still no luck, ask the user - unless disabled
475 if ( (encoding
== wxFONTENCODING_SYSTEM
) && interactive
)
477 // prepare the dialog data
480 wxString
title(m_titleDialog
);
482 title
<< wxTheApp
->GetAppName() << _(": unknown charset");
486 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());
488 // the list of choices
489 size_t count
= WXSIZEOF(gs_encodingDescs
);
491 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
492 wxT("inconsitency detected - forgot to update one of the arrays?") );
494 wxString
*encodingNamesTranslated
= new wxString
[count
];
496 for ( size_t i
= 0; i
< count
; i
++ )
498 encodingNamesTranslated
[i
] = wxGetTranslation(gs_encodingDescs
[i
]);
502 wxWindow
*parent
= m_windowParent
;
504 parent
= wxTheApp
->GetTopWindow();
506 // do ask the user and get back the index in encodings table
507 int n
= wxGetSingleChoiceIndex(msg
, title
,
509 encodingNamesTranslated
,
512 delete [] encodingNamesTranslated
;
516 encoding
= gs_encodings
[n
];
519 // save the result in the config now
520 if ( ChangePath(FONTMAPPER_CHARSET_PATH
, &pathOld
) )
522 wxConfigBase
*config
= GetConfig();
524 // remember the alt encoding for this charset
525 if ( !config
->Write(charset
, (long)encoding
) )
527 wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset
.c_str());
530 RestorePath(pathOld
);
532 #endif // wxUSE_CONFIG
541 // ----------------------------------------------------------------------------
542 // support for unknown encodings: we maintain a map between the
543 // (platform-specific) strings identifying them and our wxFontEncodings they
544 // correspond to which is used by GetFontForEncoding() function
545 // ----------------------------------------------------------------------------
549 bool wxFontMapper::TestAltEncoding(const wxString
& configEntry
,
550 wxFontEncoding encReplacement
,
551 wxNativeEncodingInfo
*info
)
553 if ( wxGetNativeFontEncoding(encReplacement
, info
) &&
554 wxTestFontEncoding(*info
) )
557 // remember the mapping in the config
558 wxFontMapperPathChanger
path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH
);
562 GetConfig()->Write(configEntry
, info
->ToString());
564 #endif // wxUSE_CONFIG
572 class ReentrancyBlocker
575 ReentrancyBlocker(bool& b
) : m_b(b
) { m_b
= TRUE
; }
576 ~ReentrancyBlocker() { m_b
= FALSE
; }
583 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
584 wxNativeEncodingInfo
*info
,
585 const wxString
& facename
,
589 // we need a flag to prevent infinite recursion which happens, for
590 // example, when GetAltForEncoding() is called from an OnPaint() handler:
591 // in this case, wxYield() which is called from wxMessageBox() we use here
592 // will lead to another call of OnPaint() and hence to another call of
593 // GetAltForEncoding() - and it is impossible to catch this from the user
594 // code because we are called from wxFont ctor implicitly.
596 // assume we're always called from the main thread, so that it is safe to
598 static bool s_inGetAltForEncoding
= FALSE
;
600 if ( interactive
&& s_inGetAltForEncoding
)
603 ReentrancyBlocker
blocker(s_inGetAltForEncoding
);
606 wxCHECK_MSG( info
, FALSE
, wxT("bad pointer in GetAltForEncoding") );
608 info
->facename
= facename
;
610 if ( encoding
== wxFONTENCODING_DEFAULT
)
612 encoding
= wxFont::GetDefaultEncoding();
615 // if we failed to load the system default encoding, something is really
616 // wrong and we'd better stop now - otherwise we will go into endless
617 // recursion trying to create the font in the msg box with the error
619 if ( encoding
== wxFONTENCODING_SYSTEM
)
621 wxFatalError(_("can't load any font, aborting"));
623 // wxFatalError doesn't return
626 wxString configEntry
, encName
= GetEncodingName(encoding
);
629 configEntry
= facename
+ _T("_");
631 configEntry
+= encName
;
634 // do we have a font spec for this encoding?
636 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
638 wxConfigBase
*config
= GetConfig();
640 wxString fontinfo
= config
->Read(configEntry
);
642 RestorePath(pathOld
);
644 if ( !!fontinfo
&& !!facename
)
646 // we tried to find a match with facename - now try without it
647 fontinfo
= config
->Read(encName
);
652 if ( info
->FromString(fontinfo
) )
654 if ( wxTestFontEncoding(*info
) )
659 //else: no such fonts, look for something else
663 wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"), fontinfo
.c_str());
666 //else: there is no information in config about this encoding
668 #endif // wxUSE_CONFIG
673 wxString
title(m_titleDialog
);
675 title
<< wxTheApp
->GetAppName() << _(": unknown encoding");
679 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)?"),
680 GetEncodingDescription(encoding
).c_str());
682 wxWindow
*parent
= m_windowParent
;
684 parent
= wxTheApp
->GetTopWindow();
686 if ( wxMessageBox(msg
, title
,
687 wxICON_QUESTION
| wxYES_NO
, parent
) == wxYES
)
690 data
.SetEncoding(encoding
);
691 data
.EncodingInfo() = *info
;
692 wxFontDialog
dialog(parent
, &data
);
693 if ( dialog
.ShowModal() == wxID_OK
)
695 wxFontData retData
= dialog
.GetFontData();
696 wxFont font
= retData
.GetChosenFont();
698 *info
= retData
.EncodingInfo();
699 info
->encoding
= retData
.GetEncoding();
702 // remember this in the config
703 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
705 GetConfig()->Write(configEntry
, info
->ToString());
707 RestorePath(pathOld
);
709 #endif // wxUSE_CONFIG
713 //else: the user canceled the font selection dialog
715 //else: the user doesn't want to select a font
717 //else: we're in non-interactive mode
719 // now try the default mappings:
720 wxFontEncodingArray equiv
= wxEncodingConverter::GetAllEquivalents(encoding
);
721 size_t count
= equiv
.GetCount();
724 for ( size_t i
= (equiv
[0] == encoding
) ? 1 : 0; i
< count
; i
++ )
726 if ( TestAltEncoding(configEntry
, equiv
[i
], info
) )
734 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
735 wxFontEncoding
*alt_encoding
,
736 const wxString
& facename
,
739 wxNativeEncodingInfo info
;
740 bool r
= GetAltForEncoding(encoding
, &info
, facename
, interactive
);
741 *alt_encoding
= info
.encoding
;
745 bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding
,
746 const wxString
& facename
)
748 wxNativeEncodingInfo info
;
750 if ( wxGetNativeFontEncoding(encoding
, &info
) )
752 info
.facename
= facename
;
753 return wxTestFontEncoding(info
);