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