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