]> git.saurik.com Git - wxWidgets.git/blob - src/common/fontmap.cpp
1. wxFontMapper almost finished
[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 n = 0; n < count; n++ )
442 {
443 encodingNamesTranslated[n] = wxGetTranslation(gs_encodingDescs[n]);
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->xregistry = retData.EncodingInfo().xregistry;
568 info->xencoding = retData.EncodingInfo().xencoding;
569
570 // remember this in the config
571 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
572 {
573 GetConfig()->Write(configEntry, info->ToString());
574
575 RestorePath(pathOld);
576 }
577
578 return TRUE;
579 }
580 //else: the user canceled the font selection dialog
581 }
582 //else: the user doesn't want to select a font
583 }
584 //else: we're in non-interactive mode
585
586 // now try the default mappings
587 switch ( encoding )
588 {
589 case wxFONTENCODING_ISO8859_15:
590 // iso8859-15 is slightly modified iso8859-1
591 if ( TestAltEncoding(configEntry, wxFONTENCODING_ISO8859_1, info) )
592 return TRUE;
593 // fall through
594
595 case wxFONTENCODING_ISO8859_1:
596 // iso8859-1 is identical to CP1252
597 if ( TestAltEncoding(configEntry, wxFONTENCODING_CP1252, info) )
598 return TRUE;
599
600 break;
601
602 case wxFONTENCODING_CP1252:
603 if ( TestAltEncoding(configEntry, wxFONTENCODING_ISO8859_1, info) )
604 return TRUE;
605
606 break;
607
608 // iso8859-13 is quite similar to WinBaltic
609 case wxFONTENCODING_ISO8859_13:
610 if ( TestAltEncoding(configEntry, wxFONTENCODING_CP1257, info) )
611 return TRUE;
612
613 break;
614
615 case wxFONTENCODING_CP1257:
616 if ( TestAltEncoding(configEntry, wxFONTENCODING_ISO8859_13, info) )
617 return TRUE;
618
619 break;
620
621 // iso8859-8 is almost identical to WinHebrew
622 case wxFONTENCODING_ISO8859_8:
623 if ( TestAltEncoding(configEntry, wxFONTENCODING_CP1255, info) )
624 return TRUE;
625
626 break;
627
628 case wxFONTENCODING_CP1255:
629 if ( TestAltEncoding(configEntry, wxFONTENCODING_ISO8859_8, info) )
630 return TRUE;
631
632 break;
633
634 // and iso8859-7 is not too different from WinGreek
635 case wxFONTENCODING_ISO8859_7:
636 if ( TestAltEncoding(configEntry, wxFONTENCODING_CP1253, info) )
637 return TRUE;
638
639 break;
640
641 case wxFONTENCODING_CP1253:
642 if ( TestAltEncoding(configEntry, wxFONTENCODING_ISO8859_7, info) )
643 return TRUE;
644
645 break;
646
647 default:
648 // TODO add other mappings...
649 ;
650 }
651
652 return FALSE;
653 }