Updated wxvc_dll.dsp and memory.h to make VC++ compile in DLL mode again
[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 wxChar* FONTMAPPER_ROOT_PATH = wxT("FontMapper");
50 static const wxChar* FONTMAPPER_CHARSET_PATH = wxT("Charsets");
51 static const wxChar* FONTMAPPER_CHARSET_ALIAS_PATH = wxT("Aliases");
52 static const wxChar* FONTMAPPER_FONT_FROM_ENCODING_PATH = wxT("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 wxT( "iso8859-1" ),
116 wxT( "iso8859-2" ),
117 wxT( "iso8859-3" ),
118 wxT( "iso8859-4" ),
119 wxT( "iso8859-5" ),
120 wxT( "iso8859-6" ),
121 wxT( "iso8859-7" ),
122 wxT( "iso8859-8" ),
123 wxT( "iso8859-9" ),
124 wxT( "iso8859-10" ),
125 wxT( "iso8859-11" ),
126 wxT( "iso8859-12" ),
127 wxT( "iso8859-13" ),
128 wxT( "iso8859-14" ),
129 wxT( "iso8859-15" ),
130 wxT( "koi8-r" ),
131 wxT( "windows1250" ),
132 wxT( "windows1251" ),
133 wxT( "windows1252" ),
134 wxT( "windows1253" ),
135 wxT( "windows1254" ),
136 wxT( "windows1255" ),
137 wxT( "windows1256" ),
138 wxT( "windows1257" ),
139 };
140
141 // ----------------------------------------------------------------------------
142 // global data
143 // ----------------------------------------------------------------------------
144
145 // private object
146 static wxFontMapper gs_fontMapper;
147
148 // and public pointer
149 wxFontMapper * 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 wxT("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 wxT("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 wxT("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 wxT("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(wxT("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 == wxT("US-ASCII") )
372 encoding = wxFONTENCODING_DEFAULT;
373 else if ( cs == wxT("KOI8-R") || cs == wxT("KOI8-U") )
374 encoding = wxFONTENCODING_KOI8;
375 else if ( cs.Left(3) == wxT("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 == wxT('-') )
381 p++;
382
383 unsigned int value;
384 if ( wxSscanf(p, wxT("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) == wxT("WINDOWS-") )
396 {
397 int value;
398 if ( wxSscanf(cs.c_str() + 8, wxT("%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 wxT("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, wxT("bad pointer in GetAltForEncoding") );
503
504 if ( encoding == wxFONTENCODING_DEFAULT )
505 {
506 encoding = wxFont::GetDefaultEncoding();
507 }
508
509 // if we failed to load the system default encoding, something is really
510 // wrong and we'd better stop now - otherwise we will go into endless
511 // recursion trying to create the font in the msg box with the error
512 // message
513 if ( encoding == wxFONTENCODING_SYSTEM )
514 {
515 wxFatalError(_("can't load any font, aborting"));
516
517 // wxFatalError doesn't return
518 }
519
520 wxString configEntry = GetEncodingName(encoding);
521
522 // do we have a font spec for this encoding?
523 wxString pathOld;
524 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
525 {
526 wxConfigBase *config = GetConfig();
527
528 wxString fontinfo = config->Read(configEntry);
529
530 RestorePath(pathOld);
531
532 if ( !!fontinfo )
533 {
534 if ( info->FromString(fontinfo) )
535 {
536 if ( wxTestFontEncoding(*info) )
537 {
538 // ok, got something
539 return TRUE;
540 }
541 //else: no such fonts, look for something else
542 }
543 else
544 {
545 wxLogDebug(wxT("corrupted config data: string '%s' is not "
546 "a valid font encoding info"), fontinfo.c_str());
547 }
548 }
549 }
550
551 // ask the user
552 if ( interactive )
553 {
554 wxString title(m_titleDialog);
555 if ( !title )
556 title << wxTheApp->GetAppName() << _(": unknown encoding");
557
558 // the message
559 wxString msg;
560 msg.Printf(_("The encoding '%s' is unknown.\n"
561 "Would you like to select a font to be used for this "
562 "encoding\n"
563 "(otherwise the text in this encoding will not be "
564 "shown correctly)?"),
565 GetEncodingDescription(encoding).c_str());
566
567 wxWindow *parent = m_windowParent;
568 if ( !parent )
569 parent = wxTheApp->GetTopWindow();
570
571 if ( wxMessageBox(msg, title,
572 wxICON_QUESTION | wxYES_NO, parent) == wxYES )
573 {
574 wxFontData data;
575 data.SetEncoding(encoding);
576 data.EncodingInfo() = *info;
577 wxFontDialog dialog(parent, &data);
578 if ( dialog.ShowModal() == wxID_OK )
579 {
580 wxFontData retData = dialog.GetFontData();
581 wxFont font = retData.GetChosenFont();
582
583 *info = retData.EncodingInfo();
584
585 // remember this in the config
586 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
587 {
588 GetConfig()->Write(configEntry, info->ToString());
589
590 RestorePath(pathOld);
591 }
592
593 return TRUE;
594 }
595 //else: the user canceled the font selection dialog
596 }
597 //else: the user doesn't want to select a font
598 }
599 //else: we're in non-interactive mode
600
601 // now try the default mappings
602 switch ( encoding )
603 {
604 case wxFONTENCODING_ISO8859_15:
605 // iso8859-15 is slightly modified iso8859-1
606 if ( TestAltEncoding(configEntry, wxFONTENCODING_ISO8859_1, info) )
607 return TRUE;
608 // fall through
609
610 case wxFONTENCODING_ISO8859_1:
611 // iso8859-1 is identical to CP1252
612 if ( TestAltEncoding(configEntry, wxFONTENCODING_CP1252, info) )
613 return TRUE;
614
615 break;
616
617 case wxFONTENCODING_CP1252:
618 if ( TestAltEncoding(configEntry, wxFONTENCODING_ISO8859_1, info) )
619 return TRUE;
620
621 break;
622
623 // iso8859-13 is quite similar to WinBaltic
624 case wxFONTENCODING_ISO8859_13:
625 if ( TestAltEncoding(configEntry, wxFONTENCODING_CP1257, info) )
626 return TRUE;
627
628 break;
629
630 case wxFONTENCODING_CP1257:
631 if ( TestAltEncoding(configEntry, wxFONTENCODING_ISO8859_13, info) )
632 return TRUE;
633
634 break;
635
636 // iso8859-8 is almost identical to WinHebrew
637 case wxFONTENCODING_ISO8859_8:
638 if ( TestAltEncoding(configEntry, wxFONTENCODING_CP1255, info) )
639 return TRUE;
640
641 break;
642
643 case wxFONTENCODING_CP1255:
644 if ( TestAltEncoding(configEntry, wxFONTENCODING_ISO8859_8, info) )
645 return TRUE;
646
647 break;
648
649 // and iso8859-7 is not too different from WinGreek
650 case wxFONTENCODING_ISO8859_7:
651 if ( TestAltEncoding(configEntry, wxFONTENCODING_CP1253, info) )
652 return TRUE;
653
654 break;
655
656 case wxFONTENCODING_CP1253:
657 if ( TestAltEncoding(configEntry, wxFONTENCODING_ISO8859_7, info) )
658 return TRUE;
659
660 break;
661
662 default:
663 // TODO add other mappings...
664 ;
665 }
666
667 return FALSE;
668 }