]> git.saurik.com Git - wxWidgets.git/blob - src/common/fontmap.cpp
wxLocale now uses wxEncodingConverter (must be explicitly enabled)
[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 #include "wx/encconv.h"
44
45 // ----------------------------------------------------------------------------
46 // constants
47 // ----------------------------------------------------------------------------
48
49 // the config paths we use
50 static const wxChar* FONTMAPPER_ROOT_PATH = wxT("FontMapper");
51 static const wxChar* FONTMAPPER_CHARSET_PATH = wxT("Charsets");
52 static const wxChar* FONTMAPPER_CHARSET_ALIAS_PATH = wxT("Aliases");
53 static const wxChar* FONTMAPPER_FONT_FROM_ENCODING_PATH = wxT("Encodings");
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_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
85 static 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
114 static const wxChar* gs_encodingNames[] =
115 {
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" ),
140 };
141
142 // ----------------------------------------------------------------------------
143 // global data
144 // ----------------------------------------------------------------------------
145
146 // private object
147 static wxFontMapper gs_fontMapper;
148
149 // and public pointer
150 wxFontMapper * wxTheFontMapper = &gs_fontMapper;
151
152 // ----------------------------------------------------------------------------
153 // private classes
154 // ----------------------------------------------------------------------------
155
156 // change the config path during the lifetime of this object
157 class wxFontMapperPathChanger
158 {
159 public:
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
174 private:
175 wxFontMapper *m_fontMapper;
176 bool m_ok;
177 wxString m_pathOld;
178 };
179
180 // ============================================================================
181 // implementation
182 // ============================================================================
183
184 // ----------------------------------------------------------------------------
185 // ctor and dtor
186 // ----------------------------------------------------------------------------
187
188 wxFontMapper::wxFontMapper()
189 {
190 m_config = NULL;
191 m_windowParent = NULL;
192 }
193
194 wxFontMapper::~wxFontMapper()
195 {
196 }
197
198 // ----------------------------------------------------------------------------
199 // customisation
200 // ----------------------------------------------------------------------------
201
202 /* static */ const wxChar *wxFontMapper::GetDefaultConfigPath()
203 {
204 return FONTMAPPER_ROOT_PATH;
205 }
206
207 void wxFontMapper::SetConfigPath(const wxString& prefix)
208 {
209 wxCHECK_RET( !prefix.IsEmpty() && prefix[0] == wxCONFIG_PATH_SEPARATOR,
210 wxT("an absolute path should be given to "
211 "wxFontMapper::SetConfigPath()") );
212
213 m_configRootPath = prefix;
214 }
215
216
217 // ----------------------------------------------------------------------------
218 // get config object and path for it
219 // ----------------------------------------------------------------------------
220
221 wxConfigBase *wxFontMapper::GetConfig()
222 {
223 if ( !m_config )
224 {
225 // try the default
226 m_config = wxConfig::Get();
227 }
228
229 return m_config;
230 }
231
232 const 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
243 bool 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),
258 wxT("should be a relative path") );
259
260 path += pathNew;
261
262 config->SetPath(path);
263
264 return TRUE;
265 }
266
267 void wxFontMapper::RestorePath(const wxString& pathOld)
268 {
269 GetConfig()->SetPath(pathOld);
270 }
271
272 // ----------------------------------------------------------------------------
273 // charset/encoding correspondence
274 // ----------------------------------------------------------------------------
275
276 /* static */
277 wxString wxFontMapper::GetEncodingDescription(wxFontEncoding encoding)
278 {
279 size_t count = WXSIZEOF(gs_encodingDescs);
280
281 wxASSERT_MSG( count == WXSIZEOF(gs_encodings),
282 wxT("inconsitency detected - forgot to update one of "
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 */
300 wxString wxFontMapper::GetEncodingName(wxFontEncoding encoding)
301 {
302 size_t count = WXSIZEOF(gs_encodingNames);
303
304 wxASSERT_MSG( count == WXSIZEOF(gs_encodings),
305 wxT("inconsitency detected - forgot to update one of "
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
322 wxFontEncoding 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 {
346 wxLogDebug(wxT("corrupted config data - invalid encoding %ld "
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
372 if ( !cs || cs == wxT("US-ASCII") )
373 encoding = wxFONTENCODING_DEFAULT;
374 else if ( cs == wxT("KOI8-R") || cs == wxT("KOI8-U") )
375 encoding = wxFONTENCODING_KOI8;
376 else if ( cs.Left(3) == wxT("ISO") )
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;
381 if ( *p == wxT('-') )
382 p++;
383
384 unsigned int value;
385 if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
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 }
396 else if ( cs.Left(8) == wxT("WINDOWS-") )
397 {
398 int value;
399 if ( wxSscanf(cs.c_str() + 8, wxT("%u"), &value) == 1 )
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
434 size_t count = WXSIZEOF(gs_encodingDescs);
435
436 wxASSERT_MSG( count == WXSIZEOF(gs_encodings),
437 wxT("inconsitency detected - forgot to update one of "
438 "the arrays?") );
439
440 wxString *encodingNamesTranslated = new wxString[count];
441
442 for ( size_t i = 0; i < count; i++ )
443 {
444 encodingNamesTranslated[i] = wxGetTranslation(gs_encodingDescs[i]);
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 {
462 // TODO save the result in the config!
463
464 encoding = gs_encodings[n];
465 }
466 //else: cancelled
467 }
468
469 return encoding;
470 }
471
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
478 bool 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
499 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
500 wxNativeEncodingInfo *info,
501 bool interactive)
502 {
503 wxCHECK_MSG( info, FALSE, wxT("bad pointer in GetAltForEncoding") );
504
505 if ( encoding == wxFONTENCODING_DEFAULT )
506 {
507 encoding = wxFont::GetDefaultEncoding();
508 }
509
510 // if we failed to load the system default encoding, something is really
511 // wrong and we'd better stop now - otherwise we will go into endless
512 // recursion trying to create the font in the msg box with the error
513 // message
514 if ( encoding == wxFONTENCODING_SYSTEM )
515 {
516 wxFatalError(_("can't load any font, aborting"));
517
518 // wxFatalError doesn't return
519 }
520
521 wxString configEntry = GetEncodingName(encoding);
522
523 // do we have a font spec for this encoding?
524 wxString pathOld;
525 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
526 {
527 wxConfigBase *config = GetConfig();
528
529 wxString fontinfo = config->Read(configEntry);
530
531 RestorePath(pathOld);
532
533 if ( !!fontinfo )
534 {
535 if ( info->FromString(fontinfo) )
536 {
537 if ( wxTestFontEncoding(*info) )
538 {
539 // ok, got something
540 return TRUE;
541 }
542 //else: no such fonts, look for something else
543 }
544 else
545 {
546 wxLogDebug(wxT("corrupted config data: string '%s' is not "
547 "a valid font encoding info"), fontinfo.c_str());
548 }
549 }
550 }
551
552 // ask the user
553 if ( interactive )
554 {
555 wxString title(m_titleDialog);
556 if ( !title )
557 title << wxTheApp->GetAppName() << _(": unknown encoding");
558
559 // the message
560 wxString msg;
561 msg.Printf(_("The encoding '%s' is unknown.\n"
562 "Would you like to select a font to be used for this "
563 "encoding\n"
564 "(otherwise the text in this encoding will not be "
565 "shown correctly)?"),
566 GetEncodingDescription(encoding).c_str());
567
568 wxWindow *parent = m_windowParent;
569 if ( !parent )
570 parent = wxTheApp->GetTopWindow();
571
572 if ( wxMessageBox(msg, title,
573 wxICON_QUESTION | wxYES_NO, parent) == wxYES )
574 {
575 wxFontData data;
576 data.SetEncoding(encoding);
577 data.EncodingInfo() = *info;
578 wxFontDialog dialog(parent, &data);
579 if ( dialog.ShowModal() == wxID_OK )
580 {
581 wxFontData retData = dialog.GetFontData();
582 wxFont font = retData.GetChosenFont();
583
584 *info = retData.EncodingInfo();
585
586 // remember this in the config
587 if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
588 {
589 GetConfig()->Write(configEntry, info->ToString());
590
591 RestorePath(pathOld);
592 }
593
594 return TRUE;
595 }
596 //else: the user canceled the font selection dialog
597 }
598 //else: the user doesn't want to select a font
599 }
600 //else: we're in non-interactive mode
601
602
603 // now try the default mappings:
604
605 wxFontEncodingArray equiv = wxEncodingConverter::GetAllEquivalents(encoding);
606 for ( unsigned i = (equiv[0] == encoding) ? 1 : 0; i < equiv.GetCount(); i++ )
607 if ( TestAltEncoding(configEntry, equiv[i], info) )
608 return TRUE;
609
610 return FALSE;
611 }