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