recognize 646 charset as US-ASCII (this is how it is used by Solaris)
[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 // nl_langinfo() under Solaris returns 646 by default which stands for
493 // ISO-646, i.e. 7 bit ASCII and we should recognize it to avoid
494 // warnings about unrecognized encoding on each program startup
495 if ( cs.empty() || cs == _T("US-ASCII") || cs == _T("646") )
496 {
497 encoding = wxFONTENCODING_DEFAULT;
498 }
499 else if ( cs == wxT("UTF-7") )
500 {
501 encoding = wxFONTENCODING_UTF7;
502 }
503 else if ( cs == wxT("UTF-8") )
504 {
505 encoding = wxFONTENCODING_UTF8;
506 }
507 else if ( cs == wxT("KOI8-R") ||
508 cs == wxT("KOI8-U") ||
509 cs == wxT("KOI8-RU") )
510 {
511 // although koi8-ru is not strictly speaking the same as koi8-r,
512 // they are similar enough to make mapping it to koi8 better than
513 // not reckognizing it at all
514 encoding = wxFONTENCODING_KOI8;
515 }
516 else if ( cs.Left(3) == wxT("ISO") )
517 {
518 // the dash is optional (or, to be exact, it is not, but
519 // several brokenmails "forget" it)
520 const wxChar *p = cs.c_str() + 3;
521 if ( *p == wxT('-') )
522 p++;
523
524 unsigned int value;
525 if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
526 {
527 // make it 0 based and check that it is strictly positive in
528 // the process (no such thing as iso8859-0 encoding)
529 if ( (value-- > 0) &&
530 (value < wxFONTENCODING_ISO8859_MAX -
531 wxFONTENCODING_ISO8859_1) )
532 {
533 // it's a valid ISO8859 encoding
534 value += wxFONTENCODING_ISO8859_1;
535 encoding = (wxFontEncoding)value;
536 }
537 }
538 }
539 else // check for Windows charsets
540 {
541 size_t len;
542 if ( cs.Left(7) == wxT("WINDOWS") )
543 {
544 len = 7;
545 }
546 else if ( cs.Left(2) == wxT("CP") )
547 {
548 len = 2;
549 }
550 else // not a Windows encoding
551 {
552 len = 0;
553 }
554
555 if ( len )
556 {
557 const wxChar *p = cs.c_str() + len;
558 if ( *p == wxT('-') )
559 p++;
560
561 int value;
562 if ( wxSscanf(p, wxT("%u"), &value) == 1 )
563 {
564 if ( value >= 1250 )
565 {
566 value -= 1250;
567 if ( value < wxFONTENCODING_CP12_MAX -
568 wxFONTENCODING_CP1250 )
569 {
570 // a valid Windows code page
571 value += wxFONTENCODING_CP1250;
572 encoding = (wxFontEncoding)value;
573 }
574 }
575
576 switch ( value )
577 {
578 case 932:
579 encoding = wxFONTENCODING_CP932;
580 break;
581
582 case 936:
583 encoding = wxFONTENCODING_CP936;
584 break;
585
586 case 949:
587 encoding = wxFONTENCODING_CP949;
588 break;
589
590 case 950:
591 encoding = wxFONTENCODING_CP950;
592 break;
593 }
594 }
595 }
596 }
597 //else: unknown
598 }
599
600 #if wxUSE_GUI
601 // if still no luck, ask the user - unless disabled
602 if ( (encoding == wxFONTENCODING_SYSTEM) && interactive )
603 {
604 // prepare the dialog data
605
606 // the dialog title
607 wxString title(m_titleDialog);
608 if ( !title )
609 title << wxTheApp->GetAppName() << _(": unknown charset");
610
611 // the message
612 wxString msg;
613 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());
614
615 // the list of choices
616 size_t count = WXSIZEOF(gs_encodingDescs);
617
618 wxASSERT_MSG( count == WXSIZEOF(gs_encodings),
619 wxT("inconsitency detected - forgot to update one of the arrays?") );
620
621 wxString *encodingNamesTranslated = new wxString[count];
622
623 for ( size_t i = 0; i < count; i++ )
624 {
625 encodingNamesTranslated[i] = wxGetTranslation(gs_encodingDescs[i]);
626 }
627
628 // the parent window
629 wxWindow *parent = m_windowParent;
630 if ( !parent )
631 parent = wxTheApp->GetTopWindow();
632
633 // do ask the user and get back the index in encodings table
634 int n = wxGetSingleChoiceIndex(msg, title,
635 count,
636 encodingNamesTranslated,
637 parent);
638
639 delete [] encodingNamesTranslated;
640
641 if ( n != -1 )
642 {
643 encoding = gs_encodings[n];
644 }
645
646 #if wxUSE_CONFIG
647 // save the result in the config now
648 if ( ChangePath(FONTMAPPER_CHARSET_PATH, &pathOld) )
649 {
650 wxConfigBase *config = GetConfig();
651
652 // remember the alt encoding for this charset - or remember that
653 // we don't know it
654 long value = n == -1 ? wxFONTENCODING_UNKNOWN : (long)encoding;
655 if ( !config->Write(charset, value) )
656 {
657 wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset.c_str());
658 }
659
660 RestorePath(pathOld);
661 }
662 #endif // wxUSE_CONFIG
663 }
664 #endif // wxUSE_GUI
665
666 return encoding;
667 }
668
669 // ----------------------------------------------------------------------------
670 // support for unknown encodings: we maintain a map between the
671 // (platform-specific) strings identifying them and our wxFontEncodings they
672 // correspond to which is used by GetFontForEncoding() function
673 // ----------------------------------------------------------------------------
674
675 #if wxUSE_GUI
676
677 bool wxFontMapper::TestAltEncoding(const wxString& configEntry,
678 wxFontEncoding encReplacement,
679 wxNativeEncodingInfo *info)
680 {
681 if ( wxGetNativeFontEncoding(encReplacement, info) &&
682 wxTestFontEncoding(*info) )
683 {
684 #if wxUSE_CONFIG
685 // remember the mapping in the config
686 wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH);
687
688 if ( path.IsOk() )
689 {
690 GetConfig()->Write(configEntry, info->ToString());
691 }
692 #endif // wxUSE_CONFIG
693 return TRUE;
694 }
695
696 return FALSE;
697 }
698
699 #if wxUSE_GUI
700 class ReentrancyBlocker
701 {
702 public:
703 ReentrancyBlocker(bool& b) : m_b(b) { m_b = TRUE; }
704 ~ReentrancyBlocker() { m_b = FALSE; }
705
706 private:
707 bool& m_b;
708 };
709 #endif
710
711 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
712 wxNativeEncodingInfo *info,
713 const wxString& facename,
714 bool interactive)
715 {
716 #if wxUSE_GUI
717 // we need a flag to prevent infinite recursion which happens, for
718 // example, when GetAltForEncoding() is called from an OnPaint() handler:
719 // in this case, wxYield() which is called from wxMessageBox() we use here
720 // will lead to another call of OnPaint() and hence to another call of
721 // GetAltForEncoding() - and it is impossible to catch this from the user
722 // code because we are called from wxFont ctor implicitly.
723
724 // assume we're always called from the main thread, so that it is safe to
725 // use a static var
726 static bool s_inGetAltForEncoding = FALSE;
727
728 if ( interactive && s_inGetAltForEncoding )
729 return FALSE;
730
731 ReentrancyBlocker blocker(s_inGetAltForEncoding);
732 #endif // wxUSE_GUI
733
734 wxCHECK_MSG( info, FALSE, wxT("bad pointer in GetAltForEncoding") );
735
736 info->facename = facename;
737
738 if ( encoding == wxFONTENCODING_DEFAULT )
739 {
740 encoding = wxFont::GetDefaultEncoding();
741 }
742
743 // if we failed to load the system default encoding, something is really
744 // wrong and we'd better stop now - otherwise we will go into endless
745 // recursion trying to create the font in the msg box with the error
746 // message
747 if ( encoding == wxFONTENCODING_SYSTEM )
748 {
749 wxFatalError(_("can't load any font, aborting"));
750
751 // wxFatalError doesn't return
752 }
753
754 wxString configEntry,
755 encName = GetEncodingName(encoding);
756 if ( !!facename )
757 {
758 configEntry = facename + _T("_");
759 }
760 configEntry += encName;
761
762 #if wxUSE_CONFIG
763 // do we have a font spec for this encoding?
764 wxString pathOld;
765 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
766 {
767 wxConfigBase *config = GetConfig();
768
769 wxString fontinfo = config->Read(configEntry);
770
771 RestorePath(pathOld);
772
773 // this special value means that we don't know of fonts for this
774 // encoding but, moreover, have already asked the user as well and he
775 // didn't specify any font neither
776 if ( fontinfo == FONTMAPPER_FONT_DONT_ASK )
777 {
778 interactive = FALSE;
779 }
780 else // use the info entered the last time
781 {
782 if ( !!fontinfo && !!facename )
783 {
784 // we tried to find a match with facename - now try without it
785 fontinfo = config->Read(encName);
786 }
787
788 if ( !!fontinfo )
789 {
790 if ( info->FromString(fontinfo) )
791 {
792 if ( wxTestFontEncoding(*info) )
793 {
794 // ok, got something
795 return TRUE;
796 }
797 //else: no such fonts, look for something else
798 // (should we erase the outdated value?)
799 }
800 else
801 {
802 wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"),
803 fontinfo.c_str());
804 }
805 }
806 //else: there is no information in config about this encoding
807 }
808 }
809 #endif // wxUSE_CONFIG
810
811 // now try to map this encoding to a compatible one which we have on this
812 // system
813 wxFontEncodingArray equiv = wxEncodingConverter::GetAllEquivalents(encoding);
814 size_t count = equiv.GetCount();
815 bool foundEquivEncoding = FALSE;
816 wxFontEncoding equivEncoding = wxFONTENCODING_SYSTEM;
817 if ( count )
818 {
819 for ( size_t i = 0; i < count && !foundEquivEncoding; i++ )
820 {
821 // don't test for encoding itself, we already know we don't have it
822 if ( equiv[i] == encoding )
823 continue;
824
825 if ( TestAltEncoding(configEntry, equiv[i], info) )
826 {
827 equivEncoding = equiv[i];
828
829 foundEquivEncoding = TRUE;
830 }
831 }
832 }
833
834 // ask the user
835 #if wxUSE_FONTDLG
836 if ( interactive )
837 {
838 wxString title(m_titleDialog);
839 if ( !title )
840 title << wxTheApp->GetAppName() << _(": unknown encoding");
841
842 // built the message
843 wxString encDesc = GetEncodingDescription(encoding),
844 msg;
845 if ( foundEquivEncoding )
846 {
847 // ask the user if he wants to override found alternative encoding
848 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)?"),
849 encDesc.c_str(), GetEncodingDescription(equivEncoding).c_str());
850 }
851 else
852 {
853 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)?"),
854 encDesc.c_str());
855 }
856
857 // the question is different in 2 cases so the answer has to be
858 // interpreted differently as well
859 int answer = foundEquivEncoding ? wxNO : wxYES;
860
861 if ( wxMessageBox(msg, title,
862 wxICON_QUESTION | wxYES_NO,
863 m_windowParent) == answer )
864 {
865 wxFontData data;
866 data.SetEncoding(encoding);
867 data.EncodingInfo() = *info;
868 wxFontDialog dialog(m_windowParent, &data);
869 if ( dialog.ShowModal() == wxID_OK )
870 {
871 wxFontData retData = dialog.GetFontData();
872 wxFont font = retData.GetChosenFont();
873
874 *info = retData.EncodingInfo();
875 info->encoding = retData.GetEncoding();
876
877 #if wxUSE_CONFIG
878 // remember this in the config
879 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
880 {
881 GetConfig()->Write(configEntry, info->ToString());
882
883 RestorePath(pathOld);
884 }
885 #endif // wxUSE_CONFIG
886
887 return TRUE;
888 }
889 //else: the user canceled the font selection dialog
890 }
891 else
892 {
893 // the user doesn't want to select a font for this encoding
894 // or selected to use equivalent encoding
895 //
896 // remember it to avoid asking the same question again later
897 #if wxUSE_CONFIG
898 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
899 {
900 GetConfig()->Write
901 (
902 configEntry,
903 foundEquivEncoding ? info->ToString().c_str()
904 : FONTMAPPER_FONT_DONT_ASK
905 );
906
907 RestorePath(pathOld);
908 }
909 #endif // wxUSE_CONFIG
910 }
911 }
912 //else: we're in non-interactive mode
913 #endif // wxUSE_FONTDLG
914
915 return foundEquivEncoding;
916 }
917
918 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
919 wxFontEncoding *alt_encoding,
920 const wxString& facename,
921 bool interactive)
922 {
923 wxNativeEncodingInfo info;
924 bool r = GetAltForEncoding(encoding, &info, facename, interactive);
925 *alt_encoding = info.encoding;
926 return r;
927 }
928
929 bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding,
930 const wxString& facename)
931 {
932 wxNativeEncodingInfo info;
933
934 if (wxGetNativeFontEncoding(encoding, &info))
935 {
936 info.facename = facename;
937 return wxTestFontEncoding(info);
938 }
939
940 return FALSE;
941 }
942
943 #endif // wxUSE_GUI
944
945 #endif // wxUSE_FONTMAP