]> git.saurik.com Git - wxWidgets.git/blob - src/common/fontmap.cpp
Mingw32 fixes
[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 #ifndef WX_PRECOMP
32 #include "wx/app.h"
33 #include "wx/log.h"
34 #include "wx/intl.h"
35 #endif // PCH
36
37 #include "wx/fontmap.h"
38
39 #if wxUSE_CONFIG
40 #include "wx/config.h"
41 #include "wx/memconf.h"
42 #endif
43
44 #if wxUSE_GUI
45 #include "wx/msgdlg.h"
46 #include "wx/fontdlg.h"
47 #include "wx/choicdlg.h"
48 #endif // wxUSE_GUI
49
50 #include "wx/encconv.h"
51
52 // ----------------------------------------------------------------------------
53 // constants
54 // ----------------------------------------------------------------------------
55
56 // the config paths we use
57 static const wxChar* FONTMAPPER_ROOT_PATH = wxT("wxWindows/FontMapper");
58 static const wxChar* FONTMAPPER_CHARSET_PATH = wxT("Charsets");
59 static const wxChar* FONTMAPPER_CHARSET_ALIAS_PATH = wxT("Aliases");
60 #if wxUSE_GUI
61 static const wxChar* FONTMAPPER_FONT_FROM_ENCODING_PATH = wxT("Encodings");
62 #endif // wxUSE_GUI
63
64 // encodings supported by GetEncodingDescription
65 static wxFontEncoding gs_encodings[] =
66 {
67 wxFONTENCODING_ISO8859_1,
68 wxFONTENCODING_ISO8859_2,
69 wxFONTENCODING_ISO8859_3,
70 wxFONTENCODING_ISO8859_4,
71 wxFONTENCODING_ISO8859_5,
72 wxFONTENCODING_ISO8859_6,
73 wxFONTENCODING_ISO8859_7,
74 wxFONTENCODING_ISO8859_8,
75 wxFONTENCODING_ISO8859_9,
76 wxFONTENCODING_ISO8859_10,
77 wxFONTENCODING_ISO8859_11,
78 wxFONTENCODING_ISO8859_12,
79 wxFONTENCODING_ISO8859_13,
80 wxFONTENCODING_ISO8859_14,
81 wxFONTENCODING_ISO8859_15,
82 wxFONTENCODING_KOI8,
83 wxFONTENCODING_CP1250,
84 wxFONTENCODING_CP1251,
85 wxFONTENCODING_CP1252,
86 wxFONTENCODING_CP1253,
87 wxFONTENCODING_CP1254,
88 wxFONTENCODING_CP1255,
89 wxFONTENCODING_CP1256,
90 wxFONTENCODING_CP1257,
91 wxFONTENCODING_CP437,
92 };
93
94 // the descriptions for them
95 static const wxChar* gs_encodingDescs[] =
96 {
97 wxTRANSLATE( "West European (ISO-8859-1/Latin 1)" ),
98 wxTRANSLATE( "Central European (ISO-8859-2/Latin 2)" ),
99 wxTRANSLATE( "Esperanto (ISO-8859-3)" ),
100 wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ),
101 wxTRANSLATE( "Cyrillic (Latin 5)" ),
102 wxTRANSLATE( "Arabic (ISO-8859-6)" ),
103 wxTRANSLATE( "Greek (ISO-8859-7)" ),
104 wxTRANSLATE( "Hebrew (ISO-8859-8)" ),
105 wxTRANSLATE( "Turkish (ISO-8859-9)" ),
106 wxTRANSLATE( "Nordic (ISO-8859-10)" ),
107 wxTRANSLATE( "Thai (ISO-8859-11)" ),
108 wxTRANSLATE( "ISO-8859-12" ),
109 wxTRANSLATE( "Baltic (ISO-8859-13)" ),
110 wxTRANSLATE( "ISO-8859-14" ),
111 wxTRANSLATE( "West European new (ISO-8859-15/Latin 0)" ),
112 wxTRANSLATE( "KOI8-R" ),
113 wxTRANSLATE( "Windows Latin 2 (CP 1250)" ),
114 wxTRANSLATE( "Windows Cyrillic (CP 1251)" ),
115 wxTRANSLATE( "Windows Latin 1 (CP 1252)" ),
116 wxTRANSLATE( "Windows Greek (CP 1253)" ),
117 wxTRANSLATE( "Windows Turkish (CP 1254)" ),
118 wxTRANSLATE( "Windows Hebrew (CP 1255)" ),
119 wxTRANSLATE( "Windows Arabic (CP 1256)" ),
120 wxTRANSLATE( "Windows Baltic (CP 1257)" ),
121 wxTRANSLATE( "Windows/DOS OEM (CP 437)" ),
122 };
123
124 // and the internal names
125 static const wxChar* gs_encodingNames[] =
126 {
127 wxT( "iso8859-1" ),
128 wxT( "iso8859-2" ),
129 wxT( "iso8859-3" ),
130 wxT( "iso8859-4" ),
131 wxT( "iso8859-5" ),
132 wxT( "iso8859-6" ),
133 wxT( "iso8859-7" ),
134 wxT( "iso8859-8" ),
135 wxT( "iso8859-9" ),
136 wxT( "iso8859-10" ),
137 wxT( "iso8859-11" ),
138 wxT( "iso8859-12" ),
139 wxT( "iso8859-13" ),
140 wxT( "iso8859-14" ),
141 wxT( "iso8859-15" ),
142 wxT( "koi8-r" ),
143 wxT( "windows1250" ),
144 wxT( "windows1251" ),
145 wxT( "windows1252" ),
146 wxT( "windows1253" ),
147 wxT( "windows1254" ),
148 wxT( "windows1255" ),
149 wxT( "windows1256" ),
150 wxT( "windows1257" ),
151 wxT( "windows437" ),
152 };
153
154 // ----------------------------------------------------------------------------
155 // global data
156 // ----------------------------------------------------------------------------
157
158 // private object
159 static wxFontMapper gs_fontMapper;
160
161 // and public pointer
162 wxFontMapper * wxTheFontMapper = &gs_fontMapper;
163
164 // ----------------------------------------------------------------------------
165 // private classes
166 // ----------------------------------------------------------------------------
167
168 // change the config path during the lifetime of this object
169 class wxFontMapperPathChanger
170 {
171 public:
172 wxFontMapperPathChanger(wxFontMapper *fontMapper, const wxString& path)
173 {
174 m_fontMapper = fontMapper;
175 m_ok = m_fontMapper->ChangePath(path, &m_pathOld);
176 }
177
178 bool IsOk() const { return m_ok; }
179
180 ~wxFontMapperPathChanger()
181 {
182 if ( IsOk() )
183 m_fontMapper->RestorePath(m_pathOld);
184 }
185
186 private:
187 wxFontMapper *m_fontMapper;
188 bool m_ok;
189 wxString m_pathOld;
190 };
191
192 // ============================================================================
193 // implementation
194 // ============================================================================
195
196 // ----------------------------------------------------------------------------
197 // ctor and dtor
198 // ----------------------------------------------------------------------------
199
200 wxFontMapper::wxFontMapper()
201 {
202 #if wxUSE_CONFIG
203 m_config = NULL;
204 #endif // wxUSE_CONFIG
205
206 #if wxUSE_GUI
207 m_windowParent = NULL;
208 #endif // wxUSE_GUI
209 }
210
211 wxFontMapper::~wxFontMapper()
212 {
213 }
214
215 // ----------------------------------------------------------------------------
216 // customisation
217 // ----------------------------------------------------------------------------
218
219 #if wxUSE_CONFIG
220
221 /* static */ const wxChar *wxFontMapper::GetDefaultConfigPath()
222 {
223 return FONTMAPPER_ROOT_PATH;
224 }
225
226 void wxFontMapper::SetConfigPath(const wxString& prefix)
227 {
228 wxCHECK_RET( !prefix.IsEmpty() && prefix[0] == wxCONFIG_PATH_SEPARATOR,
229 wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") );
230
231 m_configRootPath = prefix;
232 }
233
234 // ----------------------------------------------------------------------------
235 // get config object and path for it
236 // ----------------------------------------------------------------------------
237
238 wxConfigBase *wxFontMapper::GetConfig()
239 {
240 if ( !m_config )
241 {
242 // try the default
243 m_config = wxConfig::Get(FALSE /*don't create on demand*/ );
244
245 if ( !m_config )
246 {
247 // we still want to have a config object because otherwise we would
248 // keep asking the user the same questions in the interactive mode,
249 // so create a dummy config which won't write to any files/registry
250 // but will allow us to remember the results of the questions at
251 // least during this run
252 m_config = new wxMemoryConfig;
253 wxConfig::Set(m_config);
254 }
255 }
256
257 return m_config;
258 }
259
260 const wxString& wxFontMapper::GetConfigPath()
261 {
262 if ( !m_configRootPath )
263 {
264 // use the default
265 m_configRootPath = GetDefaultConfigPath();
266 }
267
268 return m_configRootPath;
269 }
270 #endif
271
272 bool wxFontMapper::ChangePath(const wxString& pathNew, wxString *pathOld)
273 {
274 #if wxUSE_CONFIG
275 wxConfigBase *config = GetConfig();
276 if ( !config )
277 return FALSE;
278
279 *pathOld = config->GetPath();
280
281 wxString path = GetConfigPath();
282 if ( path.IsEmpty() || path.Last() != wxCONFIG_PATH_SEPARATOR )
283 {
284 path += wxCONFIG_PATH_SEPARATOR;
285 }
286
287 wxASSERT_MSG( !pathNew || (pathNew[0] != wxCONFIG_PATH_SEPARATOR),
288 wxT("should be a relative path") );
289
290 path += pathNew;
291
292 config->SetPath(path);
293
294 return TRUE;
295 #else
296 return FALSE;
297 #endif
298 }
299
300 void wxFontMapper::RestorePath(const wxString& pathOld)
301 {
302 #if wxUSE_CONFIG
303 GetConfig()->SetPath(pathOld);
304 #else
305 #endif
306 }
307
308 // ----------------------------------------------------------------------------
309 // charset/encoding correspondence
310 // ----------------------------------------------------------------------------
311
312 /* static */
313 wxString wxFontMapper::GetEncodingDescription(wxFontEncoding encoding)
314 {
315 size_t count = WXSIZEOF(gs_encodingDescs);
316
317 wxASSERT_MSG( count == WXSIZEOF(gs_encodings),
318 wxT("inconsitency detected - forgot to update one of the arrays?") );
319
320 for ( size_t i = 0; i < count; i++ )
321 {
322 if ( gs_encodings[i] == encoding )
323 {
324 return wxGetTranslation(gs_encodingDescs[i]);
325 }
326 }
327
328 wxString str;
329 str.Printf(_("Unknown encoding (%d)"), encoding);
330
331 return str;
332 }
333
334 /* static */
335 wxString wxFontMapper::GetEncodingName(wxFontEncoding encoding)
336 {
337 size_t count = WXSIZEOF(gs_encodingNames);
338
339 wxASSERT_MSG( count == WXSIZEOF(gs_encodings),
340 wxT("inconsistency detected - forgot to update one of the arrays?") );
341
342 for ( size_t i = 0; i < count; i++ )
343 {
344 if ( gs_encodings[i] == encoding )
345 {
346 return wxGetTranslation(gs_encodingNames[i]);
347 }
348 }
349
350 wxString str;
351 str.Printf(_("unknown-%d"), encoding);
352
353 return str;
354 }
355
356 wxFontEncoding wxFontMapper::CharsetToEncoding(const wxString& charset,
357 bool interactive)
358 {
359 wxFontEncoding encoding = wxFONTENCODING_SYSTEM;
360
361 // we're going to modify it, make a copy
362 wxString cs = charset;
363
364 #if wxUSE_CONFIG
365 // first try the user-defined settings
366 wxString pathOld;
367 if ( ChangePath(FONTMAPPER_CHARSET_PATH, &pathOld) )
368 {
369 wxConfigBase *config = GetConfig();
370
371 // do we have an encoding for this charset?
372 long value = config->Read(charset, -1l);
373 if ( value != -1 )
374 {
375 if ( value >= 0 && value <= wxFONTENCODING_MAX )
376 {
377 encoding = (wxFontEncoding)value;
378 }
379 else
380 {
381 wxLogDebug(wxT("corrupted config data: invalid encoding %ld for charset '%s' ignored"),
382 value, charset.c_str());
383 }
384 }
385
386 if ( encoding == wxFONTENCODING_SYSTEM )
387 {
388 // may be we have an alias?
389 config->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH);
390
391 wxString alias = config->Read(charset);
392 if ( !!alias )
393 {
394 // yes, we do - use it instead
395 cs = alias;
396 }
397 }
398
399 RestorePath(pathOld);
400 }
401 #endif
402
403 // if didn't find it there, try to reckognise it ourselves
404 if ( encoding == wxFONTENCODING_SYSTEM )
405 {
406 cs.MakeUpper();
407
408 if ( !cs || cs == wxT("US-ASCII") )
409 encoding = wxFONTENCODING_DEFAULT;
410 else if ( cs == wxT("KOI8-R") || cs == wxT("KOI8-U") )
411 encoding = wxFONTENCODING_KOI8;
412 else if ( cs.Left(3) == wxT("ISO") )
413 {
414 // the dash is optional (or, to be exact, it is not, but
415 // several brokenmails "forget" it)
416 const wxChar *p = cs.c_str() + 3;
417 if ( *p == wxT('-') )
418 p++;
419
420 unsigned int value;
421 if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
422 {
423 if ( value < wxFONTENCODING_ISO8859_MAX -
424 wxFONTENCODING_ISO8859_1 )
425 {
426 // it's a valid ISO8859 encoding
427 value += wxFONTENCODING_ISO8859_1 - 1;
428 encoding = (wxFontEncoding)value;
429 }
430 }
431 }
432 else if ( cs.Left(8) == wxT("WINDOWS-") )
433 {
434 int value;
435 if ( wxSscanf(cs.c_str() + 8, wxT("%u"), &value) == 1 )
436 {
437 if ( value >= 1250 )
438 {
439 value -= 1250;
440 if ( value < wxFONTENCODING_CP12_MAX -
441 wxFONTENCODING_CP1250 - 1 )
442 {
443 // a valid Windows code page
444 value += wxFONTENCODING_CP1250;
445 encoding = (wxFontEncoding)value;
446 }
447 }
448 }
449 }
450 //else: unknown
451 }
452
453 #if wxUSE_GUI
454 // if still no luck, ask the user - unless disabled
455 if ( (encoding == wxFONTENCODING_SYSTEM) && interactive )
456 {
457 // prepare the dialog data
458
459 // the dialog title
460 wxString title(m_titleDialog);
461 if ( !title )
462 title << wxTheApp->GetAppName() << _(": unknown charset");
463
464 // the message
465 wxString msg;
466 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());
467
468 // the list of choices
469 size_t count = WXSIZEOF(gs_encodingDescs);
470
471 wxASSERT_MSG( count == WXSIZEOF(gs_encodings),
472 wxT("inconsitency detected - forgot to update one of the arrays?") );
473
474 wxString *encodingNamesTranslated = new wxString[count];
475
476 for ( size_t i = 0; i < count; i++ )
477 {
478 encodingNamesTranslated[i] = wxGetTranslation(gs_encodingDescs[i]);
479 }
480
481 // the parent window
482 wxWindow *parent = m_windowParent;
483 if ( !parent )
484 parent = wxTheApp->GetTopWindow();
485
486 // do ask the user and get back the index in encodings table
487 int n = wxGetSingleChoiceIndex(msg, title,
488 count,
489 encodingNamesTranslated,
490 parent);
491
492 delete [] encodingNamesTranslated;
493
494 if ( n != -1 )
495 {
496 encoding = gs_encodings[n];
497
498 #if wxUSE_CONFIG
499 // save the result in the config now
500 if ( ChangePath(FONTMAPPER_CHARSET_PATH, &pathOld) )
501 {
502 wxConfigBase *config = GetConfig();
503
504 // remember the alt encoding for this charset
505 if ( !config->Write(charset, (long)encoding) )
506 {
507 wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset.c_str());
508 }
509
510 RestorePath(pathOld);
511 }
512 #endif // wxUSE_CONFIG
513 }
514 //else: cancelled
515 }
516 #endif // wxUSE_GUI
517
518 return encoding;
519 }
520
521 // ----------------------------------------------------------------------------
522 // support for unknown encodings: we maintain a map between the
523 // (platform-specific) strings identifying them and our wxFontEncodings they
524 // correspond to which is used by GetFontForEncoding() function
525 // ----------------------------------------------------------------------------
526
527 #if wxUSE_GUI
528
529 bool wxFontMapper::TestAltEncoding(const wxString& configEntry,
530 wxFontEncoding encReplacement,
531 wxNativeEncodingInfo *info)
532 {
533 if ( wxGetNativeFontEncoding(encReplacement, info) &&
534 wxTestFontEncoding(*info) )
535 {
536 #if wxUSE_CONFIG
537 // remember the mapping in the config
538 wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH);
539
540 if ( path.IsOk() )
541 {
542 GetConfig()->Write(configEntry, info->ToString());
543 }
544 #endif // wxUSE_CONFIG
545 return TRUE;
546 }
547
548 return FALSE;
549 }
550
551 #if wxUSE_GUI
552 class ReentrancyBlocker
553 {
554 public:
555 ReentrancyBlocker(bool& b) : m_b(b) { m_b = TRUE; }
556 ~ReentrancyBlocker() { m_b = FALSE; }
557
558 private:
559 bool& m_b;
560 };
561 #endif
562
563 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
564 wxNativeEncodingInfo *info,
565 const wxString& facename,
566 bool interactive)
567 {
568 #if wxUSE_GUI
569 // we need a flag to prevent infinite recursion which happens, for
570 // example, when GetAltForEncoding() is called from an OnPaint() handler:
571 // in this case, wxYield() which is called from wxMessageBox() we use here
572 // will lead to another call of OnPaint() and hence to another call of
573 // GetAltForEncoding() - and it is impossible to catch this from the user
574 // code because we are called from wxFont ctor implicitly.
575
576 // assume we're always called from the main thread, so that it is safe to
577 // use a static var
578 static bool s_inGetAltForEncoding = FALSE;
579
580 if ( interactive && s_inGetAltForEncoding )
581 return FALSE;
582
583 ReentrancyBlocker blocker(s_inGetAltForEncoding);
584 #endif // wxUSE_GUI
585
586 wxCHECK_MSG( info, FALSE, wxT("bad pointer in GetAltForEncoding") );
587
588 info->facename = facename;
589
590 if ( encoding == wxFONTENCODING_DEFAULT )
591 {
592 encoding = wxFont::GetDefaultEncoding();
593 }
594
595 // if we failed to load the system default encoding, something is really
596 // wrong and we'd better stop now - otherwise we will go into endless
597 // recursion trying to create the font in the msg box with the error
598 // message
599 if ( encoding == wxFONTENCODING_SYSTEM )
600 {
601 wxFatalError(_("can't load any font, aborting"));
602
603 // wxFatalError doesn't return
604 }
605
606 wxString configEntry, encName = GetEncodingName(encoding);
607 if ( !!facename )
608 {
609 configEntry = facename + _T("_");
610 }
611 configEntry += encName;
612
613 #if wxUSE_CONFIG
614 // do we have a font spec for this encoding?
615 wxString pathOld;
616 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
617 {
618 wxConfigBase *config = GetConfig();
619
620 wxString fontinfo = config->Read(configEntry);
621
622 RestorePath(pathOld);
623
624 if ( !!fontinfo && !!facename )
625 {
626 // we tried to find a match with facename - now try without it
627 fontinfo = config->Read(encName);
628 }
629
630 if ( !!fontinfo )
631 {
632 if ( info->FromString(fontinfo) )
633 {
634 if ( wxTestFontEncoding(*info) )
635 {
636 // ok, got something
637 return TRUE;
638 }
639 //else: no such fonts, look for something else
640 }
641 else
642 {
643 wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"), fontinfo.c_str());
644 }
645 }
646 //else: there is no information in config about this encoding
647 }
648 #endif // wxUSE_CONFIG
649
650 // ask the user
651 if ( interactive )
652 {
653 wxString title(m_titleDialog);
654 if ( !title )
655 title << wxTheApp->GetAppName() << _(": unknown encoding");
656
657 // the message
658 wxString msg;
659 msg.Printf(_("The encoding '%s' is unknown.\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)?"),
660 GetEncodingDescription(encoding).c_str());
661
662 wxWindow *parent = m_windowParent;
663 if ( !parent )
664 parent = wxTheApp->GetTopWindow();
665
666 if ( wxMessageBox(msg, title,
667 wxICON_QUESTION | wxYES_NO, parent) == wxYES )
668 {
669 wxFontData data;
670 data.SetEncoding(encoding);
671 data.EncodingInfo() = *info;
672 wxFontDialog dialog(parent, &data);
673 if ( dialog.ShowModal() == wxID_OK )
674 {
675 wxFontData retData = dialog.GetFontData();
676 wxFont font = retData.GetChosenFont();
677
678 *info = retData.EncodingInfo();
679 info -> encoding = retData.GetEncoding();
680
681 #if wxUSE_CONFIG
682 // remember this in the config
683 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
684 {
685 GetConfig()->Write(configEntry, info->ToString());
686
687 RestorePath(pathOld);
688 }
689 #endif
690
691 return TRUE;
692 }
693 //else: the user canceled the font selection dialog
694 }
695 //else: the user doesn't want to select a font
696 }
697 //else: we're in non-interactive mode
698
699 // now try the default mappings:
700 wxFontEncodingArray equiv = wxEncodingConverter::GetAllEquivalents(encoding);
701 size_t count = equiv.GetCount();
702 for ( size_t i = (equiv[0] == encoding) ? 1 : 0; i < count; i++ )
703 {
704 if ( TestAltEncoding(configEntry, equiv[i], info) )
705 return TRUE;
706 }
707
708 return FALSE;
709 }
710
711 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
712 wxFontEncoding *alt_encoding,
713 const wxString& facename,
714 bool interactive)
715 {
716 wxNativeEncodingInfo info;
717 bool r = GetAltForEncoding(encoding, &info, facename, interactive);
718 *alt_encoding = info.encoding;
719 return r;
720 }
721
722 bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding,
723 const wxString& facename)
724 {
725 wxNativeEncodingInfo info;
726
727 if (wxGetNativeFontEncoding(encoding, &info))
728 {
729 info.facename = facename;
730 return wxTestFontEncoding(info);
731 }
732 else
733 return FALSE;
734 }
735
736 #endif // wxUSE_GUI