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