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