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"
39 #include "wx/memconf.h"
41 #include "wx/msgdlg.h"
42 #include "wx/fontdlg.h"
43 #include "wx/choicdlg.h"
44 #include "wx/encconv.h"
46 // ----------------------------------------------------------------------------
48 // ----------------------------------------------------------------------------
50 // the config paths we use
51 static const wxChar
* FONTMAPPER_ROOT_PATH
= wxT("wxWindows/FontMapper");
52 static const wxChar
* FONTMAPPER_CHARSET_PATH
= wxT("Charsets");
53 static const wxChar
* FONTMAPPER_CHARSET_ALIAS_PATH
= wxT("Aliases");
54 static const wxChar
* FONTMAPPER_FONT_FROM_ENCODING_PATH
= wxT("Encodings");
56 // encodings supported by GetEncodingDescription
57 static wxFontEncoding gs_encodings
[] =
59 wxFONTENCODING_ISO8859_1
,
60 wxFONTENCODING_ISO8859_2
,
61 wxFONTENCODING_ISO8859_3
,
62 wxFONTENCODING_ISO8859_4
,
63 wxFONTENCODING_ISO8859_5
,
64 wxFONTENCODING_ISO8859_6
,
65 wxFONTENCODING_ISO8859_7
,
66 wxFONTENCODING_ISO8859_8
,
67 wxFONTENCODING_ISO8859_9
,
68 wxFONTENCODING_ISO8859_10
,
69 wxFONTENCODING_ISO8859_11
,
70 wxFONTENCODING_ISO8859_12
,
71 wxFONTENCODING_ISO8859_13
,
72 wxFONTENCODING_ISO8859_14
,
73 wxFONTENCODING_ISO8859_15
,
75 wxFONTENCODING_CP1250
,
76 wxFONTENCODING_CP1251
,
77 wxFONTENCODING_CP1252
,
78 wxFONTENCODING_CP1253
,
79 wxFONTENCODING_CP1254
,
80 wxFONTENCODING_CP1255
,
81 wxFONTENCODING_CP1256
,
82 wxFONTENCODING_CP1257
,
85 // the descriptions for them
86 static const wxChar
* gs_encodingDescs
[] =
88 wxTRANSLATE( "West European (ISO-8859-1/Latin 1)" ),
89 wxTRANSLATE( "Central European (ISO-8859-2/Latin 2)" ),
90 wxTRANSLATE( "Esperanto (ISO-8859-3)" ),
91 wxTRANSLATE( "Baltic (ISO-8859-4)" ),
92 wxTRANSLATE( "Cyrillic (Latin 5)" ),
93 wxTRANSLATE( "Arabic (ISO-8859-6)" ),
94 wxTRANSLATE( "Greek (ISO-8859-7)" ),
95 wxTRANSLATE( "Hebrew (ISO-8859-8)" ),
96 wxTRANSLATE( "Turkish (ISO-8859-9)" ),
97 wxTRANSLATE( "Baltic II (ISO-8859-10)" ),
98 wxTRANSLATE( "Thai (ISO-8859-11)" ),
99 wxTRANSLATE( "ISO-8859-12" ),
100 wxTRANSLATE( "ISO-8859-13" ),
101 wxTRANSLATE( "ISO-8859-14" ),
102 wxTRANSLATE( "West European new (ISO-8859-15/Latin 0)" ),
103 wxTRANSLATE( "KOI8-R" ),
104 wxTRANSLATE( "Windows Latin 2 (CP 1250)" ),
105 wxTRANSLATE( "Windows Cyrillic (CP 1251)" ),
106 wxTRANSLATE( "Windows Latin 1 (CP 1252)" ),
107 wxTRANSLATE( "Windows Greek (CP 1253)" ),
108 wxTRANSLATE( "Windows Turkish (CP 1254)" ),
109 wxTRANSLATE( "Windows Hebrew (CP 1255)" ),
110 wxTRANSLATE( "Windows Arabic (CP 1256)" ),
111 wxTRANSLATE( "Windows Baltic (CP 1257)" ),
114 // and the internal names
115 static const wxChar
* gs_encodingNames
[] =
133 wxT( "windows1250" ),
134 wxT( "windows1251" ),
135 wxT( "windows1252" ),
136 wxT( "windows1253" ),
137 wxT( "windows1254" ),
138 wxT( "windows1255" ),
139 wxT( "windows1256" ),
140 wxT( "windows1257" ),
143 // ----------------------------------------------------------------------------
145 // ----------------------------------------------------------------------------
148 static wxFontMapper gs_fontMapper
;
150 // and public pointer
151 wxFontMapper
* wxTheFontMapper
= &gs_fontMapper
;
153 // ----------------------------------------------------------------------------
155 // ----------------------------------------------------------------------------
157 // change the config path during the lifetime of this object
158 class wxFontMapperPathChanger
161 wxFontMapperPathChanger(wxFontMapper
*fontMapper
, const wxString
& path
)
163 m_fontMapper
= fontMapper
;
164 m_ok
= m_fontMapper
->ChangePath(path
, &m_pathOld
);
167 bool IsOk() const { return m_ok
; }
169 ~wxFontMapperPathChanger()
172 m_fontMapper
->RestorePath(m_pathOld
);
176 wxFontMapper
*m_fontMapper
;
181 // ============================================================================
183 // ============================================================================
185 // ----------------------------------------------------------------------------
187 // ----------------------------------------------------------------------------
189 wxFontMapper::wxFontMapper()
192 m_windowParent
= NULL
;
195 wxFontMapper::~wxFontMapper()
199 // ----------------------------------------------------------------------------
201 // ----------------------------------------------------------------------------
203 /* static */ const wxChar
*wxFontMapper::GetDefaultConfigPath()
205 return FONTMAPPER_ROOT_PATH
;
208 void wxFontMapper::SetConfigPath(const wxString
& prefix
)
210 wxCHECK_RET( !prefix
.IsEmpty() && prefix
[0] == wxCONFIG_PATH_SEPARATOR
,
211 wxT("an absolute path should be given to "
212 "wxFontMapper::SetConfigPath()") );
214 m_configRootPath
= prefix
;
218 // ----------------------------------------------------------------------------
219 // get config object and path for it
220 // ----------------------------------------------------------------------------
222 wxConfigBase
*wxFontMapper::GetConfig()
227 m_config
= wxConfig::Get(FALSE
/*don't create on demand*/ );
231 // we still want to have a config object because otherwise we would
232 // keep asking the user the same questions in the interactive mode,
233 // so create a dummy config which won't write to any files/registry
234 // but will allow us to remember the results of the questions at
235 // least during this run
236 m_config
= new wxMemoryConfig
;
237 wxConfig::Set(m_config
);
244 const wxString
& wxFontMapper::GetConfigPath()
246 if ( !m_configRootPath
)
249 m_configRootPath
= GetDefaultConfigPath();
252 return m_configRootPath
;
255 bool wxFontMapper::ChangePath(const wxString
& pathNew
, wxString
*pathOld
)
257 wxConfigBase
*config
= GetConfig();
261 *pathOld
= config
->GetPath();
263 wxString path
= GetConfigPath();
264 if ( path
.IsEmpty() || path
.Last() != wxCONFIG_PATH_SEPARATOR
)
266 path
+= wxCONFIG_PATH_SEPARATOR
;
269 wxASSERT_MSG( !pathNew
|| (pathNew
[0] != wxCONFIG_PATH_SEPARATOR
),
270 wxT("should be a relative path") );
274 config
->SetPath(path
);
279 void wxFontMapper::RestorePath(const wxString
& pathOld
)
281 GetConfig()->SetPath(pathOld
);
284 // ----------------------------------------------------------------------------
285 // charset/encoding correspondence
286 // ----------------------------------------------------------------------------
289 wxString
wxFontMapper::GetEncodingDescription(wxFontEncoding encoding
)
291 size_t count
= WXSIZEOF(gs_encodingDescs
);
293 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
294 wxT("inconsitency detected - forgot to update one of "
297 for ( size_t i
= 0; i
< count
; i
++ )
299 if ( gs_encodings
[i
] == encoding
)
301 return wxGetTranslation(gs_encodingDescs
[i
]);
306 str
.Printf(_("Unknown encoding (%d)"), encoding
);
312 wxString
wxFontMapper::GetEncodingName(wxFontEncoding encoding
)
314 size_t count
= WXSIZEOF(gs_encodingNames
);
316 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
317 wxT("inconsitency detected - forgot to update one of "
320 for ( size_t i
= 0; i
< count
; i
++ )
322 if ( gs_encodings
[i
] == encoding
)
324 return wxGetTranslation(gs_encodingNames
[i
]);
329 str
.Printf(_("unknown-%d"), encoding
);
334 wxFontEncoding
wxFontMapper::CharsetToEncoding(const wxString
& charset
,
337 wxFontEncoding encoding
= wxFONTENCODING_SYSTEM
;
339 // we're going to modify it, make a copy
340 wxString cs
= charset
;
342 // first try the user-defined settings
344 if ( ChangePath(FONTMAPPER_CHARSET_PATH
, &pathOld
) )
346 wxConfigBase
*config
= GetConfig();
348 // do we have an encoding for this charset?
349 long value
= config
->Read(charset
, -1l);
352 if ( value
>= 0 && value
<= wxFONTENCODING_MAX
)
354 encoding
= (wxFontEncoding
)value
;
358 wxLogDebug(wxT("corrupted config data: invalid encoding %ld "
359 "for charset '%s' ignored"),
360 value
, charset
.c_str());
364 if ( encoding
== wxFONTENCODING_SYSTEM
)
366 // may be we have an alias?
367 config
->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH
);
369 wxString alias
= config
->Read(charset
);
372 // yes, we do - use it instead
377 RestorePath(pathOld
);
380 // if didn't find it there, try to reckognise it ourselves
381 if ( encoding
== wxFONTENCODING_SYSTEM
)
385 if ( !cs
|| cs
== wxT("US-ASCII") )
386 encoding
= wxFONTENCODING_DEFAULT
;
387 else if ( cs
== wxT("KOI8-R") || cs
== wxT("KOI8-U") )
388 encoding
= wxFONTENCODING_KOI8
;
389 else if ( cs
.Left(3) == wxT("ISO") )
391 // the dash is optional (or, to be exact, it is not, but
392 // several brokenmails "forget" it)
393 const wxChar
*p
= cs
.c_str() + 3;
394 if ( *p
== wxT('-') )
398 if ( wxSscanf(p
, wxT("8859-%u"), &value
) == 1 )
400 if ( value
< wxFONTENCODING_ISO8859_MAX
-
401 wxFONTENCODING_ISO8859_1
)
403 // it's a valid ISO8859 encoding
404 value
+= wxFONTENCODING_ISO8859_1
- 1;
405 encoding
= (wxFontEncoding
)value
;
409 else if ( cs
.Left(8) == wxT("WINDOWS-") )
412 if ( wxSscanf(cs
.c_str() + 8, wxT("%u"), &value
) == 1 )
417 if ( value
< wxFONTENCODING_CP12_MAX
-
418 wxFONTENCODING_CP1250
- 1 )
420 // a valid Windows code page
421 value
+= wxFONTENCODING_CP1250
;
422 encoding
= (wxFontEncoding
)value
;
430 // if still no luck, ask the user - unless disabled
431 if ( (encoding
== wxFONTENCODING_SYSTEM
) && interactive
)
433 // prepare the dialog data
436 wxString
title(m_titleDialog
);
438 title
<< wxTheApp
->GetAppName() << _(": unknown charset");
442 msg
.Printf(_("The charset '%s' is unknown. You may select\n"
443 "another charset to replace it with or choose\n"
444 "[Cancel] if it cannot be replaced"), charset
.c_str());
446 // the list of choices
447 size_t count
= WXSIZEOF(gs_encodingDescs
);
449 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
450 wxT("inconsitency detected - forgot to update one of "
453 wxString
*encodingNamesTranslated
= new wxString
[count
];
455 for ( size_t i
= 0; i
< count
; i
++ )
457 encodingNamesTranslated
[i
] = wxGetTranslation(gs_encodingDescs
[i
]);
461 wxWindow
*parent
= m_windowParent
;
463 parent
= wxTheApp
->GetTopWindow();
465 // do ask the user and get back the index in encodings table
466 int n
= wxGetSingleChoiceIndex(msg
, title
,
468 encodingNamesTranslated
,
471 delete [] encodingNamesTranslated
;
475 encoding
= gs_encodings
[n
];
477 // save the result in the config now
478 if ( ChangePath(FONTMAPPER_CHARSET_PATH
, &pathOld
) )
480 wxConfigBase
*config
= GetConfig();
482 // remember the alt encoding for this charset
483 if ( !config
->Write(charset
, (long)encoding
) )
485 wxLogError(_("Failed to remember the encoding "
486 "for the charset '%s'."), charset
.c_str());
489 RestorePath(pathOld
);
498 // ----------------------------------------------------------------------------
499 // support for unknown encodings: we maintain a map between the
500 // (platform-specific) strings identifying them and our wxFontEncodings they
501 // correspond to which is used by GetFontForEncoding() function
502 // ----------------------------------------------------------------------------
504 bool wxFontMapper::TestAltEncoding(const wxString
& configEntry
,
505 wxFontEncoding encReplacement
,
506 wxNativeEncodingInfo
*info
)
508 if ( wxGetNativeFontEncoding(encReplacement
, info
) &&
509 wxTestFontEncoding(*info
) )
511 // remember the mapping in the config
512 wxFontMapperPathChanger
path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH
);
516 GetConfig()->Write(configEntry
, info
->ToString());
525 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
526 wxNativeEncodingInfo
*info
,
527 const wxString
& facename
,
530 wxCHECK_MSG( info
, FALSE
, wxT("bad pointer in GetAltForEncoding") );
532 info
->facename
= facename
;
534 if ( encoding
== wxFONTENCODING_DEFAULT
)
536 encoding
= wxFont::GetDefaultEncoding();
539 // if we failed to load the system default encoding, something is really
540 // wrong and we'd better stop now - otherwise we will go into endless
541 // recursion trying to create the font in the msg box with the error
543 if ( encoding
== wxFONTENCODING_SYSTEM
)
545 wxFatalError(_("can't load any font, aborting"));
547 // wxFatalError doesn't return
550 wxString configEntry
, encName
= GetEncodingName(encoding
);
553 configEntry
= facename
+ _T("_");
555 configEntry
+= encName
;
557 // do we have a font spec for this encoding?
559 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
561 wxConfigBase
*config
= GetConfig();
563 wxString fontinfo
= config
->Read(configEntry
);
565 RestorePath(pathOld
);
567 if ( !!fontinfo
&& !!facename
)
569 // we tried to find a match with facename - now try without it
570 fontinfo
= config
->Read(encName
);
575 if ( info
->FromString(fontinfo
) )
577 if ( wxTestFontEncoding(*info
) )
582 //else: no such fonts, look for something else
586 wxLogDebug(wxT("corrupted config data: string '%s' is not "
587 "a valid font encoding info"), fontinfo
.c_str());
590 //else: there is no information in config about this encoding
596 wxString
title(m_titleDialog
);
598 title
<< wxTheApp
->GetAppName() << _(": unknown encoding");
602 msg
.Printf(_("The encoding '%s' is unknown.\n"
603 "Would you like to select a font to be used for this "
605 "(otherwise the text in this encoding will not be "
606 "shown correctly)?"),
607 GetEncodingDescription(encoding
).c_str());
609 wxWindow
*parent
= m_windowParent
;
611 parent
= wxTheApp
->GetTopWindow();
613 if ( wxMessageBox(msg
, title
,
614 wxICON_QUESTION
| wxYES_NO
, parent
) == wxYES
)
617 data
.SetEncoding(encoding
);
618 data
.EncodingInfo() = *info
;
619 wxFontDialog
dialog(parent
, &data
);
620 if ( dialog
.ShowModal() == wxID_OK
)
622 wxFontData retData
= dialog
.GetFontData();
623 wxFont font
= retData
.GetChosenFont();
625 *info
= retData
.EncodingInfo();
626 info
-> encoding
= retData
.GetEncoding();
628 // remember this in the config
629 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
631 GetConfig()->Write(configEntry
, info
->ToString());
633 RestorePath(pathOld
);
638 //else: the user canceled the font selection dialog
640 //else: the user doesn't want to select a font
642 //else: we're in non-interactive mode
645 // now try the default mappings:
646 wxFontEncodingArray equiv
= wxEncodingConverter::GetAllEquivalents(encoding
);
647 size_t count
= equiv
.GetCount();
648 for ( size_t i
= (equiv
[0] == encoding
) ? 1 : 0; i
< count
; i
++ )
650 if ( TestAltEncoding(configEntry
, equiv
[i
], info
) )
659 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
660 wxFontEncoding
*alt_encoding
,
661 const wxString
& facename
,
664 wxNativeEncodingInfo info
;
665 bool r
= GetAltForEncoding(encoding
, &info
, facename
, interactive
);
666 *alt_encoding
= info
.encoding
;
672 bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding
,
673 const wxString
& facename
)
675 wxNativeEncodingInfo info
;
677 if (wxGetNativeFontEncoding(encoding
, &info
))
679 info
.facename
= facename
;
680 return wxTestFontEncoding(info
);