1 |
///////////////////////////////////////////////////////////////////////////// |
2 |
// Name: src/common/fontmap.cpp |
3 |
// Purpose: wxFontMapper class |
4 |
// Author: Vadim Zeitlin |
5 |
// Modified by: |
6 |
// Created: 04.11.99 |
7 |
// RCS-ID: $Id: fontmap.cpp 39651 2006-06-09 17:50:46Z ABX $ |
8 |
// Copyright: (c) 1999-2003 Vadim Zeitlin <vadim@wxwindows.org> |
9 |
// Licence: wxWindows licence |
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 |
#include "wx/fontmap.h" |
30 |
|
31 |
#ifndef WX_PRECOMP |
32 |
#include "wx/app.h" |
33 |
#include "wx/log.h" |
34 |
#include "wx/intl.h" |
35 |
#include "wx/msgdlg.h" |
36 |
#include "wx/choicdlg.h" |
37 |
#endif // PCH |
38 |
|
39 |
#if wxUSE_CONFIG |
40 |
#include "wx/config.h" |
41 |
#endif // wxUSE_CONFIG |
42 |
|
43 |
#if defined(__WXMSW__) |
44 |
#include "wx/msw/private.h" // includes windows.h for LOGFONT |
45 |
#include "wx/msw/winundef.h" |
46 |
#endif |
47 |
|
48 |
#include "wx/fmappriv.h" |
49 |
#include "wx/fontutil.h" |
50 |
#include "wx/fontdlg.h" |
51 |
#include "wx/encinfo.h" |
52 |
|
53 |
#include "wx/encconv.h" |
54 |
|
55 |
#if wxUSE_EXTENDED_RTTI |
56 |
|
57 |
wxBEGIN_ENUM( wxFontEncoding ) |
58 |
wxENUM_MEMBER( wxFONTENCODING_SYSTEM ) |
59 |
wxENUM_MEMBER( wxFONTENCODING_DEFAULT ) |
60 |
|
61 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_1 ) |
62 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_2 ) |
63 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_3 ) |
64 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_4 ) |
65 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_5 ) |
66 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_6 ) |
67 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_7 ) |
68 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_8 ) |
69 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_9 ) |
70 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_10 ) |
71 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_11 ) |
72 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_12 ) |
73 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_13 ) |
74 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_14 ) |
75 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_15 ) |
76 |
wxENUM_MEMBER( wxFONTENCODING_ISO8859_MAX ) |
77 |
wxENUM_MEMBER( wxFONTENCODING_KOI8 ) |
78 |
wxENUM_MEMBER( wxFONTENCODING_KOI8_U ) |
79 |
wxENUM_MEMBER( wxFONTENCODING_ALTERNATIVE ) |
80 |
wxENUM_MEMBER( wxFONTENCODING_BULGARIAN ) |
81 |
wxENUM_MEMBER( wxFONTENCODING_CP437 ) |
82 |
wxENUM_MEMBER( wxFONTENCODING_CP850 ) |
83 |
wxENUM_MEMBER( wxFONTENCODING_CP852 ) |
84 |
wxENUM_MEMBER( wxFONTENCODING_CP855 ) |
85 |
wxENUM_MEMBER( wxFONTENCODING_CP866 ) |
86 |
|
87 |
wxENUM_MEMBER( wxFONTENCODING_CP874 ) |
88 |
wxENUM_MEMBER( wxFONTENCODING_CP932 ) |
89 |
wxENUM_MEMBER( wxFONTENCODING_CP936 ) |
90 |
wxENUM_MEMBER( wxFONTENCODING_CP949 ) |
91 |
wxENUM_MEMBER( wxFONTENCODING_CP950 ) |
92 |
wxENUM_MEMBER( wxFONTENCODING_CP1250 ) |
93 |
wxENUM_MEMBER( wxFONTENCODING_CP1251 ) |
94 |
wxENUM_MEMBER( wxFONTENCODING_CP1252 ) |
95 |
wxENUM_MEMBER( wxFONTENCODING_CP1253 ) |
96 |
wxENUM_MEMBER( wxFONTENCODING_CP1254 ) |
97 |
wxENUM_MEMBER( wxFONTENCODING_CP1255 ) |
98 |
wxENUM_MEMBER( wxFONTENCODING_CP1256 ) |
99 |
wxENUM_MEMBER( wxFONTENCODING_CP1257 ) |
100 |
wxENUM_MEMBER( wxFONTENCODING_CP12_MAX ) |
101 |
wxENUM_MEMBER( wxFONTENCODING_UTF7 ) |
102 |
wxENUM_MEMBER( wxFONTENCODING_UTF8 ) |
103 |
wxENUM_MEMBER( wxFONTENCODING_GB2312 ) |
104 |
wxENUM_MEMBER( wxFONTENCODING_BIG5 ) |
105 |
wxENUM_MEMBER( wxFONTENCODING_SHIFT_JIS ) |
106 |
wxENUM_MEMBER( wxFONTENCODING_EUC_JP ) |
107 |
wxENUM_MEMBER( wxFONTENCODING_UNICODE ) |
108 |
wxEND_ENUM( wxFontEncoding ) |
109 |
#endif |
110 |
|
111 |
// ---------------------------------------------------------------------------- |
112 |
// constants |
113 |
// ---------------------------------------------------------------------------- |
114 |
|
115 |
// the config paths we use |
116 |
#if wxUSE_CONFIG |
117 |
|
118 |
static const wxChar* FONTMAPPER_FONT_FROM_ENCODING_PATH = wxT("Encodings"); |
119 |
static const wxChar* FONTMAPPER_FONT_DONT_ASK = wxT("none"); |
120 |
|
121 |
#endif // wxUSE_CONFIG |
122 |
|
123 |
// ---------------------------------------------------------------------------- |
124 |
// private classes |
125 |
// ---------------------------------------------------------------------------- |
126 |
|
127 |
// it may happen that while we're showing a dialog asking the user about |
128 |
// something, another request for an encoding mapping arrives: in this case it |
129 |
// is best to not do anything because otherwise we risk to enter an infinite |
130 |
// loop so we create an object of this class on stack to test for this in all |
131 |
// interactive functions |
132 |
class ReentrancyBlocker |
133 |
{ |
134 |
public: |
135 |
ReentrancyBlocker(bool& flag) : m_flagOld(flag), m_flag(flag) |
136 |
{ m_flag = true; } |
137 |
~ReentrancyBlocker() { m_flag = m_flagOld; } |
138 |
|
139 |
private: |
140 |
bool m_flagOld; |
141 |
bool& m_flag; |
142 |
|
143 |
DECLARE_NO_COPY_CLASS(ReentrancyBlocker) |
144 |
}; |
145 |
|
146 |
// ============================================================================ |
147 |
// implementation |
148 |
// ============================================================================ |
149 |
|
150 |
// ---------------------------------------------------------------------------- |
151 |
// ctor and dtor |
152 |
// ---------------------------------------------------------------------------- |
153 |
|
154 |
wxFontMapper::wxFontMapper() |
155 |
{ |
156 |
m_windowParent = NULL; |
157 |
} |
158 |
|
159 |
wxFontMapper::~wxFontMapper() |
160 |
{ |
161 |
} |
162 |
|
163 |
/* static */ |
164 |
wxFontMapper *wxFontMapper::Get() |
165 |
{ |
166 |
wxFontMapperBase *fontmapper = wxFontMapperBase::Get(); |
167 |
wxASSERT_MSG( !fontmapper->IsDummy(), |
168 |
wxT("GUI code requested a wxFontMapper but we only have a wxFontMapperBase.") ); |
169 |
|
170 |
// Now return it anyway because there's a chance the GUI code might just |
171 |
// only want to call wxFontMapperBase functions and it's better than |
172 |
// crashing by returning NULL |
173 |
return (wxFontMapper *)fontmapper; |
174 |
} |
175 |
|
176 |
wxFontEncoding |
177 |
wxFontMapper::CharsetToEncoding(const wxString& charset, bool interactive) |
178 |
{ |
179 |
// try the ways not needing the users intervention first |
180 |
int encoding = wxFontMapperBase::NonInteractiveCharsetToEncoding(charset); |
181 |
|
182 |
// if we failed to find the encoding, ask the user -- unless disabled |
183 |
if ( encoding == wxFONTENCODING_UNKNOWN ) |
184 |
{ |
185 |
// this is the special value which disables asking the user (he had |
186 |
// chosen to suppress this the last time) |
187 |
encoding = wxFONTENCODING_SYSTEM; |
188 |
} |
189 |
#if wxUSE_CHOICEDLG |
190 |
else if ( (encoding == wxFONTENCODING_SYSTEM) && interactive ) |
191 |
{ |
192 |
// prepare the dialog data |
193 |
|
194 |
// the dialog title |
195 |
wxString title(m_titleDialog); |
196 |
if ( !title ) |
197 |
title << wxTheApp->GetAppName() << _(": unknown charset"); |
198 |
|
199 |
// the message |
200 |
wxString msg; |
201 |
msg.Printf(_("The charset '%s' is unknown. You may select\nanother charset to replace it with or choose\n[Cancel] if it cannot be replaced"), charset.c_str()); |
202 |
|
203 |
// the list of choices |
204 |
const size_t count = GetSupportedEncodingsCount(); |
205 |
|
206 |
wxString *encodingNamesTranslated = new wxString[count]; |
207 |
|
208 |
for ( size_t i = 0; i < count; i++ ) |
209 |
{ |
210 |
encodingNamesTranslated[i] = GetEncodingDescription(GetEncoding(i)); |
211 |
} |
212 |
|
213 |
// the parent window |
214 |
wxWindow *parent = m_windowParent; |
215 |
if ( !parent ) |
216 |
parent = wxTheApp->GetTopWindow(); |
217 |
|
218 |
// do ask the user and get back the index in encodings table |
219 |
int n = wxGetSingleChoiceIndex(msg, title, |
220 |
count, |
221 |
encodingNamesTranslated, |
222 |
parent); |
223 |
|
224 |
delete [] encodingNamesTranslated; |
225 |
|
226 |
if ( n != -1 ) |
227 |
{ |
228 |
encoding = GetEncoding(n); |
229 |
} |
230 |
|
231 |
#if wxUSE_CONFIG && wxUSE_FILECONFIG |
232 |
// save the result in the config now |
233 |
wxFontMapperPathChanger path(this, FONTMAPPER_CHARSET_PATH); |
234 |
if ( path.IsOk() ) |
235 |
{ |
236 |
wxConfigBase *config = GetConfig(); |
237 |
|
238 |
// remember the alt encoding for this charset -- or remember that |
239 |
// we don't know it |
240 |
long value = n == -1 ? (long)wxFONTENCODING_UNKNOWN : (long)encoding; |
241 |
if ( !config->Write(charset, value) ) |
242 |
{ |
243 |
wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset.c_str()); |
244 |
} |
245 |
} |
246 |
#endif // wxUSE_CONFIG |
247 |
} |
248 |
#else |
249 |
wxUnusedVar(interactive); |
250 |
#endif // wxUSE_CHOICEDLG |
251 |
|
252 |
return (wxFontEncoding)encoding; |
253 |
} |
254 |
|
255 |
// ---------------------------------------------------------------------------- |
256 |
// support for unknown encodings: we maintain a map between the |
257 |
// (platform-specific) strings identifying them and our wxFontEncodings they |
258 |
// correspond to which is used by GetFontForEncoding() function |
259 |
// ---------------------------------------------------------------------------- |
260 |
|
261 |
bool wxFontMapper::TestAltEncoding(const wxString& configEntry, |
262 |
wxFontEncoding encReplacement, |
263 |
wxNativeEncodingInfo *info) |
264 |
{ |
265 |
if ( wxGetNativeFontEncoding(encReplacement, info) && |
266 |
wxTestFontEncoding(*info) ) |
267 |
{ |
268 |
#if wxUSE_CONFIG && wxUSE_FILECONFIG |
269 |
// remember the mapping in the config |
270 |
wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH); |
271 |
|
272 |
if ( path.IsOk() ) |
273 |
{ |
274 |
GetConfig()->Write(configEntry, info->ToString()); |
275 |
} |
276 |
#else |
277 |
wxUnusedVar(configEntry); |
278 |
#endif // wxUSE_CONFIG |
279 |
return true; |
280 |
} |
281 |
|
282 |
return false; |
283 |
} |
284 |
|
285 |
bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding, |
286 |
wxNativeEncodingInfo *info, |
287 |
const wxString& facename, |
288 |
bool interactive) |
289 |
{ |
290 |
#if wxUSE_GUI |
291 |
// we need a flag to prevent infinite recursion which happens, for |
292 |
// example, when GetAltForEncoding() is called from an OnPaint() handler: |
293 |
// in this case, wxYield() which is called from wxMessageBox() we use here |
294 |
// will lead to another call of OnPaint() and hence to another call of |
295 |
// GetAltForEncoding() -- and it is impossible to catch this from the user |
296 |
// code because we are called from wxFont ctor implicitly. |
297 |
|
298 |
// assume we're always called from the main thread, so that it is safe to |
299 |
// use a static var |
300 |
static bool s_inGetAltForEncoding = false; |
301 |
|
302 |
if ( interactive && s_inGetAltForEncoding ) |
303 |
return false; |
304 |
|
305 |
ReentrancyBlocker blocker(s_inGetAltForEncoding); |
306 |
#endif // wxUSE_GUI |
307 |
|
308 |
wxCHECK_MSG( info, false, wxT("bad pointer in GetAltForEncoding") ); |
309 |
|
310 |
info->facename = facename; |
311 |
|
312 |
if ( encoding == wxFONTENCODING_DEFAULT ) |
313 |
{ |
314 |
encoding = wxFont::GetDefaultEncoding(); |
315 |
} |
316 |
|
317 |
// if we failed to load the system default encoding, something is really |
318 |
// wrong and we'd better stop now -- otherwise we will go into endless |
319 |
// recursion trying to create the font in the msg box with the error |
320 |
// message |
321 |
if ( encoding == wxFONTENCODING_SYSTEM ) |
322 |
{ |
323 |
wxLogFatalError(_("can't load any font, aborting")); |
324 |
|
325 |
// wxLogFatalError doesn't return |
326 |
} |
327 |
|
328 |
wxString configEntry, |
329 |
encName = GetEncodingName(encoding); |
330 |
if ( !facename.empty() ) |
331 |
{ |
332 |
configEntry = facename + _T("_"); |
333 |
} |
334 |
configEntry += encName; |
335 |
|
336 |
#if wxUSE_CONFIG && wxUSE_FILECONFIG |
337 |
// do we have a font spec for this encoding? |
338 |
wxString fontinfo; |
339 |
wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH); |
340 |
if ( path.IsOk() ) |
341 |
{ |
342 |
fontinfo = GetConfig()->Read(configEntry); |
343 |
} |
344 |
|
345 |
// this special value means that we don't know of fonts for this |
346 |
// encoding but, moreover, have already asked the user as well and he |
347 |
// didn't specify any font neither |
348 |
if ( fontinfo == FONTMAPPER_FONT_DONT_ASK ) |
349 |
{ |
350 |
interactive = false; |
351 |
} |
352 |
else // use the info entered the last time |
353 |
{ |
354 |
if ( !fontinfo.empty() && !facename.empty() ) |
355 |
{ |
356 |
// we tried to find a match with facename -- now try without it |
357 |
fontinfo = GetConfig()->Read(encName); |
358 |
} |
359 |
|
360 |
if ( !fontinfo.empty() ) |
361 |
{ |
362 |
if ( info->FromString(fontinfo) ) |
363 |
{ |
364 |
if ( wxTestFontEncoding(*info) ) |
365 |
{ |
366 |
// ok, got something |
367 |
return true; |
368 |
} |
369 |
//else: no such fonts, look for something else |
370 |
// (should we erase the outdated value?) |
371 |
} |
372 |
else |
373 |
{ |
374 |
wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"), |
375 |
fontinfo.c_str()); |
376 |
} |
377 |
} |
378 |
//else: there is no information in config about this encoding |
379 |
} |
380 |
#endif // wxUSE_CONFIG |
381 |
|
382 |
// now try to map this encoding to a compatible one which we have on this |
383 |
// system |
384 |
wxFontEncodingArray equiv = wxEncodingConverter::GetAllEquivalents(encoding); |
385 |
size_t count = equiv.GetCount(); |
386 |
bool foundEquivEncoding = false; |
387 |
wxFontEncoding equivEncoding = wxFONTENCODING_SYSTEM; |
388 |
if ( count ) |
389 |
{ |
390 |
for ( size_t i = 0; i < count && !foundEquivEncoding; i++ ) |
391 |
{ |
392 |
// don't test for encoding itself, we already know we don't have it |
393 |
if ( equiv[i] == encoding ) |
394 |
continue; |
395 |
|
396 |
if ( TestAltEncoding(configEntry, equiv[i], info) ) |
397 |
{ |
398 |
equivEncoding = equiv[i]; |
399 |
|
400 |
foundEquivEncoding = true; |
401 |
} |
402 |
} |
403 |
} |
404 |
|
405 |
// ask the user |
406 |
#if wxUSE_FONTDLG |
407 |
if ( interactive ) |
408 |
{ |
409 |
wxString title(m_titleDialog); |
410 |
if ( !title ) |
411 |
title << wxTheApp->GetAppName() << _(": unknown encoding"); |
412 |
|
413 |
// built the message |
414 |
wxString encDesc = GetEncodingDescription(encoding), |
415 |
msg; |
416 |
if ( foundEquivEncoding ) |
417 |
{ |
418 |
// ask the user if he wants to override found alternative encoding |
419 |
msg.Printf(_("No font for displaying text in encoding '%s' found,\nbut an alternative encoding '%s' is available.\nDo you want to use this encoding (otherwise you will have to choose another one)?"), |
420 |
encDesc.c_str(), GetEncodingDescription(equivEncoding).c_str()); |
421 |
} |
422 |
else |
423 |
{ |
424 |
msg.Printf(_("No font for displaying text in encoding '%s' found.\nWould you like to select a font to be used for this encoding\n(otherwise the text in this encoding will not be shown correctly)?"), |
425 |
encDesc.c_str()); |
426 |
} |
427 |
|
428 |
// the question is different in 2 cases so the answer has to be |
429 |
// interpreted differently as well |
430 |
int answer = foundEquivEncoding ? wxNO : wxYES; |
431 |
|
432 |
if ( wxMessageBox(msg, title, |
433 |
wxICON_QUESTION | wxYES_NO, |
434 |
m_windowParent) == answer ) |
435 |
{ |
436 |
wxFontData data; |
437 |
data.SetEncoding(encoding); |
438 |
data.EncodingInfo() = *info; |
439 |
wxFontDialog dialog(m_windowParent, data); |
440 |
if ( dialog.ShowModal() == wxID_OK ) |
441 |
{ |
442 |
wxFontData retData = dialog.GetFontData(); |
443 |
|
444 |
*info = retData.EncodingInfo(); |
445 |
info->encoding = retData.GetEncoding(); |
446 |
|
447 |
#if wxUSE_CONFIG && wxUSE_FILECONFIG |
448 |
// remember this in the config |
449 |
wxFontMapperPathChanger path2(this, |
450 |
FONTMAPPER_FONT_FROM_ENCODING_PATH); |
451 |
if ( path2.IsOk() ) |
452 |
{ |
453 |
GetConfig()->Write(configEntry, info->ToString()); |
454 |
} |
455 |
#endif // wxUSE_CONFIG |
456 |
|
457 |
return true; |
458 |
} |
459 |
//else: the user canceled the font selection dialog |
460 |
} |
461 |
else |
462 |
{ |
463 |
// the user doesn't want to select a font for this encoding |
464 |
// or selected to use equivalent encoding |
465 |
// |
466 |
// remember it to avoid asking the same question again later |
467 |
#if wxUSE_CONFIG && wxUSE_FILECONFIG |
468 |
wxFontMapperPathChanger path2(this, |
469 |
FONTMAPPER_FONT_FROM_ENCODING_PATH); |
470 |
if ( path2.IsOk() ) |
471 |
{ |
472 |
GetConfig()->Write |
473 |
( |
474 |
configEntry, |
475 |
foundEquivEncoding ? info->ToString().c_str() |
476 |
: FONTMAPPER_FONT_DONT_ASK |
477 |
); |
478 |
} |
479 |
#endif // wxUSE_CONFIG |
480 |
} |
481 |
} |
482 |
//else: we're in non-interactive mode |
483 |
#else |
484 |
wxUnusedVar(equivEncoding); |
485 |
#endif // wxUSE_FONTDLG |
486 |
|
487 |
return foundEquivEncoding; |
488 |
} |
489 |
|
490 |
bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding, |
491 |
wxFontEncoding *encodingAlt, |
492 |
const wxString& facename, |
493 |
bool interactive) |
494 |
{ |
495 |
wxCHECK_MSG( encodingAlt, false, |
496 |
_T("wxFontEncoding::GetAltForEncoding(): NULL pointer") ); |
497 |
|
498 |
wxNativeEncodingInfo info; |
499 |
if ( !GetAltForEncoding(encoding, &info, facename, interactive) ) |
500 |
return false; |
501 |
|
502 |
*encodingAlt = info.encoding; |
503 |
|
504 |
return true; |
505 |
} |
506 |
|
507 |
bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding, |
508 |
const wxString& facename) |
509 |
{ |
510 |
wxNativeEncodingInfo info; |
511 |
|
512 |
if ( !wxGetNativeFontEncoding(encoding, &info) ) |
513 |
return false; |
514 |
|
515 |
info.facename = facename; |
516 |
return wxTestFontEncoding(info); |
517 |
} |
518 |
|
519 |
#endif // wxUSE_FONTMAP |