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