]> git.saurik.com Git - wxWidgets.git/blame - src/common/fontmap.cpp
Added return NULL; for __WXCOCOA__
[wxWidgets.git] / src / common / fontmap.cpp
CommitLineData
3c1866e8
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: common/fontmap.cpp
3// Purpose: wxFontMapper class
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 04.11.99
7// RCS-ID: $Id$
8// Copyright: (c) Vadim Zeitlin
55d99c7a 9// Licence: wxWindows licence
3c1866e8
VZ
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation "fontmap.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
1e6feb95
VZ
31#if wxUSE_FONTMAP
32
3c1866e8
VZ
33#ifndef WX_PRECOMP
34 #include "wx/app.h"
35 #include "wx/log.h"
36 #include "wx/intl.h"
37#endif // PCH
38
65e50848 39#include "wx/module.h"
3c1866e8 40#include "wx/fontmap.h"
7beba2fc 41
f6bcfd97
BP
42#if wxUSE_CONFIG
43 #include "wx/config.h"
44 #include "wx/memconf.h"
45#endif
46
47#if wxUSE_GUI
70184095 48 #include "wx/fontutil.h"
f6bcfd97
BP
49 #include "wx/msgdlg.h"
50 #include "wx/fontdlg.h"
51 #include "wx/choicdlg.h"
52#endif // wxUSE_GUI
53
82545b58 54#include "wx/encconv.h"
3c1866e8
VZ
55
56// ----------------------------------------------------------------------------
57// constants
58// ----------------------------------------------------------------------------
59
60// the config paths we use
1e6feb95 61#if wxUSE_CONFIG
3ca6a5f0 62static const wxChar* FONTMAPPER_ROOT_PATH = wxT("/wxWindows/FontMapper");
511f273f
OK
63static const wxChar* FONTMAPPER_CHARSET_PATH = wxT("Charsets");
64static const wxChar* FONTMAPPER_CHARSET_ALIAS_PATH = wxT("Aliases");
6603907d
VZ
65
66// we only ask questions in GUI mode
f6bcfd97
BP
67#if wxUSE_GUI
68 static const wxChar* FONTMAPPER_FONT_FROM_ENCODING_PATH = wxT("Encodings");
6603907d 69 static const wxChar* FONTMAPPER_FONT_DONT_ASK = wxT("none");
f6bcfd97 70#endif // wxUSE_GUI
1e6feb95 71#endif // wxUSE_CONFIG
7beba2fc
VZ
72
73// encodings supported by GetEncodingDescription
74static wxFontEncoding gs_encodings[] =
75{
76 wxFONTENCODING_ISO8859_1,
77 wxFONTENCODING_ISO8859_2,
78 wxFONTENCODING_ISO8859_3,
79 wxFONTENCODING_ISO8859_4,
80 wxFONTENCODING_ISO8859_5,
81 wxFONTENCODING_ISO8859_6,
82 wxFONTENCODING_ISO8859_7,
83 wxFONTENCODING_ISO8859_8,
84 wxFONTENCODING_ISO8859_9,
85 wxFONTENCODING_ISO8859_10,
86 wxFONTENCODING_ISO8859_11,
87 wxFONTENCODING_ISO8859_12,
88 wxFONTENCODING_ISO8859_13,
89 wxFONTENCODING_ISO8859_14,
90 wxFONTENCODING_ISO8859_15,
91 wxFONTENCODING_KOI8,
bc4e6fcd
VZ
92 wxFONTENCODING_CP932,
93 wxFONTENCODING_CP936,
94 wxFONTENCODING_CP949,
95 wxFONTENCODING_CP950,
7beba2fc
VZ
96 wxFONTENCODING_CP1250,
97 wxFONTENCODING_CP1251,
98 wxFONTENCODING_CP1252,
99 wxFONTENCODING_CP1253,
100 wxFONTENCODING_CP1254,
101 wxFONTENCODING_CP1255,
102 wxFONTENCODING_CP1256,
103 wxFONTENCODING_CP1257,
f6bcfd97 104 wxFONTENCODING_CP437,
bb84929e
VZ
105 wxFONTENCODING_UTF7,
106 wxFONTENCODING_UTF8,
2b5f62a0 107 wxFONTENCODING_EUC_JP,
7beba2fc
VZ
108};
109
110// the descriptions for them
111static const wxChar* gs_encodingDescs[] =
112{
03424b1b
VZ
113 wxTRANSLATE( "Western European (ISO-8859-1)" ),
114 wxTRANSLATE( "Central European (ISO-8859-2)" ),
7beba2fc 115 wxTRANSLATE( "Esperanto (ISO-8859-3)" ),
f6bcfd97 116 wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ),
03424b1b 117 wxTRANSLATE( "Cyrillic (ISO-8859-5)" ),
7beba2fc
VZ
118 wxTRANSLATE( "Arabic (ISO-8859-6)" ),
119 wxTRANSLATE( "Greek (ISO-8859-7)" ),
120 wxTRANSLATE( "Hebrew (ISO-8859-8)" ),
121 wxTRANSLATE( "Turkish (ISO-8859-9)" ),
f6bcfd97 122 wxTRANSLATE( "Nordic (ISO-8859-10)" ),
7beba2fc 123 wxTRANSLATE( "Thai (ISO-8859-11)" ),
80a24267 124 wxTRANSLATE( "Indian (ISO-8859-12)" ),
f6bcfd97 125 wxTRANSLATE( "Baltic (ISO-8859-13)" ),
80a24267 126 wxTRANSLATE( "Celtic (ISO-8859-14)" ),
03424b1b 127 wxTRANSLATE( "Western European with Euro (ISO-8859-15)" ),
7beba2fc 128 wxTRANSLATE( "KOI8-R" ),
bc4e6fcd 129 wxTRANSLATE( "Windows Japanese (CP 932)" ),
62b3ca69 130 wxTRANSLATE( "Windows Chinese Simplified (CP 936)" ),
bc4e6fcd
VZ
131 wxTRANSLATE( "Windows Korean (CP 949)" ),
132 wxTRANSLATE( "Windows Chinese Traditional (CP 950)" ),
80a24267 133 wxTRANSLATE( "Windows Central European (CP 1250)" ),
7beba2fc 134 wxTRANSLATE( "Windows Cyrillic (CP 1251)" ),
80a24267 135 wxTRANSLATE( "Windows Western European (CP 1252)" ),
7beba2fc
VZ
136 wxTRANSLATE( "Windows Greek (CP 1253)" ),
137 wxTRANSLATE( "Windows Turkish (CP 1254)" ),
138 wxTRANSLATE( "Windows Hebrew (CP 1255)" ),
139 wxTRANSLATE( "Windows Arabic (CP 1256)" ),
140 wxTRANSLATE( "Windows Baltic (CP 1257)" ),
f6bcfd97 141 wxTRANSLATE( "Windows/DOS OEM (CP 437)" ),
bb84929e
VZ
142 wxTRANSLATE( "Unicode 7 bit (UTF-7)" ),
143 wxTRANSLATE( "Unicode 8 bit (UTF-8)" ),
2b5f62a0 144 wxTRANSLATE( "Extended Unix Codepage for Japanese (EUC-JP)" ),
7beba2fc
VZ
145};
146
a4a6984d 147// and the internal names (these are not translated on purpose!)
7beba2fc
VZ
148static const wxChar* gs_encodingNames[] =
149{
ecffe992
VS
150 wxT( "iso-8859-1" ),
151 wxT( "iso-8859-2" ),
152 wxT( "iso-8859-3" ),
153 wxT( "iso-8859-4" ),
154 wxT( "iso-8859-5" ),
155 wxT( "iso-8859-6" ),
156 wxT( "iso-8859-7" ),
157 wxT( "iso-8859-8" ),
158 wxT( "iso-8859-9" ),
159 wxT( "iso-8859-10" ),
160 wxT( "iso-8859-11" ),
161 wxT( "iso-8859-12" ),
162 wxT( "iso-8859-13" ),
163 wxT( "iso-8859-14" ),
164 wxT( "iso-8859-15" ),
511f273f 165 wxT( "koi8-r" ),
bc4e6fcd
VZ
166 wxT( "windows-932" ),
167 wxT( "windows-936" ),
168 wxT( "windows-949" ),
169 wxT( "windows-950" ),
551fe3a6
VZ
170 wxT( "windows-1250" ),
171 wxT( "windows-1251" ),
172 wxT( "windows-1252" ),
173 wxT( "windows-1253" ),
174 wxT( "windows-1254" ),
175 wxT( "windows-1255" ),
176 wxT( "windows-1256" ),
177 wxT( "windows-1257" ),
178 wxT( "windows-437" ),
5707316c
VS
179 wxT( "utf-7" ),
180 wxT( "utf-8" ),
2b5f62a0 181 wxT( "euc-jp" ),
7beba2fc
VZ
182};
183
2b5f62a0
VZ
184wxCOMPILE_TIME_ASSERT( WXSIZEOF(gs_encodingDescs) == WXSIZEOF(gs_encodings) &&
185 WXSIZEOF(gs_encodingNames) == WXSIZEOF(gs_encodings),
186 EncodingsArraysNotInSync );
7beba2fc
VZ
187
188// ----------------------------------------------------------------------------
189// private classes
190// ----------------------------------------------------------------------------
191
192// change the config path during the lifetime of this object
193class wxFontMapperPathChanger
194{
195public:
196 wxFontMapperPathChanger(wxFontMapper *fontMapper, const wxString& path)
197 {
198 m_fontMapper = fontMapper;
199 m_ok = m_fontMapper->ChangePath(path, &m_pathOld);
200 }
201
202 bool IsOk() const { return m_ok; }
203
204 ~wxFontMapperPathChanger()
205 {
206 if ( IsOk() )
207 m_fontMapper->RestorePath(m_pathOld);
208 }
209
210private:
211 wxFontMapper *m_fontMapper;
212 bool m_ok;
213 wxString m_pathOld;
22f3361e
VZ
214
215 DECLARE_NO_COPY_CLASS(wxFontMapperPathChanger)
7beba2fc 216};
3c1866e8
VZ
217
218// ============================================================================
219// implementation
220// ============================================================================
221
222// ----------------------------------------------------------------------------
223// ctor and dtor
224// ----------------------------------------------------------------------------
225
226wxFontMapper::wxFontMapper()
227{
f6bcfd97 228#if wxUSE_CONFIG
3c1866e8 229 m_config = NULL;
5fe83549 230 m_configIsDummy = FALSE;
f6bcfd97
BP
231#endif // wxUSE_CONFIG
232
233#if wxUSE_GUI
3c1866e8 234 m_windowParent = NULL;
f6bcfd97 235#endif // wxUSE_GUI
3c1866e8
VZ
236}
237
238wxFontMapper::~wxFontMapper()
239{
4d416b5f
VZ
240#if wxUSE_CONFIG
241 if ( m_configIsDummy )
242 delete m_config;
243#endif // wxUSE_CONFIG
3c1866e8
VZ
244}
245
142b3bc2
VS
246wxFontMapper *wxFontMapper::sm_instance = NULL;
247
248/*static*/ wxFontMapper *wxFontMapper::Get()
249{
250 if ( !sm_instance )
251 sm_instance = new wxFontMapper;
252 return sm_instance;
253}
254
255/*static*/ wxFontMapper *wxFontMapper::Set(wxFontMapper *mapper)
256{
257 wxFontMapper *old = sm_instance;
258 sm_instance = mapper;
259 return old;
260}
261
262class wxFontMapperModule: public wxModule
263{
264public:
265 wxFontMapperModule() : wxModule() {}
266 virtual bool OnInit() { return TRUE; }
267 virtual void OnExit() { delete wxFontMapper::Set(NULL); }
268
269 DECLARE_DYNAMIC_CLASS(wxFontMapperModule)
270};
271
272IMPLEMENT_DYNAMIC_CLASS(wxFontMapperModule, wxModule)
273
3c1866e8
VZ
274// ----------------------------------------------------------------------------
275// customisation
276// ----------------------------------------------------------------------------
277
f6bcfd97
BP
278#if wxUSE_CONFIG
279
3c1866e8
VZ
280/* static */ const wxChar *wxFontMapper::GetDefaultConfigPath()
281{
282 return FONTMAPPER_ROOT_PATH;
283}
284
285void wxFontMapper::SetConfigPath(const wxString& prefix)
286{
287 wxCHECK_RET( !prefix.IsEmpty() && prefix[0] == wxCONFIG_PATH_SEPARATOR,
fbdcff4a 288 wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") );
3c1866e8
VZ
289
290 m_configRootPath = prefix;
291}
292
3c1866e8
VZ
293// ----------------------------------------------------------------------------
294// get config object and path for it
295// ----------------------------------------------------------------------------
296
297wxConfigBase *wxFontMapper::GetConfig()
298{
299 if ( !m_config )
300 {
301 // try the default
1d910ac1
VZ
302 m_config = wxConfig::Get(FALSE /*don't create on demand*/ );
303
304 if ( !m_config )
305 {
306 // we still want to have a config object because otherwise we would
307 // keep asking the user the same questions in the interactive mode,
308 // so create a dummy config which won't write to any files/registry
309 // but will allow us to remember the results of the questions at
310 // least during this run
311 m_config = new wxMemoryConfig;
5fe83549
VS
312 m_configIsDummy = TRUE;
313 // VS: we can't call wxConfig::Set(m_config) here because that would
314 // disable automatic wxConfig instance creation if this code was
315 // called before wxApp::OnInit (this happens in wxGTK -- it sets
316 // default wxFont encoding in wxApp::Initialize())
1d910ac1 317 }
3c1866e8
VZ
318 }
319
5fe83549
VS
320 if ( m_configIsDummy && wxConfig::Get(FALSE) != NULL )
321 {
322 // VS: in case we created dummy m_config (see above), we want to switch back
323 // to the real one as soon as one becomes available.
4d416b5f 324 delete m_config;
5fe83549
VS
325 m_config = wxConfig::Get(FALSE);
326 m_configIsDummy = FALSE;
327 // FIXME: ideally, we should add keys from dummy config to the real one now,
328 // but it is a low-priority task because typical wxWin application
c7821f94
VZ
329 // either doesn't use wxConfig at all or creates wxConfig object in
330 // wxApp::OnInit(), before any real interaction with the user takes
5fe83549
VS
331 // place...
332 }
333
3c1866e8
VZ
334 return m_config;
335}
336
337const wxString& wxFontMapper::GetConfigPath()
338{
339 if ( !m_configRootPath )
340 {
341 // use the default
342 m_configRootPath = GetDefaultConfigPath();
343 }
344
345 return m_configRootPath;
346}
f6bcfd97 347#endif
3c1866e8
VZ
348
349bool wxFontMapper::ChangePath(const wxString& pathNew, wxString *pathOld)
350{
f6bcfd97 351#if wxUSE_CONFIG
3c1866e8
VZ
352 wxConfigBase *config = GetConfig();
353 if ( !config )
354 return FALSE;
355
356 *pathOld = config->GetPath();
357
358 wxString path = GetConfigPath();
359 if ( path.IsEmpty() || path.Last() != wxCONFIG_PATH_SEPARATOR )
360 {
361 path += wxCONFIG_PATH_SEPARATOR;
362 }
363
364 wxASSERT_MSG( !pathNew || (pathNew[0] != wxCONFIG_PATH_SEPARATOR),
58c837a4 365 wxT("should be a relative path") );
3c1866e8
VZ
366
367 path += pathNew;
368
369 config->SetPath(path);
370
371 return TRUE;
f6bcfd97
BP
372#else
373 return FALSE;
374#endif
3c1866e8
VZ
375}
376
377void wxFontMapper::RestorePath(const wxString& pathOld)
378{
f6bcfd97 379#if wxUSE_CONFIG
3c1866e8 380 GetConfig()->SetPath(pathOld);
f6bcfd97
BP
381#else
382#endif
3c1866e8
VZ
383}
384
385// ----------------------------------------------------------------------------
386// charset/encoding correspondence
387// ----------------------------------------------------------------------------
388
7beba2fc
VZ
389/* static */
390wxString wxFontMapper::GetEncodingDescription(wxFontEncoding encoding)
391{
551fe3a6
VZ
392 if ( encoding == wxFONTENCODING_DEFAULT )
393 {
394 return _("Default encoding");
395 }
396
2b5f62a0 397 const size_t count = WXSIZEOF(gs_encodingDescs);
7beba2fc
VZ
398
399 for ( size_t i = 0; i < count; i++ )
400 {
401 if ( gs_encodings[i] == encoding )
402 {
403 return wxGetTranslation(gs_encodingDescs[i]);
404 }
405 }
406
407 wxString str;
408 str.Printf(_("Unknown encoding (%d)"), encoding);
409
410 return str;
411}
412
413/* static */
414wxString wxFontMapper::GetEncodingName(wxFontEncoding encoding)
415{
551fe3a6
VZ
416 if ( encoding == wxFONTENCODING_DEFAULT )
417 {
418 return _("default");
419 }
420
2b5f62a0 421 const size_t count = WXSIZEOF(gs_encodingNames);
7beba2fc
VZ
422
423 for ( size_t i = 0; i < count; i++ )
424 {
425 if ( gs_encodings[i] == encoding )
426 {
a4a6984d 427 return gs_encodingNames[i];
7beba2fc
VZ
428 }
429 }
430
431 wxString str;
432 str.Printf(_("unknown-%d"), encoding);
433
434 return str;
435}
436
3c1866e8
VZ
437wxFontEncoding wxFontMapper::CharsetToEncoding(const wxString& charset,
438 bool interactive)
439{
3e7fb236
VZ
440 // a special pseudo encoding which means "don't ask me about this charset
441 // any more" - we need it to avoid driving the user crazy with asking him
442 // time after time about the same charset which he [presumably] doesn't
443 // have the fonts fot
444 static const int wxFONTENCODING_UNKNOWN = -2;
445
3c1866e8
VZ
446 wxFontEncoding encoding = wxFONTENCODING_SYSTEM;
447
448 // we're going to modify it, make a copy
449 wxString cs = charset;
450
f6bcfd97 451#if wxUSE_CONFIG
3c1866e8
VZ
452 // first try the user-defined settings
453 wxString pathOld;
454 if ( ChangePath(FONTMAPPER_CHARSET_PATH, &pathOld) )
455 {
456 wxConfigBase *config = GetConfig();
457
458 // do we have an encoding for this charset?
459 long value = config->Read(charset, -1l);
460 if ( value != -1 )
461 {
3e7fb236
VZ
462 if ( value == wxFONTENCODING_UNKNOWN )
463 {
464 // don't try to find it, in particular don't ask the user
465 return wxFONTENCODING_SYSTEM;
466 }
467
3c1866e8
VZ
468 if ( value >= 0 && value <= wxFONTENCODING_MAX )
469 {
470 encoding = (wxFontEncoding)value;
471 }
472 else
473 {
f6bcfd97 474 wxLogDebug(wxT("corrupted config data: invalid encoding %ld for charset '%s' ignored"),
1d910ac1 475 value, charset.c_str());
3c1866e8
VZ
476 }
477 }
478
479 if ( encoding == wxFONTENCODING_SYSTEM )
480 {
481 // may be we have an alias?
482 config->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH);
483
484 wxString alias = config->Read(charset);
485 if ( !!alias )
486 {
487 // yes, we do - use it instead
488 cs = alias;
489 }
490 }
491
492 RestorePath(pathOld);
493 }
3e7fb236 494#endif // wxUSE_CONFIG
3c1866e8 495
551fe3a6 496 // if didn't find it there, try to recognize it ourselves
3c1866e8
VZ
497 if ( encoding == wxFONTENCODING_SYSTEM )
498 {
551fe3a6
VZ
499 // trim any spaces
500 cs.Trim(TRUE);
501 cs.Trim(FALSE);
502
3ca6a5f0 503 // discard the optional quotes
caa6e137 504 if ( !cs.empty() )
3ca6a5f0
BP
505 {
506 if ( cs[0u] == _T('"') && cs.Last() == _T('"') )
507 {
508 cs = wxString(cs.c_str(), cs.length() - 1);
509 }
510 }
511
3c1866e8
VZ
512 cs.MakeUpper();
513
cafbf6fb 514 if ( cs.empty() || cs == _T("US-ASCII") )
551fe3a6 515 {
3c1866e8 516 encoding = wxFONTENCODING_DEFAULT;
551fe3a6 517 }
bb84929e 518 else if ( cs == wxT("UTF-7") )
551fe3a6 519 {
bb84929e 520 encoding = wxFONTENCODING_UTF7;
551fe3a6 521 }
bb84929e 522 else if ( cs == wxT("UTF-8") )
551fe3a6 523 {
bb84929e 524 encoding = wxFONTENCODING_UTF8;
551fe3a6 525 }
2b5f62a0
VZ
526 else if ( cs == wxT("GB2312") )
527 {
528 encoding = wxFONTENCODING_GB2312;
529 }
530 else if ( cs == wxT("BIG5") )
531 {
532 encoding = wxFONTENCODING_BIG5;
533 }
534 else if ( cs == wxT("SJIS") ||
535 cs == wxT("SHIFT_JIS") ||
536 cs == wxT("SHIFT-JIS") )
537 {
538 encoding = wxFONTENCODING_SHIFT_JIS;
539 }
540 else if ( cs == wxT("EUC-JP") ||
541 cs == wxT("EUC_JP") )
542 {
543 encoding = wxFONTENCODING_EUC_JP;
544 }
551fe3a6
VZ
545 else if ( cs == wxT("KOI8-R") ||
546 cs == wxT("KOI8-U") ||
547 cs == wxT("KOI8-RU") )
548 {
549 // although koi8-ru is not strictly speaking the same as koi8-r,
550 // they are similar enough to make mapping it to koi8 better than
551 // not reckognizing it at all
3c1866e8 552 encoding = wxFONTENCODING_KOI8;
551fe3a6 553 }
58c837a4 554 else if ( cs.Left(3) == wxT("ISO") )
3c1866e8
VZ
555 {
556 // the dash is optional (or, to be exact, it is not, but
557 // several brokenmails "forget" it)
558 const wxChar *p = cs.c_str() + 3;
58c837a4 559 if ( *p == wxT('-') )
3c1866e8 560 p++;
2b5f62a0
VZ
561
562 // printf( "iso %s\n", (const char*) cs.ToAscii() );
3c1866e8
VZ
563
564 unsigned int value;
58c837a4 565 if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
3c1866e8 566 {
2b5f62a0
VZ
567 // printf( "value %d\n", (int)value );
568
569 // make it 0 based and check that it is strictly positive in
570 // the process (no such thing as iso8859-0 encoding)
571 if ( (value-- > 0) &&
572 (value < wxFONTENCODING_ISO8859_MAX -
573 wxFONTENCODING_ISO8859_1) )
574 {
575 // it's a valid ISO8859 encoding
576 value += wxFONTENCODING_ISO8859_1;
577 encoding = (wxFontEncoding)value;
578 }
579 }
580 }
581 else if ( cs.Left(4) == wxT("8859") )
582 {
583 const wxChar *p = cs.c_str();
584
585 unsigned int value;
586 if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
587 {
588 // printf( "value %d\n", (int)value );
589
daaa6710
VZ
590 // make it 0 based and check that it is strictly positive in
591 // the process (no such thing as iso8859-0 encoding)
592 if ( (value-- > 0) &&
593 (value < wxFONTENCODING_ISO8859_MAX -
594 wxFONTENCODING_ISO8859_1) )
3c1866e8
VZ
595 {
596 // it's a valid ISO8859 encoding
daaa6710 597 value += wxFONTENCODING_ISO8859_1;
3c1866e8
VZ
598 encoding = (wxFontEncoding)value;
599 }
600 }
601 }
551fe3a6 602 else // check for Windows charsets
3c1866e8 603 {
551fe3a6
VZ
604 size_t len;
605 if ( cs.Left(7) == wxT("WINDOWS") )
606 {
607 len = 7;
608 }
609 else if ( cs.Left(2) == wxT("CP") )
3c1866e8 610 {
551fe3a6
VZ
611 len = 2;
612 }
613 else // not a Windows encoding
614 {
615 len = 0;
616 }
617
618 if ( len )
619 {
620 const wxChar *p = cs.c_str() + len;
621 if ( *p == wxT('-') )
622 p++;
623
624 int value;
625 if ( wxSscanf(p, wxT("%u"), &value) == 1 )
3c1866e8 626 {
551fe3a6 627 if ( value >= 1250 )
3c1866e8 628 {
551fe3a6
VZ
629 value -= 1250;
630 if ( value < wxFONTENCODING_CP12_MAX -
631 wxFONTENCODING_CP1250 )
632 {
633 // a valid Windows code page
634 value += wxFONTENCODING_CP1250;
635 encoding = (wxFontEncoding)value;
636 }
3c1866e8 637 }
c7821f94
VZ
638
639 switch ( value )
640 {
641 case 932:
642 encoding = wxFONTENCODING_CP932;
643 break;
644
645 case 936:
646 encoding = wxFONTENCODING_CP936;
647 break;
648
649 case 949:
650 encoding = wxFONTENCODING_CP949;
651 break;
652
653 case 950:
654 encoding = wxFONTENCODING_CP950;
655 break;
656 }
3c1866e8
VZ
657 }
658 }
659 }
660 //else: unknown
661 }
662
f6bcfd97 663#if wxUSE_GUI
3c1866e8
VZ
664 // if still no luck, ask the user - unless disabled
665 if ( (encoding == wxFONTENCODING_SYSTEM) && interactive )
666 {
667 // prepare the dialog data
668
669 // the dialog title
670 wxString title(m_titleDialog);
671 if ( !title )
672 title << wxTheApp->GetAppName() << _(": unknown charset");
673
674 // the message
675 wxString msg;
f6bcfd97 676 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());
3c1866e8
VZ
677
678 // the list of choices
2b5f62a0 679 const size_t count = WXSIZEOF(gs_encodingDescs);
3c1866e8
VZ
680
681 wxString *encodingNamesTranslated = new wxString[count];
682
11c7d5b6 683 for ( size_t i = 0; i < count; i++ )
3c1866e8 684 {
11c7d5b6 685 encodingNamesTranslated[i] = wxGetTranslation(gs_encodingDescs[i]);
3c1866e8
VZ
686 }
687
688 // the parent window
689 wxWindow *parent = m_windowParent;
690 if ( !parent )
691 parent = wxTheApp->GetTopWindow();
692
693 // do ask the user and get back the index in encodings table
694 int n = wxGetSingleChoiceIndex(msg, title,
695 count,
696 encodingNamesTranslated,
697 parent);
698
699 delete [] encodingNamesTranslated;
700
701 if ( n != -1 )
702 {
7beba2fc 703 encoding = gs_encodings[n];
3e7fb236 704 }
1d910ac1 705
f6bcfd97
BP
706#if wxUSE_CONFIG
707 // save the result in the config now
3e7fb236
VZ
708 if ( ChangePath(FONTMAPPER_CHARSET_PATH, &pathOld) )
709 {
710 wxConfigBase *config = GetConfig();
1d910ac1 711
3e7fb236
VZ
712 // remember the alt encoding for this charset - or remember that
713 // we don't know it
714 long value = n == -1 ? wxFONTENCODING_UNKNOWN : (long)encoding;
715 if ( !config->Write(charset, value) )
716 {
717 wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset.c_str());
1d910ac1 718 }
3e7fb236
VZ
719
720 RestorePath(pathOld);
3c1866e8 721 }
3e7fb236 722#endif // wxUSE_CONFIG
3c1866e8 723 }
f6bcfd97 724#endif // wxUSE_GUI
3c1866e8
VZ
725
726 return encoding;
727}
728
7beba2fc
VZ
729// ----------------------------------------------------------------------------
730// support for unknown encodings: we maintain a map between the
731// (platform-specific) strings identifying them and our wxFontEncodings they
732// correspond to which is used by GetFontForEncoding() function
733// ----------------------------------------------------------------------------
734
f6bcfd97
BP
735#if wxUSE_GUI
736
7beba2fc
VZ
737bool wxFontMapper::TestAltEncoding(const wxString& configEntry,
738 wxFontEncoding encReplacement,
739 wxNativeEncodingInfo *info)
740{
741 if ( wxGetNativeFontEncoding(encReplacement, info) &&
742 wxTestFontEncoding(*info) )
743 {
f6bcfd97 744#if wxUSE_CONFIG
7beba2fc
VZ
745 // remember the mapping in the config
746 wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH);
747
748 if ( path.IsOk() )
749 {
750 GetConfig()->Write(configEntry, info->ToString());
751 }
f6bcfd97 752#endif // wxUSE_CONFIG
7beba2fc
VZ
753 return TRUE;
754 }
755
756 return FALSE;
757}
758
f6bcfd97
BP
759#if wxUSE_GUI
760class ReentrancyBlocker
761{
762public:
523c2b8d
VZ
763 ReentrancyBlocker(bool& flag) : m_flagOld(flag), m_flag(flag)
764 { m_flag = TRUE; }
765 ~ReentrancyBlocker() { m_flag = m_flagOld; }
f6bcfd97
BP
766
767private:
523c2b8d
VZ
768 bool m_flagOld;
769 bool& m_flag;
f6bcfd97 770};
523c2b8d 771#endif // wxUSE_GUI
f6bcfd97 772
7beba2fc
VZ
773bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
774 wxNativeEncodingInfo *info,
6648cd46 775 const wxString& facename,
7beba2fc
VZ
776 bool interactive)
777{
f6bcfd97
BP
778#if wxUSE_GUI
779 // we need a flag to prevent infinite recursion which happens, for
780 // example, when GetAltForEncoding() is called from an OnPaint() handler:
781 // in this case, wxYield() which is called from wxMessageBox() we use here
782 // will lead to another call of OnPaint() and hence to another call of
783 // GetAltForEncoding() - and it is impossible to catch this from the user
784 // code because we are called from wxFont ctor implicitly.
785
786 // assume we're always called from the main thread, so that it is safe to
787 // use a static var
788 static bool s_inGetAltForEncoding = FALSE;
789
790 if ( interactive && s_inGetAltForEncoding )
791 return FALSE;
792
793 ReentrancyBlocker blocker(s_inGetAltForEncoding);
794#endif // wxUSE_GUI
795
58c837a4 796 wxCHECK_MSG( info, FALSE, wxT("bad pointer in GetAltForEncoding") );
7beba2fc 797
6648cd46
VS
798 info->facename = facename;
799
97d3f0ee
VZ
800 if ( encoding == wxFONTENCODING_DEFAULT )
801 {
802 encoding = wxFont::GetDefaultEncoding();
803 }
804
805 // if we failed to load the system default encoding, something is really
806 // wrong and we'd better stop now - otherwise we will go into endless
807 // recursion trying to create the font in the msg box with the error
808 // message
809 if ( encoding == wxFONTENCODING_SYSTEM )
810 {
73deed44 811 wxLogFatalError(_("can't load any font, aborting"));
97d3f0ee 812
73deed44 813 // wxLogFatalError doesn't return
97d3f0ee
VZ
814 }
815
a4a6984d
VZ
816 wxString configEntry,
817 encName = GetEncodingName(encoding);
1d910ac1
VZ
818 if ( !!facename )
819 {
820 configEntry = facename + _T("_");
821 }
822 configEntry += encName;
7beba2fc 823
f6bcfd97 824#if wxUSE_CONFIG
7beba2fc
VZ
825 // do we have a font spec for this encoding?
826 wxString pathOld;
827 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
828 {
829 wxConfigBase *config = GetConfig();
830
831 wxString fontinfo = config->Read(configEntry);
832
833 RestorePath(pathOld);
834
6603907d
VZ
835 // this special value means that we don't know of fonts for this
836 // encoding but, moreover, have already asked the user as well and he
837 // didn't specify any font neither
838 if ( fontinfo == FONTMAPPER_FONT_DONT_ASK )
1d910ac1 839 {
6603907d 840 interactive = FALSE;
1d910ac1 841 }
6603907d 842 else // use the info entered the last time
7beba2fc 843 {
6603907d 844 if ( !!fontinfo && !!facename )
7beba2fc 845 {
6603907d
VZ
846 // we tried to find a match with facename - now try without it
847 fontinfo = config->Read(encName);
7beba2fc 848 }
6603907d
VZ
849
850 if ( !!fontinfo )
7beba2fc 851 {
6603907d
VZ
852 if ( info->FromString(fontinfo) )
853 {
854 if ( wxTestFontEncoding(*info) )
855 {
856 // ok, got something
857 return TRUE;
858 }
859 //else: no such fonts, look for something else
860 // (should we erase the outdated value?)
861 }
862 else
863 {
864 wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"),
865 fontinfo.c_str());
866 }
7beba2fc 867 }
6603907d 868 //else: there is no information in config about this encoding
7beba2fc
VZ
869 }
870 }
f6bcfd97 871#endif // wxUSE_CONFIG
7beba2fc 872
3a989c8a
VZ
873 // now try to map this encoding to a compatible one which we have on this
874 // system
875 wxFontEncodingArray equiv = wxEncodingConverter::GetAllEquivalents(encoding);
876 size_t count = equiv.GetCount();
877 bool foundEquivEncoding = FALSE;
c6465c96 878 wxFontEncoding equivEncoding = wxFONTENCODING_SYSTEM;
3a989c8a
VZ
879 if ( count )
880 {
881 for ( size_t i = 0; i < count && !foundEquivEncoding; i++ )
882 {
883 // don't test for encoding itself, we already know we don't have it
884 if ( equiv[i] == encoding )
885 continue;
886
887 if ( TestAltEncoding(configEntry, equiv[i], info) )
888 {
889 equivEncoding = equiv[i];
890
891 foundEquivEncoding = TRUE;
892 }
893 }
894 }
895
7beba2fc 896 // ask the user
3379ed37 897#if wxUSE_FONTDLG
7beba2fc
VZ
898 if ( interactive )
899 {
900 wxString title(m_titleDialog);
901 if ( !title )
902 title << wxTheApp->GetAppName() << _(": unknown encoding");
903
3a989c8a
VZ
904 // built the message
905 wxString encDesc = GetEncodingDescription(encoding),
906 msg;
907 if ( foundEquivEncoding )
908 {
909 // ask the user if he wants to override found alternative encoding
910 msg.Printf(_("No font for displaying text in encoding '%s' found,\nbut an alternative encoding '%s' is available.\nDo you want to use this encoding (otherwise you will have to choose another one)?"),
911 encDesc.c_str(), GetEncodingDescription(equivEncoding).c_str());
912 }
913 else
914 {
915 msg.Printf(_("No font for displaying text in encoding '%s' found.\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)?"),
916 encDesc.c_str());
917 }
7beba2fc 918
3a989c8a
VZ
919 // the question is different in 2 cases so the answer has to be
920 // interpreted differently as well
921 int answer = foundEquivEncoding ? wxNO : wxYES;
7beba2fc
VZ
922
923 if ( wxMessageBox(msg, title,
3a989c8a
VZ
924 wxICON_QUESTION | wxYES_NO,
925 m_windowParent) == answer )
7beba2fc
VZ
926 {
927 wxFontData data;
928 data.SetEncoding(encoding);
929 data.EncodingInfo() = *info;
baaae89f 930 wxFontDialog dialog(m_windowParent, data);
7beba2fc
VZ
931 if ( dialog.ShowModal() == wxID_OK )
932 {
933 wxFontData retData = dialog.GetFontData();
934 wxFont font = retData.GetChosenFont();
935
11c7d5b6 936 *info = retData.EncodingInfo();
3a989c8a 937 info->encoding = retData.GetEncoding();
7beba2fc 938
f6bcfd97 939#if wxUSE_CONFIG
6603907d 940 // remember this in the config
7beba2fc
VZ
941 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
942 {
943 GetConfig()->Write(configEntry, info->ToString());
944
945 RestorePath(pathOld);
946 }
bb84929e 947#endif // wxUSE_CONFIG
7beba2fc
VZ
948
949 return TRUE;
950 }
951 //else: the user canceled the font selection dialog
952 }
6603907d
VZ
953 else
954 {
3a989c8a
VZ
955 // the user doesn't want to select a font for this encoding
956 // or selected to use equivalent encoding
957 //
6603907d
VZ
958 // remember it to avoid asking the same question again later
959#if wxUSE_CONFIG
960 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
961 {
3a989c8a
VZ
962 GetConfig()->Write
963 (
964 configEntry,
965 foundEquivEncoding ? info->ToString().c_str()
966 : FONTMAPPER_FONT_DONT_ASK
967 );
6603907d
VZ
968
969 RestorePath(pathOld);
970 }
971#endif // wxUSE_CONFIG
972 }
7beba2fc
VZ
973 }
974 //else: we're in non-interactive mode
3379ed37 975#endif // wxUSE_FONTDLG
7beba2fc 976
3a989c8a 977 return foundEquivEncoding;
7beba2fc 978}
6648cd46 979
6648cd46
VS
980bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
981 wxFontEncoding *alt_encoding,
982 const wxString& facename,
983 bool interactive)
984{
985 wxNativeEncodingInfo info;
986 bool r = GetAltForEncoding(encoding, &info, facename, interactive);
987 *alt_encoding = info.encoding;
988 return r;
989}
990
6648cd46
VS
991bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding,
992 const wxString& facename)
993{
994 wxNativeEncodingInfo info;
62ea506e 995
551fe3a6 996 if (wxGetNativeFontEncoding(encoding, &info))
62ea506e
VS
997 {
998 info.facename = facename;
999 return wxTestFontEncoding(info);
1000 }
3ca6a5f0
BP
1001
1002 return FALSE;
6648cd46 1003}
f6bcfd97
BP
1004
1005#endif // wxUSE_GUI
1e6feb95
VZ
1006
1007#endif // wxUSE_FONTMAP