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