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