More WinCE mods.
[wxWidgets.git] / src / common / fmapbase.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: common/fmapbase.cpp
3 // Purpose: wxFontMapperBase class implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 21.06.2003 (extracted from common/fontmap.cpp)
7 // RCS-ID: $Id$
8 // Copyright: (c) 1999-2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // License: wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #if wxUSE_FONTMAP
28
29 #ifndef WX_PRECOMP
30 #include "wx/app.h"
31 #include "wx/log.h"
32 #include "wx/intl.h"
33 #endif //WX_PRECOMP
34
35 #if defined(__WXMSW__)
36 #include "wx/msw/private.h" // includes windows.h for LOGFONT
37 #include "wx/msw/winundef.h"
38 #endif
39
40 #include "wx/fontmap.h"
41 #include "wx/fmappriv.h"
42
43 #include "wx/apptrait.h"
44 #include "wx/module.h"
45
46 #if wxUSE_CONFIG
47 #include "wx/config.h"
48 #include "wx/memconf.h"
49 #endif
50
51 // ----------------------------------------------------------------------------
52 // constants
53 // ----------------------------------------------------------------------------
54
55 // encodings supported by GetEncodingDescription
56 static wxFontEncoding gs_encodings[] =
57 {
58 wxFONTENCODING_ISO8859_1,
59 wxFONTENCODING_ISO8859_2,
60 wxFONTENCODING_ISO8859_3,
61 wxFONTENCODING_ISO8859_4,
62 wxFONTENCODING_ISO8859_5,
63 wxFONTENCODING_ISO8859_6,
64 wxFONTENCODING_ISO8859_7,
65 wxFONTENCODING_ISO8859_8,
66 wxFONTENCODING_ISO8859_9,
67 wxFONTENCODING_ISO8859_10,
68 wxFONTENCODING_ISO8859_11,
69 wxFONTENCODING_ISO8859_12,
70 wxFONTENCODING_ISO8859_13,
71 wxFONTENCODING_ISO8859_14,
72 wxFONTENCODING_ISO8859_15,
73 wxFONTENCODING_KOI8,
74 wxFONTENCODING_CP932,
75 wxFONTENCODING_CP936,
76 wxFONTENCODING_CP949,
77 wxFONTENCODING_CP950,
78 wxFONTENCODING_CP1250,
79 wxFONTENCODING_CP1251,
80 wxFONTENCODING_CP1252,
81 wxFONTENCODING_CP1253,
82 wxFONTENCODING_CP1254,
83 wxFONTENCODING_CP1255,
84 wxFONTENCODING_CP1256,
85 wxFONTENCODING_CP1257,
86 wxFONTENCODING_CP437,
87 wxFONTENCODING_UTF7,
88 wxFONTENCODING_UTF8,
89 wxFONTENCODING_EUC_JP,
90 };
91
92 // the descriptions for them
93 static const wxChar* gs_encodingDescs[] =
94 {
95 wxTRANSLATE( "Western European (ISO-8859-1)" ),
96 wxTRANSLATE( "Central European (ISO-8859-2)" ),
97 wxTRANSLATE( "Esperanto (ISO-8859-3)" ),
98 wxTRANSLATE( "Baltic (old) (ISO-8859-4)" ),
99 wxTRANSLATE( "Cyrillic (ISO-8859-5)" ),
100 wxTRANSLATE( "Arabic (ISO-8859-6)" ),
101 wxTRANSLATE( "Greek (ISO-8859-7)" ),
102 wxTRANSLATE( "Hebrew (ISO-8859-8)" ),
103 wxTRANSLATE( "Turkish (ISO-8859-9)" ),
104 wxTRANSLATE( "Nordic (ISO-8859-10)" ),
105 wxTRANSLATE( "Thai (ISO-8859-11)" ),
106 wxTRANSLATE( "Indian (ISO-8859-12)" ),
107 wxTRANSLATE( "Baltic (ISO-8859-13)" ),
108 wxTRANSLATE( "Celtic (ISO-8859-14)" ),
109 wxTRANSLATE( "Western European with Euro (ISO-8859-15)" ),
110 wxTRANSLATE( "KOI8-R" ),
111 wxTRANSLATE( "Windows Japanese (CP 932)" ),
112 wxTRANSLATE( "Windows Chinese Simplified (CP 936)" ),
113 wxTRANSLATE( "Windows Korean (CP 949)" ),
114 wxTRANSLATE( "Windows Chinese Traditional (CP 950)" ),
115 wxTRANSLATE( "Windows Central European (CP 1250)" ),
116 wxTRANSLATE( "Windows Cyrillic (CP 1251)" ),
117 wxTRANSLATE( "Windows Western European (CP 1252)" ),
118 wxTRANSLATE( "Windows Greek (CP 1253)" ),
119 wxTRANSLATE( "Windows Turkish (CP 1254)" ),
120 wxTRANSLATE( "Windows Hebrew (CP 1255)" ),
121 wxTRANSLATE( "Windows Arabic (CP 1256)" ),
122 wxTRANSLATE( "Windows Baltic (CP 1257)" ),
123 wxTRANSLATE( "Windows/DOS OEM (CP 437)" ),
124 wxTRANSLATE( "Unicode 7 bit (UTF-7)" ),
125 wxTRANSLATE( "Unicode 8 bit (UTF-8)" ),
126 wxTRANSLATE( "Extended Unix Codepage for Japanese (EUC-JP)" ),
127 };
128
129 // and the internal names (these are not translated on purpose!)
130 static const wxChar* gs_encodingNames[] =
131 {
132 wxT( "iso-8859-1" ),
133 wxT( "iso-8859-2" ),
134 wxT( "iso-8859-3" ),
135 wxT( "iso-8859-4" ),
136 wxT( "iso-8859-5" ),
137 wxT( "iso-8859-6" ),
138 wxT( "iso-8859-7" ),
139 wxT( "iso-8859-8" ),
140 wxT( "iso-8859-9" ),
141 wxT( "iso-8859-10" ),
142 wxT( "iso-8859-11" ),
143 wxT( "iso-8859-12" ),
144 wxT( "iso-8859-13" ),
145 wxT( "iso-8859-14" ),
146 wxT( "iso-8859-15" ),
147 wxT( "koi8-r" ),
148 wxT( "windows-932" ),
149 wxT( "windows-936" ),
150 wxT( "windows-949" ),
151 wxT( "windows-950" ),
152 wxT( "windows-1250" ),
153 wxT( "windows-1251" ),
154 wxT( "windows-1252" ),
155 wxT( "windows-1253" ),
156 wxT( "windows-1254" ),
157 wxT( "windows-1255" ),
158 wxT( "windows-1256" ),
159 wxT( "windows-1257" ),
160 wxT( "windows-437" ),
161 wxT( "utf-7" ),
162 wxT( "utf-8" ),
163 wxT( "euc-jp" ),
164 };
165
166 wxCOMPILE_TIME_ASSERT( WXSIZEOF(gs_encodingDescs) == WXSIZEOF(gs_encodings) &&
167 WXSIZEOF(gs_encodingNames) == WXSIZEOF(gs_encodings),
168 EncodingsArraysNotInSync );
169
170 // ----------------------------------------------------------------------------
171 // private classes
172 // ----------------------------------------------------------------------------
173
174 // clean up the font mapper object
175 class wxFontMapperModule : public wxModule
176 {
177 public:
178 wxFontMapperModule() : wxModule() { }
179 virtual bool OnInit() { return TRUE; }
180 virtual void OnExit() { delete wxFontMapper::Set(NULL); }
181
182 DECLARE_DYNAMIC_CLASS(wxFontMapperModule)
183 };
184
185 IMPLEMENT_DYNAMIC_CLASS(wxFontMapperModule, wxModule)
186
187
188 // ============================================================================
189 // wxFontMapperBase implementation
190 // ============================================================================
191
192 wxFontMapper *wxFontMapperBase::sm_instance = NULL;
193
194 // ----------------------------------------------------------------------------
195 // ctor and dtor
196 // ----------------------------------------------------------------------------
197
198 wxFontMapperBase::wxFontMapperBase()
199 {
200 #if wxUSE_CONFIG
201 m_config = NULL;
202 m_configIsDummy = FALSE;
203 #endif // wxUSE_CONFIG
204 }
205
206 wxFontMapperBase::~wxFontMapperBase()
207 {
208 #if wxUSE_CONFIG
209 if ( m_configIsDummy )
210 delete m_config;
211 #endif // wxUSE_CONFIG
212 }
213
214 /* static */
215 wxFontMapper *wxFontMapperBase::Get()
216 {
217 if ( !sm_instance )
218 {
219 wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL;
220 if ( traits )
221 {
222 sm_instance = traits->CreateFontMapper();
223
224 wxASSERT_MSG( sm_instance,
225 _T("wxAppTraits::CreateFontMapper() failed") );
226 }
227
228 if ( !sm_instance )
229 {
230 // last resort: we must create something because the existing code
231 // relies on always having a valid font mapper object
232 sm_instance = (wxFontMapper *)new wxFontMapperBase;
233 }
234 }
235
236 return sm_instance;
237 }
238
239 /* static */
240 wxFontMapper *wxFontMapperBase::Set(wxFontMapper *mapper)
241 {
242 wxFontMapper *old = sm_instance;
243 sm_instance = mapper;
244 return old;
245 }
246
247 #if wxUSE_CONFIG
248
249 // ----------------------------------------------------------------------------
250 // config usage customisation
251 // ----------------------------------------------------------------------------
252
253 /* static */
254 const wxChar *wxFontMapperBase::GetDefaultConfigPath()
255 {
256 return FONTMAPPER_ROOT_PATH;
257 }
258
259 void wxFontMapperBase::SetConfigPath(const wxString& prefix)
260 {
261 wxCHECK_RET( !prefix.IsEmpty() && prefix[0] == wxCONFIG_PATH_SEPARATOR,
262 wxT("an absolute path should be given to wxFontMapper::SetConfigPath()") );
263
264 m_configRootPath = prefix;
265 }
266
267 // ----------------------------------------------------------------------------
268 // get config object and path for it
269 // ----------------------------------------------------------------------------
270
271 wxConfigBase *wxFontMapperBase::GetConfig()
272 {
273 if ( !m_config )
274 {
275 // try the default
276 m_config = wxConfig::Get(FALSE /*don't create on demand*/ );
277
278 if ( !m_config )
279 {
280 // we still want to have a config object because otherwise we would
281 // keep asking the user the same questions in the interactive mode,
282 // so create a dummy config which won't write to any files/registry
283 // but will allow us to remember the results of the questions at
284 // least during this run
285 m_config = new wxMemoryConfig;
286 m_configIsDummy = TRUE;
287 // VS: we can't call wxConfig::Set(m_config) here because that would
288 // disable automatic wxConfig instance creation if this code was
289 // called before wxApp::OnInit (this happens in wxGTK -- it sets
290 // default wxFont encoding in wxApp::Initialize())
291 }
292 }
293
294 if ( m_configIsDummy && wxConfig::Get(FALSE) != NULL )
295 {
296 // VS: in case we created dummy m_config (see above), we want to switch back
297 // to the real one as soon as one becomes available.
298 delete m_config;
299 m_config = wxConfig::Get(FALSE);
300 m_configIsDummy = FALSE;
301 // FIXME: ideally, we should add keys from dummy config to the real one now,
302 // but it is a low-priority task because typical wxWin application
303 // either doesn't use wxConfig at all or creates wxConfig object in
304 // wxApp::OnInit(), before any real interaction with the user takes
305 // place...
306 }
307
308 return m_config;
309 }
310
311 const wxString& wxFontMapperBase::GetConfigPath()
312 {
313 if ( !m_configRootPath )
314 {
315 // use the default
316 m_configRootPath = GetDefaultConfigPath();
317 }
318
319 return m_configRootPath;
320 }
321
322 // ----------------------------------------------------------------------------
323 // config helpers
324 // ----------------------------------------------------------------------------
325
326 bool wxFontMapperBase::ChangePath(const wxString& pathNew, wxString *pathOld)
327 {
328 wxConfigBase *config = GetConfig();
329 if ( !config )
330 return FALSE;
331
332 *pathOld = config->GetPath();
333
334 wxString path = GetConfigPath();
335 if ( path.IsEmpty() || path.Last() != wxCONFIG_PATH_SEPARATOR )
336 {
337 path += wxCONFIG_PATH_SEPARATOR;
338 }
339
340 wxASSERT_MSG( !pathNew || (pathNew[0] != wxCONFIG_PATH_SEPARATOR),
341 wxT("should be a relative path") );
342
343 path += pathNew;
344
345 config->SetPath(path);
346
347 return TRUE;
348 }
349
350 void wxFontMapperBase::RestorePath(const wxString& pathOld)
351 {
352 GetConfig()->SetPath(pathOld);
353 }
354
355 // ----------------------------------------------------------------------------
356 // charset/encoding correspondence
357 // ----------------------------------------------------------------------------
358
359 wxFontEncoding
360 wxFontMapperBase::CharsetToEncoding(const wxString& charset,
361 bool WXUNUSED(interactive))
362 {
363 wxFontEncoding encoding = wxFONTENCODING_SYSTEM;
364
365 // we're going to modify it, make a copy
366 wxString cs = charset;
367
368 #if wxUSE_CONFIG
369 // first try the user-defined settings
370 wxFontMapperPathChanger path(this, FONTMAPPER_CHARSET_PATH);
371 if ( path.IsOk() )
372 {
373 wxConfigBase *config = GetConfig();
374
375 // do we have an encoding for this charset?
376 long value = config->Read(charset, -1l);
377 if ( value != -1 )
378 {
379 if ( value == wxFONTENCODING_UNKNOWN )
380 {
381 // don't try to find it, in particular don't ask the user
382 return wxFONTENCODING_SYSTEM;
383 }
384
385 if ( value >= 0 && value <= wxFONTENCODING_MAX )
386 {
387 encoding = (wxFontEncoding)value;
388 }
389 else
390 {
391 wxLogDebug(wxT("corrupted config data: invalid encoding %ld for charset '%s' ignored"),
392 value, charset.c_str());
393 }
394 }
395
396 if ( encoding == wxFONTENCODING_SYSTEM )
397 {
398 // may be we have an alias?
399 config->SetPath(FONTMAPPER_CHARSET_ALIAS_PATH);
400
401 wxString alias = config->Read(charset);
402 if ( !!alias )
403 {
404 // yes, we do - use it instead
405 cs = alias;
406 }
407 }
408 }
409 #endif // wxUSE_CONFIG
410
411 // if didn't find it there, try to recognize it ourselves
412 if ( encoding == wxFONTENCODING_SYSTEM )
413 {
414 // trim any spaces
415 cs.Trim(true);
416 cs.Trim(false);
417
418 // discard the optional quotes
419 if ( !cs.empty() )
420 {
421 if ( cs[0u] == _T('"') && cs.Last() == _T('"') )
422 {
423 cs = wxString(cs.c_str(), cs.length() - 1);
424 }
425 }
426
427 cs.MakeUpper();
428
429 if ( cs.empty() || cs == _T("US-ASCII") )
430 {
431 encoding = wxFONTENCODING_DEFAULT;
432 }
433 else if ( cs == wxT("UTF-7") )
434 {
435 encoding = wxFONTENCODING_UTF7;
436 }
437 else if ( cs == wxT("UTF-8") )
438 {
439 encoding = wxFONTENCODING_UTF8;
440 }
441 else if ( cs == wxT("GB2312") )
442 {
443 encoding = wxFONTENCODING_GB2312;
444 }
445 else if ( cs == wxT("BIG5") )
446 {
447 encoding = wxFONTENCODING_BIG5;
448 }
449 else if ( cs == wxT("SJIS") ||
450 cs == wxT("SHIFT_JIS") ||
451 cs == wxT("SHIFT-JIS") )
452 {
453 encoding = wxFONTENCODING_SHIFT_JIS;
454 }
455 else if ( cs == wxT("EUC-JP") ||
456 cs == wxT("EUC_JP") )
457 {
458 encoding = wxFONTENCODING_EUC_JP;
459 }
460 else if ( cs == wxT("KOI8-R") ||
461 cs == wxT("KOI8-U") ||
462 cs == wxT("KOI8-RU") )
463 {
464 // although koi8-ru is not strictly speaking the same as koi8-r,
465 // they are similar enough to make mapping it to koi8 better than
466 // not reckognizing it at all
467 encoding = wxFONTENCODING_KOI8;
468 }
469 else if ( cs.Left(3) == wxT("ISO") )
470 {
471 // the dash is optional (or, to be exact, it is not, but
472 // several brokenmails "forget" it)
473 const wxChar *p = cs.c_str() + 3;
474 if ( *p == wxT('-') )
475 p++;
476
477 // printf( "iso %s\n", (const char*) cs.ToAscii() );
478
479 unsigned int value;
480 if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
481 {
482 // printf( "value %d\n", (int)value );
483
484 // make it 0 based and check that it is strictly positive in
485 // the process (no such thing as iso8859-0 encoding)
486 if ( (value-- > 0) &&
487 (value < wxFONTENCODING_ISO8859_MAX -
488 wxFONTENCODING_ISO8859_1) )
489 {
490 // it's a valid ISO8859 encoding
491 value += wxFONTENCODING_ISO8859_1;
492 encoding = (wxFontEncoding)value;
493 }
494 }
495 }
496 else if ( cs.Left(4) == wxT("8859") )
497 {
498 const wxChar *p = cs.c_str();
499
500 unsigned int value;
501 if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
502 {
503 // printf( "value %d\n", (int)value );
504
505 // make it 0 based and check that it is strictly positive in
506 // the process (no such thing as iso8859-0 encoding)
507 if ( (value-- > 0) &&
508 (value < wxFONTENCODING_ISO8859_MAX -
509 wxFONTENCODING_ISO8859_1) )
510 {
511 // it's a valid ISO8859 encoding
512 value += wxFONTENCODING_ISO8859_1;
513 encoding = (wxFontEncoding)value;
514 }
515 }
516 }
517 else // check for Windows charsets
518 {
519 size_t len;
520 if ( cs.Left(7) == wxT("WINDOWS") )
521 {
522 len = 7;
523 }
524 else if ( cs.Left(2) == wxT("CP") )
525 {
526 len = 2;
527 }
528 else // not a Windows encoding
529 {
530 len = 0;
531 }
532
533 if ( len )
534 {
535 const wxChar *p = cs.c_str() + len;
536 if ( *p == wxT('-') )
537 p++;
538
539 int value;
540 if ( wxSscanf(p, wxT("%u"), &value) == 1 )
541 {
542 if ( value >= 1250 )
543 {
544 value -= 1250;
545 if ( value < wxFONTENCODING_CP12_MAX -
546 wxFONTENCODING_CP1250 )
547 {
548 // a valid Windows code page
549 value += wxFONTENCODING_CP1250;
550 encoding = (wxFontEncoding)value;
551 }
552 }
553
554 switch ( value )
555 {
556 case 932:
557 encoding = wxFONTENCODING_CP932;
558 break;
559
560 case 936:
561 encoding = wxFONTENCODING_CP936;
562 break;
563
564 case 949:
565 encoding = wxFONTENCODING_CP949;
566 break;
567
568 case 950:
569 encoding = wxFONTENCODING_CP950;
570 break;
571 }
572 }
573 }
574 }
575 //else: unknown
576 }
577
578 return encoding;
579 }
580
581 /* static */
582 size_t wxFontMapperBase::GetSupportedEncodingsCount()
583 {
584 return WXSIZEOF(gs_encodings);
585 }
586
587 /* static */
588 wxFontEncoding wxFontMapperBase::GetEncoding(size_t n)
589 {
590 wxCHECK_MSG( n < WXSIZEOF(gs_encodings), wxFONTENCODING_SYSTEM,
591 _T("wxFontMapper::GetEncoding(): invalid index") );
592
593 return gs_encodings[n];
594 }
595
596 /* static */
597 wxString wxFontMapperBase::GetEncodingDescription(wxFontEncoding encoding)
598 {
599 if ( encoding == wxFONTENCODING_DEFAULT )
600 {
601 return _("Default encoding");
602 }
603
604 const size_t count = WXSIZEOF(gs_encodingDescs);
605
606 for ( size_t i = 0; i < count; i++ )
607 {
608 if ( gs_encodings[i] == encoding )
609 {
610 return wxGetTranslation(gs_encodingDescs[i]);
611 }
612 }
613
614 wxString str;
615 str.Printf(_("Unknown encoding (%d)"), encoding);
616
617 return str;
618 }
619
620 /* static */
621 wxString wxFontMapperBase::GetEncodingName(wxFontEncoding encoding)
622 {
623 if ( encoding == wxFONTENCODING_DEFAULT )
624 {
625 return _("default");
626 }
627
628 const size_t count = WXSIZEOF(gs_encodingNames);
629
630 for ( size_t i = 0; i < count; i++ )
631 {
632 if ( gs_encodings[i] == encoding )
633 {
634 return gs_encodingNames[i];
635 }
636 }
637
638 wxString str;
639 str.Printf(_("unknown-%d"), encoding);
640
641 return str;
642 }
643
644 #endif // wxUSE_CONFIG
645
646 #endif // wxUSE_FONTMAP
647