]> git.saurik.com Git - wxWidgets.git/blob - src/common/fontmap.cpp
Don't call a function that might do drawing when setting a null image list
[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/module.h"
40 #include "wx/fontmap.h"
41
42 #if wxUSE_CONFIG
43 #include "wx/config.h"
44 #include "wx/memconf.h"
45 #endif
46
47 #if wxUSE_GUI
48 #include "wx/fontutil.h"
49 #include "wx/msgdlg.h"
50 #include "wx/fontdlg.h"
51 #include "wx/choicdlg.h"
52 #endif // wxUSE_GUI
53
54 #include "wx/encconv.h"
55
56 // ----------------------------------------------------------------------------
57 // constants
58 // ----------------------------------------------------------------------------
59
60 // the config paths we use
61 #if wxUSE_CONFIG
62 static const wxChar* FONTMAPPER_ROOT_PATH = wxT("/wxWindows/FontMapper");
63 static const wxChar* FONTMAPPER_CHARSET_PATH = wxT("Charsets");
64 static const wxChar* FONTMAPPER_CHARSET_ALIAS_PATH = wxT("Aliases");
65
66 // we only ask questions in GUI mode
67 #if wxUSE_GUI
68 static const wxChar* FONTMAPPER_FONT_FROM_ENCODING_PATH = wxT("Encodings");
69 static const wxChar* FONTMAPPER_FONT_DONT_ASK = wxT("none");
70 #endif // wxUSE_GUI
71 #endif // wxUSE_CONFIG
72
73 // encodings supported by GetEncodingDescription
74 static 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,
92 wxFONTENCODING_CP932,
93 wxFONTENCODING_CP936,
94 wxFONTENCODING_CP949,
95 wxFONTENCODING_CP950,
96 wxFONTENCODING_CP1250,
97 wxFONTENCODING_CP1251,
98 wxFONTENCODING_CP1252,
99 wxFONTENCODING_CP1253,
100 wxFONTENCODING_CP1254,
101 wxFONTENCODING_CP1255,
102 wxFONTENCODING_CP1256,
103 wxFONTENCODING_CP1257,
104 wxFONTENCODING_CP437,
105 wxFONTENCODING_UTF7,
106 wxFONTENCODING_UTF8,
107 };
108
109 // the descriptions for them
110 static const wxChar* gs_encodingDescs[] =
111 {
112 wxTRANSLATE( "Western European (ISO-8859-1)" ),
113 wxTRANSLATE( "Central European (ISO-8859-2)" ),
114 wxTRANSLATE( "Esperanto (ISO-8859-3)" ),
115 wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ),
116 wxTRANSLATE( "Cyrillic (ISO-8859-5)" ),
117 wxTRANSLATE( "Arabic (ISO-8859-6)" ),
118 wxTRANSLATE( "Greek (ISO-8859-7)" ),
119 wxTRANSLATE( "Hebrew (ISO-8859-8)" ),
120 wxTRANSLATE( "Turkish (ISO-8859-9)" ),
121 wxTRANSLATE( "Nordic (ISO-8859-10)" ),
122 wxTRANSLATE( "Thai (ISO-8859-11)" ),
123 wxTRANSLATE( "Indian (ISO-8859-12)" ),
124 wxTRANSLATE( "Baltic (ISO-8859-13)" ),
125 wxTRANSLATE( "Celtic (ISO-8859-14)" ),
126 wxTRANSLATE( "Western European with Euro (ISO-8859-15)" ),
127 wxTRANSLATE( "KOI8-R" ),
128 wxTRANSLATE( "Windows Japanese (CP 932)" ),
129 wxTRANSLATE( "Windows Chinese Simplified (CP 936)" ),
130 wxTRANSLATE( "Windows Korean (CP 949)" ),
131 wxTRANSLATE( "Windows Chinese Traditional (CP 950)" ),
132 wxTRANSLATE( "Windows Central European (CP 1250)" ),
133 wxTRANSLATE( "Windows Cyrillic (CP 1251)" ),
134 wxTRANSLATE( "Windows Western European (CP 1252)" ),
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)" ),
140 wxTRANSLATE( "Windows/DOS OEM (CP 437)" ),
141 wxTRANSLATE( "Unicode 7 bit (UTF-7)" ),
142 wxTRANSLATE( "Unicode 8 bit (UTF-8)" ),
143 };
144
145 // and the internal names (these are not translated on purpose!)
146 static const wxChar* gs_encodingNames[] =
147 {
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" ),
163 wxT( "koi8-r" ),
164 wxT( "windows-932" ),
165 wxT( "windows-936" ),
166 wxT( "windows-949" ),
167 wxT( "windows-950" ),
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" ),
177 wxT( "utf-7" ),
178 wxT( "utf-8" ),
179 };
180
181
182 // ----------------------------------------------------------------------------
183 // private classes
184 // ----------------------------------------------------------------------------
185
186 // change the config path during the lifetime of this object
187 class wxFontMapperPathChanger
188 {
189 public:
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
204 private:
205 wxFontMapper *m_fontMapper;
206 bool m_ok;
207 wxString m_pathOld;
208 };
209
210 // ============================================================================
211 // implementation
212 // ============================================================================
213
214 // ----------------------------------------------------------------------------
215 // ctor and dtor
216 // ----------------------------------------------------------------------------
217
218 wxFontMapper::wxFontMapper()
219 {
220 #if wxUSE_CONFIG
221 m_config = NULL;
222 m_configIsDummy = FALSE;
223 #endif // wxUSE_CONFIG
224
225 #if wxUSE_GUI
226 m_windowParent = NULL;
227 #endif // wxUSE_GUI
228 }
229
230 wxFontMapper::~wxFontMapper()
231 {
232 #if wxUSE_CONFIG
233 if ( m_configIsDummy )
234 delete m_config;
235 #endif // wxUSE_CONFIG
236 }
237
238 wxFontMapper *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
254 class wxFontMapperModule: public wxModule
255 {
256 public:
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
264 IMPLEMENT_DYNAMIC_CLASS(wxFontMapperModule, wxModule)
265
266 // ----------------------------------------------------------------------------
267 // customisation
268 // ----------------------------------------------------------------------------
269
270 #if wxUSE_CONFIG
271
272 /* static */ const wxChar *wxFontMapper::GetDefaultConfigPath()
273 {
274 return FONTMAPPER_ROOT_PATH;
275 }
276
277 void wxFontMapper::SetConfigPath(const wxString& prefix)
278 {
279 wxCHECK_RET( !prefix.IsEmpty() && prefix[0] == wxCONFIG_PATH_SEPARATOR,
280 wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") );
281
282 m_configRootPath = prefix;
283 }
284
285 // ----------------------------------------------------------------------------
286 // get config object and path for it
287 // ----------------------------------------------------------------------------
288
289 wxConfigBase *wxFontMapper::GetConfig()
290 {
291 if ( !m_config )
292 {
293 // try the default
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;
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())
309 }
310 }
311
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.
316 delete m_config;
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
321 // either doesn't use wxConfig at all or creates wxConfig object in
322 // wxApp::OnInit(), before any real interaction with the user takes
323 // place...
324 }
325
326 return m_config;
327 }
328
329 const wxString& wxFontMapper::GetConfigPath()
330 {
331 if ( !m_configRootPath )
332 {
333 // use the default
334 m_configRootPath = GetDefaultConfigPath();
335 }
336
337 return m_configRootPath;
338 }
339 #endif
340
341 bool wxFontMapper::ChangePath(const wxString& pathNew, wxString *pathOld)
342 {
343 #if wxUSE_CONFIG
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),
357 wxT("should be a relative path") );
358
359 path += pathNew;
360
361 config->SetPath(path);
362
363 return TRUE;
364 #else
365 return FALSE;
366 #endif
367 }
368
369 void wxFontMapper::RestorePath(const wxString& pathOld)
370 {
371 #if wxUSE_CONFIG
372 GetConfig()->SetPath(pathOld);
373 #else
374 #endif
375 }
376
377 // ----------------------------------------------------------------------------
378 // charset/encoding correspondence
379 // ----------------------------------------------------------------------------
380
381 /* static */
382 wxString wxFontMapper::GetEncodingDescription(wxFontEncoding encoding)
383 {
384 if ( encoding == wxFONTENCODING_DEFAULT )
385 {
386 return _("Default encoding");
387 }
388
389 size_t count = WXSIZEOF(gs_encodingDescs);
390
391 wxASSERT_MSG( count == WXSIZEOF(gs_encodings),
392 wxT("inconsitency detected - forgot to update one of the arrays?") );
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 */
409 wxString wxFontMapper::GetEncodingName(wxFontEncoding encoding)
410 {
411 if ( encoding == wxFONTENCODING_DEFAULT )
412 {
413 return _("default");
414 }
415
416 size_t count = WXSIZEOF(gs_encodingNames);
417
418 wxASSERT_MSG( count == WXSIZEOF(gs_encodings),
419 wxT("inconsistency detected - forgot to update one of the arrays?") );
420
421 for ( size_t i = 0; i < count; i++ )
422 {
423 if ( gs_encodings[i] == encoding )
424 {
425 return gs_encodingNames[i];
426 }
427 }
428
429 wxString str;
430 str.Printf(_("unknown-%d"), encoding);
431
432 return str;
433 }
434
435 wxFontEncoding wxFontMapper::CharsetToEncoding(const wxString& charset,
436 bool interactive)
437 {
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
444 wxFontEncoding encoding = wxFONTENCODING_SYSTEM;
445
446 // we're going to modify it, make a copy
447 wxString cs = charset;
448
449 #if wxUSE_CONFIG
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 {
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
466 if ( value >= 0 && value <= wxFONTENCODING_MAX )
467 {
468 encoding = (wxFontEncoding)value;
469 }
470 else
471 {
472 wxLogDebug(wxT("corrupted config data: invalid encoding %ld for charset '%s' ignored"),
473 value, charset.c_str());
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 }
492 #endif // wxUSE_CONFIG
493
494 // if didn't find it there, try to recognize it ourselves
495 if ( encoding == wxFONTENCODING_SYSTEM )
496 {
497 // trim any spaces
498 cs.Trim(TRUE);
499 cs.Trim(FALSE);
500
501 // discard the optional quotes
502 if ( !cs.empty() )
503 {
504 if ( cs[0u] == _T('"') && cs.Last() == _T('"') )
505 {
506 cs = wxString(cs.c_str(), cs.length() - 1);
507 }
508 }
509
510 cs.MakeUpper();
511
512 if ( cs.empty() || cs == _T("US-ASCII") )
513 {
514 encoding = wxFONTENCODING_DEFAULT;
515 }
516 else if ( cs == wxT("UTF-7") )
517 {
518 encoding = wxFONTENCODING_UTF7;
519 }
520 else if ( cs == wxT("UTF-8") )
521 {
522 encoding = wxFONTENCODING_UTF8;
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
531 encoding = wxFONTENCODING_KOI8;
532 }
533 else if ( cs.Left(3) == wxT("ISO") )
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;
538 if ( *p == wxT('-') )
539 p++;
540
541 unsigned int value;
542 if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
543 {
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) )
549 {
550 // it's a valid ISO8859 encoding
551 value += wxFONTENCODING_ISO8859_1;
552 encoding = (wxFontEncoding)value;
553 }
554 }
555 }
556 else // check for Windows charsets
557 {
558 size_t len;
559 if ( cs.Left(7) == wxT("WINDOWS") )
560 {
561 len = 7;
562 }
563 else if ( cs.Left(2) == wxT("CP") )
564 {
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 )
580 {
581 if ( value >= 1250 )
582 {
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 }
591 }
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 }
611 }
612 }
613 }
614 //else: unknown
615 }
616
617 #if wxUSE_GUI
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;
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());
631
632 // the list of choices
633 size_t count = WXSIZEOF(gs_encodingDescs);
634
635 wxASSERT_MSG( count == WXSIZEOF(gs_encodings),
636 wxT("inconsitency detected - forgot to update one of the arrays?") );
637
638 wxString *encodingNamesTranslated = new wxString[count];
639
640 for ( size_t i = 0; i < count; i++ )
641 {
642 encodingNamesTranslated[i] = wxGetTranslation(gs_encodingDescs[i]);
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 {
660 encoding = gs_encodings[n];
661 }
662
663 #if wxUSE_CONFIG
664 // save the result in the config now
665 if ( ChangePath(FONTMAPPER_CHARSET_PATH, &pathOld) )
666 {
667 wxConfigBase *config = GetConfig();
668
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());
675 }
676
677 RestorePath(pathOld);
678 }
679 #endif // wxUSE_CONFIG
680 }
681 #endif // wxUSE_GUI
682
683 return encoding;
684 }
685
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
692 #if wxUSE_GUI
693
694 bool wxFontMapper::TestAltEncoding(const wxString& configEntry,
695 wxFontEncoding encReplacement,
696 wxNativeEncodingInfo *info)
697 {
698 if ( wxGetNativeFontEncoding(encReplacement, info) &&
699 wxTestFontEncoding(*info) )
700 {
701 #if wxUSE_CONFIG
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 }
709 #endif // wxUSE_CONFIG
710 return TRUE;
711 }
712
713 return FALSE;
714 }
715
716 #if wxUSE_GUI
717 class ReentrancyBlocker
718 {
719 public:
720 ReentrancyBlocker(bool& b) : m_b(b) { m_b = TRUE; }
721 ~ReentrancyBlocker() { m_b = FALSE; }
722
723 private:
724 bool& m_b;
725 };
726 #endif
727
728 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
729 wxNativeEncodingInfo *info,
730 const wxString& facename,
731 bool interactive)
732 {
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
751 wxCHECK_MSG( info, FALSE, wxT("bad pointer in GetAltForEncoding") );
752
753 info->facename = facename;
754
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 {
766 wxLogFatalError(_("can't load any font, aborting"));
767
768 // wxLogFatalError doesn't return
769 }
770
771 wxString configEntry,
772 encName = GetEncodingName(encoding);
773 if ( !!facename )
774 {
775 configEntry = facename + _T("_");
776 }
777 configEntry += encName;
778
779 #if wxUSE_CONFIG
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
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 )
794 {
795 interactive = FALSE;
796 }
797 else // use the info entered the last time
798 {
799 if ( !!fontinfo && !!facename )
800 {
801 // we tried to find a match with facename - now try without it
802 fontinfo = config->Read(encName);
803 }
804
805 if ( !!fontinfo )
806 {
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 }
822 }
823 //else: there is no information in config about this encoding
824 }
825 }
826 #endif // wxUSE_CONFIG
827
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;
833 wxFontEncoding equivEncoding = wxFONTENCODING_SYSTEM;
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
851 // ask the user
852 #if wxUSE_FONTDLG
853 if ( interactive )
854 {
855 wxString title(m_titleDialog);
856 if ( !title )
857 title << wxTheApp->GetAppName() << _(": unknown encoding");
858
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 }
873
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;
877
878 if ( wxMessageBox(msg, title,
879 wxICON_QUESTION | wxYES_NO,
880 m_windowParent) == answer )
881 {
882 wxFontData data;
883 data.SetEncoding(encoding);
884 data.EncodingInfo() = *info;
885 wxFontDialog dialog(m_windowParent, &data);
886 if ( dialog.ShowModal() == wxID_OK )
887 {
888 wxFontData retData = dialog.GetFontData();
889 wxFont font = retData.GetChosenFont();
890
891 *info = retData.EncodingInfo();
892 info->encoding = retData.GetEncoding();
893
894 #if wxUSE_CONFIG
895 // remember this in the config
896 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
897 {
898 GetConfig()->Write(configEntry, info->ToString());
899
900 RestorePath(pathOld);
901 }
902 #endif // wxUSE_CONFIG
903
904 return TRUE;
905 }
906 //else: the user canceled the font selection dialog
907 }
908 else
909 {
910 // the user doesn't want to select a font for this encoding
911 // or selected to use equivalent encoding
912 //
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 {
917 GetConfig()->Write
918 (
919 configEntry,
920 foundEquivEncoding ? info->ToString().c_str()
921 : FONTMAPPER_FONT_DONT_ASK
922 );
923
924 RestorePath(pathOld);
925 }
926 #endif // wxUSE_CONFIG
927 }
928 }
929 //else: we're in non-interactive mode
930 #endif // wxUSE_FONTDLG
931
932 return foundEquivEncoding;
933 }
934
935 bool 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
946 bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding,
947 const wxString& facename)
948 {
949 wxNativeEncodingInfo info;
950
951 if (wxGetNativeFontEncoding(encoding, &info))
952 {
953 info.facename = facename;
954 return wxTestFontEncoding(info);
955 }
956
957 return FALSE;
958 }
959
960 #endif // wxUSE_GUI
961
962 #endif // wxUSE_FONTMAP