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