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 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*/ );
230 // we still want to have a config object because otherwise we would
231 // keep asking the user the same questions in the interactive mode,
232 // so create a dummy config which won't write to any files/registry
233 // but will allow us to remember the results of the questions at
234 // least during this run
235 m_config
= new wxMemoryConfig
;
236 wxConfig::Set(m_config
);
243 const wxString
& wxFontMapper::GetConfigPath()
245 if ( !m_configRootPath
)
248 m_configRootPath
= GetDefaultConfigPath();
251 return m_configRootPath
;
254 bool wxFontMapper::ChangePath(const wxString
& pathNew
, wxString
*pathOld
)
256 wxConfigBase
*config
= GetConfig();
260 *pathOld
= config
->GetPath();
262 wxString path
= GetConfigPath();
263 if ( path
.IsEmpty() || path
.Last() != wxCONFIG_PATH_SEPARATOR
)
265 path
+= wxCONFIG_PATH_SEPARATOR
;
268 wxASSERT_MSG( !pathNew
|| (pathNew
[0] != wxCONFIG_PATH_SEPARATOR
),
269 wxT("should be a relative path") );
273 config
->SetPath(path
);
278 void wxFontMapper::RestorePath(const wxString
& pathOld
)
280 GetConfig()->SetPath(pathOld
);
283 // ----------------------------------------------------------------------------
284 // charset/encoding correspondence
285 // ----------------------------------------------------------------------------
288 wxString
wxFontMapper::GetEncodingDescription(wxFontEncoding encoding
)
290 size_t count
= WXSIZEOF(gs_encodingDescs
);
292 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
293 wxT("inconsitency detected - forgot to update one of "
296 for ( size_t i
= 0; i
< count
; i
++ )
298 if ( gs_encodings
[i
] == encoding
)
300 return wxGetTranslation(gs_encodingDescs
[i
]);
305 str
.Printf(_("Unknown encoding (%d)"), encoding
);
311 wxString
wxFontMapper::GetEncodingName(wxFontEncoding encoding
)
313 size_t count
= WXSIZEOF(gs_encodingNames
);
315 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
316 wxT("inconsitency detected - forgot to update one of "
319 for ( size_t i
= 0; i
< count
; i
++ )
321 if ( gs_encodings
[i
] == encoding
)
323 return wxGetTranslation(gs_encodingNames
[i
]);
328 str
.Printf(_("unknown-%d"), encoding
);
333 wxFontEncoding
wxFontMapper::CharsetToEncoding(const wxString
& charset
,
336 wxFontEncoding encoding
= wxFONTENCODING_SYSTEM
;
338 // we're going to modify it, make a copy
339 wxString cs
= charset
;
341 // first try the user-defined settings
343 if ( ChangePath(FONTMAPPER_CHARSET_PATH
, &pathOld
) )
345 wxConfigBase
*config
= GetConfig();
347 // do we have an encoding for this charset?
348 long value
= config
->Read(charset
, -1l);
351 if ( value
>= 0 && value
<= wxFONTENCODING_MAX
)
353 encoding
= (wxFontEncoding
)value
;
357 wxLogDebug(wxT("corrupted config data: invalid encoding %ld "
358 "for charset '%s' ignored"),
359 value
, charset
.c_str());
363 if ( encoding
== wxFONTENCODING_SYSTEM
)
365 // may be we have an alias?
366 config
->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH
);
368 wxString alias
= config
->Read(charset
);
371 // yes, we do - use it instead
376 RestorePath(pathOld
);
379 // if didn't find it there, try to reckognise it ourselves
380 if ( encoding
== wxFONTENCODING_SYSTEM
)
384 if ( !cs
|| cs
== wxT("US-ASCII") )
385 encoding
= wxFONTENCODING_DEFAULT
;
386 else if ( cs
== wxT("KOI8-R") || cs
== wxT("KOI8-U") )
387 encoding
= wxFONTENCODING_KOI8
;
388 else if ( cs
.Left(3) == wxT("ISO") )
390 // the dash is optional (or, to be exact, it is not, but
391 // several brokenmails "forget" it)
392 const wxChar
*p
= cs
.c_str() + 3;
393 if ( *p
== wxT('-') )
397 if ( wxSscanf(p
, wxT("8859-%u"), &value
) == 1 )
399 if ( value
< wxFONTENCODING_ISO8859_MAX
-
400 wxFONTENCODING_ISO8859_1
)
402 // it's a valid ISO8859 encoding
403 value
+= wxFONTENCODING_ISO8859_1
- 1;
404 encoding
= (wxFontEncoding
)value
;
408 else if ( cs
.Left(8) == wxT("WINDOWS-") )
411 if ( wxSscanf(cs
.c_str() + 8, wxT("%u"), &value
) == 1 )
416 if ( value
< wxFONTENCODING_CP12_MAX
-
417 wxFONTENCODING_CP1250
- 1 )
419 // a valid Windows code page
420 value
+= wxFONTENCODING_CP1250
;
421 encoding
= (wxFontEncoding
)value
;
429 // if still no luck, ask the user - unless disabled
430 if ( (encoding
== wxFONTENCODING_SYSTEM
) && interactive
)
432 // prepare the dialog data
435 wxString
title(m_titleDialog
);
437 title
<< wxTheApp
->GetAppName() << _(": unknown charset");
441 msg
.Printf(_("The charset '%s' is unknown. You may select\n"
442 "another charset to replace it with or choose\n"
443 "[Cancel] if it cannot be replaced"), charset
.c_str());
445 // the list of choices
446 size_t count
= WXSIZEOF(gs_encodingDescs
);
448 wxASSERT_MSG( count
== WXSIZEOF(gs_encodings
),
449 wxT("inconsitency detected - forgot to update one of "
452 wxString
*encodingNamesTranslated
= new wxString
[count
];
454 for ( size_t i
= 0; i
< count
; i
++ )
456 encodingNamesTranslated
[i
] = wxGetTranslation(gs_encodingDescs
[i
]);
460 wxWindow
*parent
= m_windowParent
;
462 parent
= wxTheApp
->GetTopWindow();
464 // do ask the user and get back the index in encodings table
465 int n
= wxGetSingleChoiceIndex(msg
, title
,
467 encodingNamesTranslated
,
470 delete [] encodingNamesTranslated
;
474 encoding
= gs_encodings
[n
];
476 // save the result in the config now
477 if ( ChangePath(FONTMAPPER_CHARSET_PATH
, &pathOld
) )
479 wxConfigBase
*config
= GetConfig();
481 // remember the alt encoding for this charset
482 if ( !config
->Write(charset
, (long)encoding
) )
484 wxLogError(_("Failed to remember the encoding "
485 "for the charset '%s'."), charset
.c_str());
488 RestorePath(pathOld
);
497 // ----------------------------------------------------------------------------
498 // support for unknown encodings: we maintain a map between the
499 // (platform-specific) strings identifying them and our wxFontEncodings they
500 // correspond to which is used by GetFontForEncoding() function
501 // ----------------------------------------------------------------------------
503 bool wxFontMapper::TestAltEncoding(const wxString
& configEntry
,
504 wxFontEncoding encReplacement
,
505 wxNativeEncodingInfo
*info
)
507 if ( wxGetNativeFontEncoding(encReplacement
, info
) &&
508 wxTestFontEncoding(*info
) )
510 // remember the mapping in the config
511 wxFontMapperPathChanger
path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH
);
515 GetConfig()->Write(configEntry
, info
->ToString());
524 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
525 wxNativeEncodingInfo
*info
,
526 const wxString
& facename
,
529 wxCHECK_MSG( info
, FALSE
, wxT("bad pointer in GetAltForEncoding") );
531 info
->facename
= facename
;
533 if ( encoding
== wxFONTENCODING_DEFAULT
)
535 encoding
= wxFont::GetDefaultEncoding();
538 // if we failed to load the system default encoding, something is really
539 // wrong and we'd better stop now - otherwise we will go into endless
540 // recursion trying to create the font in the msg box with the error
542 if ( encoding
== wxFONTENCODING_SYSTEM
)
544 wxFatalError(_("can't load any font, aborting"));
546 // wxFatalError doesn't return
549 wxString configEntry
, encName
= GetEncodingName(encoding
);
552 configEntry
= facename
+ _T("_");
554 configEntry
+= encName
;
556 // do we have a font spec for this encoding?
558 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
560 wxConfigBase
*config
= GetConfig();
562 wxString fontinfo
= config
->Read(configEntry
);
564 RestorePath(pathOld
);
566 if ( !!fontinfo
&& !!facename
)
568 // we tried to find a match with facename - now try without it
569 fontinfo
= config
->Read(encName
);
574 if ( info
->FromString(fontinfo
) )
576 if ( wxTestFontEncoding(*info
) )
581 //else: no such fonts, look for something else
585 wxLogDebug(wxT("corrupted config data: string '%s' is not "
586 "a valid font encoding info"), fontinfo
.c_str());
589 //else: there is no information in config about this encoding
595 wxString
title(m_titleDialog
);
597 title
<< wxTheApp
->GetAppName() << _(": unknown encoding");
601 msg
.Printf(_("The encoding '%s' is unknown.\n"
602 "Would you like to select a font to be used for this "
604 "(otherwise the text in this encoding will not be "
605 "shown correctly)?"),
606 GetEncodingDescription(encoding
).c_str());
608 wxWindow
*parent
= m_windowParent
;
610 parent
= wxTheApp
->GetTopWindow();
612 if ( wxMessageBox(msg
, title
,
613 wxICON_QUESTION
| wxYES_NO
, parent
) == wxYES
)
616 data
.SetEncoding(encoding
);
617 data
.EncodingInfo() = *info
;
618 wxFontDialog
dialog(parent
, &data
);
619 if ( dialog
.ShowModal() == wxID_OK
)
621 wxFontData retData
= dialog
.GetFontData();
622 wxFont font
= retData
.GetChosenFont();
624 *info
= retData
.EncodingInfo();
625 info
-> encoding
= retData
.GetEncoding();
627 // remember this in the config
628 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH
, &pathOld
) )
630 GetConfig()->Write(configEntry
, info
->ToString());
632 RestorePath(pathOld
);
637 //else: the user canceled the font selection dialog
639 //else: the user doesn't want to select a font
641 //else: we're in non-interactive mode
644 // now try the default mappings:
645 wxFontEncodingArray equiv
= wxEncodingConverter::GetAllEquivalents(encoding
);
646 size_t count
= equiv
.GetCount();
647 for ( size_t i
= (equiv
[0] == encoding
) ? 1 : 0; i
< count
; i
++ )
649 if ( TestAltEncoding(configEntry
, equiv
[i
], info
) )
658 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
659 wxFontEncoding
*alt_encoding
,
660 const wxString
& facename
,
663 wxNativeEncodingInfo info
;
664 bool r
= GetAltForEncoding(encoding
, &info
, facename
, interactive
);
665 *alt_encoding
= info
.encoding
;
671 bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding
,
672 const wxString
& facename
)
674 wxNativeEncodingInfo info
;
676 if (wxGetNativeFontEncoding(encoding
, &info
))
678 info
.facename
= facename
;
679 return wxTestFontEncoding(info
);