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"
44 // ----------------------------------------------------------------------------
46 // ----------------------------------------------------------------------------
48 // the config paths we use
49 static const char* FONTMAPPER_ROOT_PATH
= _T("FontMapper");
50 static const char* FONTMAPPER_CHARSET_PATH
= _T("Charsets");
51 static const char* FONTMAPPER_CHARSET_ALIAS_PATH
= _T("Aliases");
52 static const char* FONTMAPPER_FONT_FROM_ENCODING_PATH
= _T("Encodings");
54 // encodings supported by GetEncodingDescription
55 static wxFontEncoding gs_encodings
[] =
57 wxFONTENCODING_ISO8859_1
,
58 wxFONTENCODING_ISO8859_2
,
59 wxFONTENCODING_ISO8859_3
,
60 wxFONTENCODING_ISO8859_4
,
61 wxFONTENCODING_ISO8859_5
,
62 wxFONTENCODING_ISO8859_6
,
63 wxFONTENCODING_ISO8859_7
,
64 wxFONTENCODING_ISO8859_8
,
65 wxFONTENCODING_ISO8859_9
,
66 wxFONTENCODING_ISO8859_10
,
67 wxFONTENCODING_ISO8859_11
,
68 wxFONTENCODING_ISO8859_12
,
69 wxFONTENCODING_ISO8859_13
,
70 wxFONTENCODING_ISO8859_14
,
71 wxFONTENCODING_ISO8859_15
,
73 wxFONTENCODING_CP1250
,
74 wxFONTENCODING_CP1251
,
75 wxFONTENCODING_CP1252
,
76 wxFONTENCODING_CP1253
,
77 wxFONTENCODING_CP1254
,
78 wxFONTENCODING_CP1255
,
79 wxFONTENCODING_CP1256
,
80 wxFONTENCODING_CP1257
,
83 // the descriptions for them
84 static const wxChar
* gs_encodingDescs
[] =
86 wxTRANSLATE( "West European (ISO-8859-1/Latin 1)" ),
87 wxTRANSLATE( "Central European (ISO-8859-2/Latin 2)" ),
88 wxTRANSLATE( "Esperanto (ISO-8859-3)" ),
89 wxTRANSLATE( "Baltic (ISO-8859-4)" ),
90 wxTRANSLATE( "Cyrillic (Latin 5)" ),
91 wxTRANSLATE( "Arabic (ISO-8859-6)" ),
92 wxTRANSLATE( "Greek (ISO-8859-7)" ),
93 wxTRANSLATE( "Hebrew (ISO-8859-8)" ),
94 wxTRANSLATE( "Turkish (ISO-8859-9)" ),
95 wxTRANSLATE( "Baltic II (ISO-8859-10)" ),
96 wxTRANSLATE( "Thai (ISO-8859-11)" ),
97 wxTRANSLATE( "ISO-8859-12" ),
98 wxTRANSLATE( "ISO-8859-13" ),
99 wxTRANSLATE( "ISO-8859-14" ),
100 wxTRANSLATE( "West European new (ISO-8859-15/Latin 0)" ),
101 wxTRANSLATE( "KOI8-R" ),
102 wxTRANSLATE( "Windows Latin 2 (CP 1250)" ),
103 wxTRANSLATE( "Windows Cyrillic (CP 1251)" ),
104 wxTRANSLATE( "Windows Latin 1 (CP 1252)" ),
105 wxTRANSLATE( "Windows Greek (CP 1253)" ),
106 wxTRANSLATE( "Windows Turkish (CP 1254)" ),
107 wxTRANSLATE( "Windows Hebrew (CP 1255)" ),
108 wxTRANSLATE( "Windows Arabic (CP 1256)" ),
109 wxTRANSLATE( "Windows Baltic (CP 1257)" ),
112 // and the internal names
113 static const wxChar
* gs_encodingNames
[] =
141 // ----------------------------------------------------------------------------
143 // ----------------------------------------------------------------------------
146 static wxFontMapper gs_fontMapper
;
148 // and public pointer
149 wxFontMapper
* WXDLLEXPORT wxTheFontMapper
= &gs_fontMapper
;
151 // ----------------------------------------------------------------------------
153 // ----------------------------------------------------------------------------
155 // change the config path during the lifetime of this object
156 class wxFontMapperPathChanger
159 wxFontMapperPathChanger(wxFontMapper
*fontMapper
, const wxString
& path
)
161 m_fontMapper
= fontMapper
;
162 m_ok
= m_fontMapper
->ChangePath(path
, &m_pathOld
);
165 bool IsOk() const { return m_ok
; }
167 ~wxFontMapperPathChanger()
170 m_fontMapper
->RestorePath(m_pathOld
);
174 wxFontMapper
*m_fontMapper
;
179 // ============================================================================
181 // ============================================================================
183 // ----------------------------------------------------------------------------
185 // ----------------------------------------------------------------------------
187 wxFontMapper::wxFontMapper()
190 m_windowParent
= NULL
;
193 wxFontMapper::~wxFontMapper()
197 // ----------------------------------------------------------------------------
199 // ----------------------------------------------------------------------------
201 /* static */ const wxChar
*wxFontMapper::GetDefaultConfigPath()
203 return FONTMAPPER_ROOT_PATH
;
206 void wxFontMapper::SetConfigPath(const wxString
& prefix
)
208 wxCHECK_RET( !prefix
.IsEmpty() && prefix
[0] == wxCONFIG_PATH_SEPARATOR
,
209 _T("an absolute path should be given to "
210 "wxFontMapper::SetConfigPath()") );
212 m_configRootPath
= prefix
;
216 // ----------------------------------------------------------------------------
217 // get config object and path for it
218 // ----------------------------------------------------------------------------
220 wxConfigBase
*wxFontMapper::GetConfig()
225 m_config
= wxConfig::Get();
231 const wxString
& wxFontMapper::GetConfigPath()
233 if ( !m_configRootPath
)
236 m_configRootPath
= GetDefaultConfigPath();
239 return m_configRootPath
;
242 bool wxFontMapper::ChangePath(const wxString
& pathNew
, wxString
*pathOld
)
244 wxConfigBase
*config
= GetConfig();
248 *pathOld
= config
->GetPath();
250 wxString path
= GetConfigPath();
251 if ( path
.IsEmpty() || path
.Last() != wxCONFIG_PATH_SEPARATOR
)
253 path
+= wxCONFIG_PATH_SEPARATOR
;
256 wxASSERT_MSG( !pathNew
|| (pathNew
[0] != wxCONFIG_PATH_SEPARATOR
),
257 _T("should be a relative path") );
261 config
->SetPath(path
);
266 void wxFontMapper::RestorePath(const wxString
& pathOld
)
268 GetConfig()->SetPath(pathOld
);
271 // ----------------------------------------------------------------------------
272 // charset/encoding correspondence
273 // ----------------------------------------------------------------------------
276 wxString
wxFontMapper::GetEncodingDescription(wxFontEncoding encoding
)
278 size_t count
= WXSIZEOF(gs_encodingDescs
);
280 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
281 _T("inconsitency detected - forgot to update one of "
284 for ( size_t i
= 0; i
< count
; i
++ )
286 if ( gs_encodings
[i
] == encoding
)
288 return wxGetTranslation(gs_encodingDescs
[i
]);
293 str
.Printf(_("Unknown encoding (%d)"), encoding
);
299 wxString
wxFontMapper::GetEncodingName(wxFontEncoding encoding
)
301 size_t count
= WXSIZEOF(gs_encodingNames
);
303 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
304 _T("inconsitency detected - forgot to update one of "
307 for ( size_t i
= 0; i
< count
; i
++ )
309 if ( gs_encodings
[i
] == encoding
)
311 return wxGetTranslation(gs_encodingNames
[i
]);
316 str
.Printf(_("unknown-%d"), encoding
);
321 wxFontEncoding
wxFontMapper::CharsetToEncoding(const wxString
& charset
,
324 wxFontEncoding encoding
= wxFONTENCODING_SYSTEM
;
326 // we're going to modify it, make a copy
327 wxString cs
= charset
;
329 // first try the user-defined settings
331 if ( ChangePath(FONTMAPPER_CHARSET_PATH
, &pathOld
) )
333 wxConfigBase
*config
= GetConfig();
335 // do we have an encoding for this charset?
336 long value
= config
->Read(charset
, -1l);
339 if ( value
>= 0 && value
<= wxFONTENCODING_MAX
)
341 encoding
= (wxFontEncoding
)value
;
345 wxLogDebug(_T("corrupted config data - invalid encoding %ld "
346 "for charset '%s'"), value
, charset
.c_str());
350 if ( encoding
== wxFONTENCODING_SYSTEM
)
352 // may be we have an alias?
353 config
->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH
);
355 wxString alias
= config
->Read(charset
);
358 // yes, we do - use it instead
363 RestorePath(pathOld
);
366 // if didn't find it there, try to reckognise it ourselves
367 if ( encoding
== wxFONTENCODING_SYSTEM
)
371 if ( !cs
|| cs
== _T("US-ASCII") )
372 encoding
= wxFONTENCODING_DEFAULT
;
373 else if ( cs
== _T("KOI8-R") || cs
== _T("KOI8-U") )
374 encoding
= wxFONTENCODING_KOI8
;
375 else if ( cs
.Left(3) == _T("ISO") )
377 // the dash is optional (or, to be exact, it is not, but
378 // several brokenmails "forget" it)
379 const wxChar
*p
= cs
.c_str() + 3;
384 if ( wxSscanf(p
, _T("8859-%u"), &value
) == 1 )
386 if ( value
< wxFONTENCODING_ISO8859_MAX
-
387 wxFONTENCODING_ISO8859_1
)
389 // it's a valid ISO8859 encoding
390 value
+= wxFONTENCODING_ISO8859_1
- 1;
391 encoding
= (wxFontEncoding
)value
;
395 else if ( cs
.Left(8) == _T("WINDOWS-") )
398 if ( wxSscanf(cs
.c_str() + 8, "%u", &value
) == 1 )
403 if ( value
< wxFONTENCODING_CP12_MAX
-
404 wxFONTENCODING_CP1250
- 1 )
406 // a valid Windows code page
407 value
+= wxFONTENCODING_CP1250
;
408 encoding
= (wxFontEncoding
)value
;
416 // if still no luck, ask the user - unless disabled
417 if ( (encoding
== wxFONTENCODING_SYSTEM
) && interactive
)
419 // prepare the dialog data
422 wxString
title(m_titleDialog
);
424 title
<< wxTheApp
->GetAppName() << _(": unknown charset");
428 msg
.Printf(_("The charset '%s' is unknown. You may select another "
429 "charset to replace it with or choose [Cancel] if it "
430 "cannot be replaced"), charset
.c_str());
432 // the list of choices
433 size_t count
= WXSIZEOF(gs_encodingDescs
);
435 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
436 _T("inconsitency detected - forgot to update one of "
439 wxString
*encodingNamesTranslated
= new wxString
[count
];
441 for ( size_t i
= 0; i
< count
; i
++ )
443 encodingNamesTranslated
[i
] = wxGetTranslation(gs_encodingDescs
[i
]);
447 wxWindow
*parent
= m_windowParent
;
449 parent
= wxTheApp
->GetTopWindow();
451 // do ask the user and get back the index in encodings table
452 int n
= wxGetSingleChoiceIndex(msg
, title
,
454 encodingNamesTranslated
,
457 delete [] encodingNamesTranslated
;
461 // TODO save the result in the config!
463 encoding
= gs_encodings
[n
];
471 // ----------------------------------------------------------------------------
472 // support for unknown encodings: we maintain a map between the
473 // (platform-specific) strings identifying them and our wxFontEncodings they
474 // correspond to which is used by GetFontForEncoding() function
475 // ----------------------------------------------------------------------------
477 bool wxFontMapper::TestAltEncoding(const wxString
& configEntry
,
478 wxFontEncoding encReplacement
,
479 wxNativeEncodingInfo
*info
)
481 if ( wxGetNativeFontEncoding(encReplacement
, info
) &&
482 wxTestFontEncoding(*info
) )
484 // remember the mapping in the config
485 wxFontMapperPathChanger
path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH
);
489 GetConfig()->Write(configEntry
, info
->ToString());
498 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
499 wxNativeEncodingInfo
*info
,
502 wxCHECK_MSG( info
, FALSE
, _T("bad pointer in GetAltForEncoding") );
504 if ( encoding
== wxFONTENCODING_DEFAULT
)
506 encoding
= wxFont::GetDefaultEncoding();
509 // if we failed to load the system default encoding, something is really
510 // wrong and we'd better stop now - otherwise we will go into endless
511 // recursion trying to create the font in the msg box with the error
513 if ( encoding
== wxFONTENCODING_SYSTEM
)
515 wxFatalError(_("can't load any font, aborting"));
517 // wxFatalError doesn't return
520 wxString configEntry
= GetEncodingName(encoding
);
522 // do we have a font spec for this encoding?
524 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
526 wxConfigBase
*config
= GetConfig();
528 wxString fontinfo
= config
->Read(configEntry
);
530 RestorePath(pathOld
);
534 if ( info
->FromString(fontinfo
) )
536 if ( wxTestFontEncoding(*info
) )
541 //else: no such fonts, look for something else
545 wxLogDebug(_T("corrupted config data: string '%s' is not "
546 "a valid font encoding info"), fontinfo
.c_str());
554 wxString
title(m_titleDialog
);
556 title
<< wxTheApp
->GetAppName() << _(": unknown encoding");
560 msg
.Printf(_("The encoding '%s' is unknown.\n"
561 "Would you like to select a font to be used for this "
563 "(otherwise the text in this encoding will not be "
564 "shown correctly)?"),
565 GetEncodingDescription(encoding
).c_str());
567 wxWindow
*parent
= m_windowParent
;
569 parent
= wxTheApp
->GetTopWindow();
571 if ( wxMessageBox(msg
, title
,
572 wxICON_QUESTION
| wxYES_NO
, parent
) == wxYES
)
575 data
.SetEncoding(encoding
);
576 data
.EncodingInfo() = *info
;
577 wxFontDialog
dialog(parent
, &data
);
578 if ( dialog
.ShowModal() == wxID_OK
)
580 wxFontData retData
= dialog
.GetFontData();
581 wxFont font
= retData
.GetChosenFont();
583 *info
= retData
.EncodingInfo();
585 // remember this in the config
586 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
588 GetConfig()->Write(configEntry
, info
->ToString());
590 RestorePath(pathOld
);
595 //else: the user canceled the font selection dialog
597 //else: the user doesn't want to select a font
599 //else: we're in non-interactive mode
601 // now try the default mappings
604 case wxFONTENCODING_ISO8859_15
:
605 // iso8859-15 is slightly modified iso8859-1
606 if ( TestAltEncoding(configEntry
, wxFONTENCODING_ISO8859_1
, info
) )
610 case wxFONTENCODING_ISO8859_1
:
611 // iso8859-1 is identical to CP1252
612 if ( TestAltEncoding(configEntry
, wxFONTENCODING_CP1252
, info
) )
617 case wxFONTENCODING_CP1252
:
618 if ( TestAltEncoding(configEntry
, wxFONTENCODING_ISO8859_1
, info
) )
623 // iso8859-13 is quite similar to WinBaltic
624 case wxFONTENCODING_ISO8859_13
:
625 if ( TestAltEncoding(configEntry
, wxFONTENCODING_CP1257
, info
) )
630 case wxFONTENCODING_CP1257
:
631 if ( TestAltEncoding(configEntry
, wxFONTENCODING_ISO8859_13
, info
) )
636 // iso8859-8 is almost identical to WinHebrew
637 case wxFONTENCODING_ISO8859_8
:
638 if ( TestAltEncoding(configEntry
, wxFONTENCODING_CP1255
, info
) )
643 case wxFONTENCODING_CP1255
:
644 if ( TestAltEncoding(configEntry
, wxFONTENCODING_ISO8859_8
, info
) )
649 // and iso8859-7 is not too different from WinGreek
650 case wxFONTENCODING_ISO8859_7
:
651 if ( TestAltEncoding(configEntry
, wxFONTENCODING_CP1253
, info
) )
656 case wxFONTENCODING_CP1253
:
657 if ( TestAltEncoding(configEntry
, wxFONTENCODING_ISO8859_7
, info
) )
663 // TODO add other mappings...