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