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"
38 #include "wx/config.h"
40 #include "wx/msgdlg.h"
41 #include "wx/fontdlg.h"
42 #include "wx/choicdlg.h"
43 #include "wx/encconv.h"
45 // ----------------------------------------------------------------------------
47 // ----------------------------------------------------------------------------
49 // the config paths we use
50 static const wxChar
* FONTMAPPER_ROOT_PATH
= wxT("wxWindows/FontMapper");
51 static const wxChar
* FONTMAPPER_CHARSET_PATH
= wxT("Charsets");
52 static const wxChar
* FONTMAPPER_CHARSET_ALIAS_PATH
= wxT("Aliases");
53 static const wxChar
* FONTMAPPER_FONT_FROM_ENCODING_PATH
= wxT("Encodings");
55 // encodings supported by GetEncodingDescription
56 static wxFontEncoding gs_encodings
[] =
58 wxFONTENCODING_ISO8859_1
,
59 wxFONTENCODING_ISO8859_2
,
60 wxFONTENCODING_ISO8859_3
,
61 wxFONTENCODING_ISO8859_4
,
62 wxFONTENCODING_ISO8859_5
,
63 wxFONTENCODING_ISO8859_6
,
64 wxFONTENCODING_ISO8859_7
,
65 wxFONTENCODING_ISO8859_8
,
66 wxFONTENCODING_ISO8859_9
,
67 wxFONTENCODING_ISO8859_10
,
68 wxFONTENCODING_ISO8859_11
,
69 wxFONTENCODING_ISO8859_12
,
70 wxFONTENCODING_ISO8859_13
,
71 wxFONTENCODING_ISO8859_14
,
72 wxFONTENCODING_ISO8859_15
,
74 wxFONTENCODING_CP1250
,
75 wxFONTENCODING_CP1251
,
76 wxFONTENCODING_CP1252
,
77 wxFONTENCODING_CP1253
,
78 wxFONTENCODING_CP1254
,
79 wxFONTENCODING_CP1255
,
80 wxFONTENCODING_CP1256
,
81 wxFONTENCODING_CP1257
,
84 // the descriptions for them
85 static const wxChar
* gs_encodingDescs
[] =
87 wxTRANSLATE( "West European (ISO-8859-1/Latin 1)" ),
88 wxTRANSLATE( "Central European (ISO-8859-2/Latin 2)" ),
89 wxTRANSLATE( "Esperanto (ISO-8859-3)" ),
90 wxTRANSLATE( "Baltic (ISO-8859-4)" ),
91 wxTRANSLATE( "Cyrillic (Latin 5)" ),
92 wxTRANSLATE( "Arabic (ISO-8859-6)" ),
93 wxTRANSLATE( "Greek (ISO-8859-7)" ),
94 wxTRANSLATE( "Hebrew (ISO-8859-8)" ),
95 wxTRANSLATE( "Turkish (ISO-8859-9)" ),
96 wxTRANSLATE( "Baltic II (ISO-8859-10)" ),
97 wxTRANSLATE( "Thai (ISO-8859-11)" ),
98 wxTRANSLATE( "ISO-8859-12" ),
99 wxTRANSLATE( "ISO-8859-13" ),
100 wxTRANSLATE( "ISO-8859-14" ),
101 wxTRANSLATE( "West European new (ISO-8859-15/Latin 0)" ),
102 wxTRANSLATE( "KOI8-R" ),
103 wxTRANSLATE( "Windows Latin 2 (CP 1250)" ),
104 wxTRANSLATE( "Windows Cyrillic (CP 1251)" ),
105 wxTRANSLATE( "Windows Latin 1 (CP 1252)" ),
106 wxTRANSLATE( "Windows Greek (CP 1253)" ),
107 wxTRANSLATE( "Windows Turkish (CP 1254)" ),
108 wxTRANSLATE( "Windows Hebrew (CP 1255)" ),
109 wxTRANSLATE( "Windows Arabic (CP 1256)" ),
110 wxTRANSLATE( "Windows Baltic (CP 1257)" ),
113 // and the internal names
114 static const wxChar
* gs_encodingNames
[] =
132 wxT( "windows1250" ),
133 wxT( "windows1251" ),
134 wxT( "windows1252" ),
135 wxT( "windows1253" ),
136 wxT( "windows1254" ),
137 wxT( "windows1255" ),
138 wxT( "windows1256" ),
139 wxT( "windows1257" ),
142 // ----------------------------------------------------------------------------
144 // ----------------------------------------------------------------------------
147 static wxFontMapper gs_fontMapper
;
149 // and public pointer
150 wxFontMapper
* wxTheFontMapper
= &gs_fontMapper
;
152 // ----------------------------------------------------------------------------
154 // ----------------------------------------------------------------------------
156 // change the config path during the lifetime of this object
157 class wxFontMapperPathChanger
160 wxFontMapperPathChanger(wxFontMapper
*fontMapper
, const wxString
& path
)
162 m_fontMapper
= fontMapper
;
163 m_ok
= m_fontMapper
->ChangePath(path
, &m_pathOld
);
166 bool IsOk() const { return m_ok
; }
168 ~wxFontMapperPathChanger()
171 m_fontMapper
->RestorePath(m_pathOld
);
175 wxFontMapper
*m_fontMapper
;
180 // ============================================================================
182 // ============================================================================
184 // ----------------------------------------------------------------------------
186 // ----------------------------------------------------------------------------
188 wxFontMapper::wxFontMapper()
191 m_windowParent
= NULL
;
194 wxFontMapper::~wxFontMapper()
198 // ----------------------------------------------------------------------------
200 // ----------------------------------------------------------------------------
202 /* static */ const wxChar
*wxFontMapper::GetDefaultConfigPath()
204 return FONTMAPPER_ROOT_PATH
;
207 void wxFontMapper::SetConfigPath(const wxString
& prefix
)
209 wxCHECK_RET( !prefix
.IsEmpty() && prefix
[0] == wxCONFIG_PATH_SEPARATOR
,
210 wxT("an absolute path should be given to "
211 "wxFontMapper::SetConfigPath()") );
213 m_configRootPath
= prefix
;
217 // ----------------------------------------------------------------------------
218 // get config object and path for it
219 // ----------------------------------------------------------------------------
221 wxConfigBase
*wxFontMapper::GetConfig()
226 m_config
= wxConfig::Get(FALSE
/*don't create on demand*/);
232 const wxString
& wxFontMapper::GetConfigPath()
234 if ( !m_configRootPath
)
237 m_configRootPath
= GetDefaultConfigPath();
240 return m_configRootPath
;
243 bool wxFontMapper::ChangePath(const wxString
& pathNew
, wxString
*pathOld
)
245 wxConfigBase
*config
= GetConfig();
249 *pathOld
= config
->GetPath();
251 wxString path
= GetConfigPath();
252 if ( path
.IsEmpty() || path
.Last() != wxCONFIG_PATH_SEPARATOR
)
254 path
+= wxCONFIG_PATH_SEPARATOR
;
257 wxASSERT_MSG( !pathNew
|| (pathNew
[0] != wxCONFIG_PATH_SEPARATOR
),
258 wxT("should be a relative path") );
262 config
->SetPath(path
);
267 void wxFontMapper::RestorePath(const wxString
& pathOld
)
269 GetConfig()->SetPath(pathOld
);
272 // ----------------------------------------------------------------------------
273 // charset/encoding correspondence
274 // ----------------------------------------------------------------------------
277 wxString
wxFontMapper::GetEncodingDescription(wxFontEncoding encoding
)
279 size_t count
= WXSIZEOF(gs_encodingDescs
);
281 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
282 wxT("inconsitency detected - forgot to update one of "
285 for ( size_t i
= 0; i
< count
; i
++ )
287 if ( gs_encodings
[i
] == encoding
)
289 return wxGetTranslation(gs_encodingDescs
[i
]);
294 str
.Printf(_("Unknown encoding (%d)"), encoding
);
300 wxString
wxFontMapper::GetEncodingName(wxFontEncoding encoding
)
302 size_t count
= WXSIZEOF(gs_encodingNames
);
304 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
305 wxT("inconsitency detected - forgot to update one of "
308 for ( size_t i
= 0; i
< count
; i
++ )
310 if ( gs_encodings
[i
] == encoding
)
312 return wxGetTranslation(gs_encodingNames
[i
]);
317 str
.Printf(_("unknown-%d"), encoding
);
322 wxFontEncoding
wxFontMapper::CharsetToEncoding(const wxString
& charset
,
325 wxFontEncoding encoding
= wxFONTENCODING_SYSTEM
;
327 // we're going to modify it, make a copy
328 wxString cs
= charset
;
330 // first try the user-defined settings
332 if ( ChangePath(FONTMAPPER_CHARSET_PATH
, &pathOld
) )
334 wxConfigBase
*config
= GetConfig();
336 // do we have an encoding for this charset?
337 long value
= config
->Read(charset
, -1l);
340 if ( value
>= 0 && value
<= wxFONTENCODING_MAX
)
342 encoding
= (wxFontEncoding
)value
;
346 wxLogDebug(wxT("corrupted config data - invalid encoding %ld "
347 "for charset '%s'"), value
, charset
.c_str());
351 if ( encoding
== wxFONTENCODING_SYSTEM
)
353 // may be we have an alias?
354 config
->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH
);
356 wxString alias
= config
->Read(charset
);
359 // yes, we do - use it instead
364 RestorePath(pathOld
);
367 // if didn't find it there, try to reckognise it ourselves
368 if ( encoding
== wxFONTENCODING_SYSTEM
)
372 if ( !cs
|| cs
== wxT("US-ASCII") )
373 encoding
= wxFONTENCODING_DEFAULT
;
374 else if ( cs
== wxT("KOI8-R") || cs
== wxT("KOI8-U") )
375 encoding
= wxFONTENCODING_KOI8
;
376 else if ( cs
.Left(3) == wxT("ISO") )
378 // the dash is optional (or, to be exact, it is not, but
379 // several brokenmails "forget" it)
380 const wxChar
*p
= cs
.c_str() + 3;
381 if ( *p
== wxT('-') )
385 if ( wxSscanf(p
, wxT("8859-%u"), &value
) == 1 )
387 if ( value
< wxFONTENCODING_ISO8859_MAX
-
388 wxFONTENCODING_ISO8859_1
)
390 // it's a valid ISO8859 encoding
391 value
+= wxFONTENCODING_ISO8859_1
- 1;
392 encoding
= (wxFontEncoding
)value
;
396 else if ( cs
.Left(8) == wxT("WINDOWS-") )
399 if ( wxSscanf(cs
.c_str() + 8, wxT("%u"), &value
) == 1 )
404 if ( value
< wxFONTENCODING_CP12_MAX
-
405 wxFONTENCODING_CP1250
- 1 )
407 // a valid Windows code page
408 value
+= wxFONTENCODING_CP1250
;
409 encoding
= (wxFontEncoding
)value
;
417 // if still no luck, ask the user - unless disabled
418 if ( (encoding
== wxFONTENCODING_SYSTEM
) && interactive
)
420 // prepare the dialog data
423 wxString
title(m_titleDialog
);
425 title
<< wxTheApp
->GetAppName() << _(": unknown charset");
429 msg
.Printf(_("The charset '%s' is unknown. You may select\n"
430 "another charset to replace it with or choose\n"
431 "[Cancel] if it cannot be replaced"), charset
.c_str());
433 // the list of choices
434 size_t count
= WXSIZEOF(gs_encodingDescs
);
436 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
437 wxT("inconsitency detected - forgot to update one of "
440 wxString
*encodingNamesTranslated
= new wxString
[count
];
442 for ( size_t i
= 0; i
< count
; i
++ )
444 encodingNamesTranslated
[i
] = wxGetTranslation(gs_encodingDescs
[i
]);
448 wxWindow
*parent
= m_windowParent
;
450 parent
= wxTheApp
->GetTopWindow();
452 // do ask the user and get back the index in encodings table
453 int n
= wxGetSingleChoiceIndex(msg
, title
,
455 encodingNamesTranslated
,
458 delete [] encodingNamesTranslated
;
462 // TODO save the result in the config!
464 encoding
= gs_encodings
[n
];
472 // ----------------------------------------------------------------------------
473 // support for unknown encodings: we maintain a map between the
474 // (platform-specific) strings identifying them and our wxFontEncodings they
475 // correspond to which is used by GetFontForEncoding() function
476 // ----------------------------------------------------------------------------
478 bool wxFontMapper::TestAltEncoding(const wxString
& configEntry
,
479 wxFontEncoding encReplacement
,
480 wxNativeEncodingInfo
*info
)
482 if ( wxGetNativeFontEncoding(encReplacement
, info
) &&
483 wxTestFontEncoding(*info
) )
485 // remember the mapping in the config
486 wxFontMapperPathChanger
path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH
);
490 GetConfig()->Write(configEntry
, info
->ToString());
499 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
500 wxNativeEncodingInfo
*info
,
501 const wxString
& facename
,
504 wxCHECK_MSG( info
, FALSE
, wxT("bad pointer in GetAltForEncoding") );
506 info
->facename
= facename
;
508 if ( encoding
== wxFONTENCODING_DEFAULT
)
510 encoding
= wxFont::GetDefaultEncoding();
513 // if we failed to load the system default encoding, something is really
514 // wrong and we'd better stop now - otherwise we will go into endless
515 // recursion trying to create the font in the msg box with the error
517 if ( encoding
== wxFONTENCODING_SYSTEM
)
519 wxFatalError(_("can't load any font, aborting"));
521 // wxFatalError doesn't return
524 wxString configEntry
= facename
+ _T("_") + GetEncodingName(encoding
);
526 // do we have a font spec for this encoding?
528 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
530 wxConfigBase
*config
= GetConfig();
532 wxString fontinfo
= config
->Read(configEntry
);
534 RestorePath(pathOld
);
538 if ( info
->FromString(fontinfo
) )
540 if ( wxTestFontEncoding(*info
) )
545 //else: no such fonts, look for something else
549 wxLogDebug(wxT("corrupted config data: string '%s' is not "
550 "a valid font encoding info"), fontinfo
.c_str());
558 wxString
title(m_titleDialog
);
560 title
<< wxTheApp
->GetAppName() << _(": unknown encoding");
564 msg
.Printf(_("The encoding '%s' is unknown.\n"
565 "Would you like to select a font to be used for this "
567 "(otherwise the text in this encoding will not be "
568 "shown correctly)?"),
569 GetEncodingDescription(encoding
).c_str());
571 wxWindow
*parent
= m_windowParent
;
573 parent
= wxTheApp
->GetTopWindow();
575 if ( wxMessageBox(msg
, title
,
576 wxICON_QUESTION
| wxYES_NO
, parent
) == wxYES
)
579 data
.SetEncoding(encoding
);
580 data
.EncodingInfo() = *info
;
581 wxFontDialog
dialog(parent
, &data
);
582 if ( dialog
.ShowModal() == wxID_OK
)
584 wxFontData retData
= dialog
.GetFontData();
585 wxFont font
= retData
.GetChosenFont();
587 *info
= retData
.EncodingInfo();
588 info
-> encoding
= retData
.GetEncoding();
590 // remember this in the config
591 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
593 GetConfig()->Write(configEntry
, info
->ToString());
595 RestorePath(pathOld
);
600 //else: the user canceled the font selection dialog
602 //else: the user doesn't want to select a font
604 //else: we're in non-interactive mode
607 // now try the default mappings:
608 wxFontEncodingArray equiv
= wxEncodingConverter::GetAllEquivalents(encoding
);
609 for ( unsigned i
= (equiv
[0] == encoding
) ? 1 : 0; i
< equiv
.GetCount(); i
++ )
610 if ( TestAltEncoding(configEntry
, equiv
[i
], info
) )
618 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
619 wxFontEncoding
*alt_encoding
,
620 const wxString
& facename
,
623 wxNativeEncodingInfo info
;
624 bool r
= GetAltForEncoding(encoding
, &info
, facename
, interactive
);
625 *alt_encoding
= info
.encoding
;
631 bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding
,
632 const wxString
& facename
)
634 wxNativeEncodingInfo info
;
636 if (wxGetNativeFontEncoding(encoding
, &info
))
638 info
.facename
= facename
;
639 return wxTestFontEncoding(info
);