1 /////////////////////////////////////////////////////////////////////////////
2 // Name: common/fontmap.cpp
3 // Purpose: wxFontMapper class
4 // Author: Vadim Zeitlin
8 // Copyright: (c) 1999-2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
21 #pragma implementation "fontmap.h"
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
39 #include "wx/fontmap.h"
40 #include "wx/fmappriv.h"
43 #include "wx/config.h"
44 #endif // wxUSE_CONFIG
46 #include "wx/fontutil.h"
47 #include "wx/msgdlg.h"
48 #include "wx/fontdlg.h"
49 #include "wx/choicdlg.h"
51 #include "wx/encconv.h"
53 // ----------------------------------------------------------------------------
55 // ----------------------------------------------------------------------------
57 // the config paths we use
60 static const wxChar
* FONTMAPPER_FONT_FROM_ENCODING_PATH
= wxT("Encodings");
61 static const wxChar
* FONTMAPPER_FONT_DONT_ASK
= wxT("none");
63 #endif // wxUSE_CONFIG
65 // ----------------------------------------------------------------------------
67 // ----------------------------------------------------------------------------
69 // it may happen that while we're showing a dialog asking the user about
70 // something, another request for an encoding mapping arrives: in this case it
71 // is best to not do anything because otherwise we risk to enter an infinite
72 // loop so we create an object of this class on stack to test for this in all
73 // interactive functions
74 class ReentrancyBlocker
77 ReentrancyBlocker(bool& flag
) : m_flagOld(flag
), m_flag(flag
)
79 ~ReentrancyBlocker() { m_flag
= m_flagOld
; }
86 // ============================================================================
88 // ============================================================================
90 // ----------------------------------------------------------------------------
92 // ----------------------------------------------------------------------------
94 wxFontMapper::wxFontMapper()
96 m_windowParent
= NULL
;
99 wxFontMapper::~wxFontMapper()
104 wxFontMapper::CharsetToEncoding(const wxString
& charset
, bool interactive
)
106 // try the ways not needing the users intervention first
108 encoding
= wxFontMapperBase::CharsetToEncoding(charset
, interactive
);
110 // if we failed to find the encoding, ask the user -- unless disabled
111 if ( (encoding
== wxFONTENCODING_SYSTEM
) && interactive
)
113 // prepare the dialog data
116 wxString
title(m_titleDialog
);
118 title
<< wxTheApp
->GetAppName() << _(": unknown charset");
122 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());
124 // the list of choices
125 const size_t count
= GetSupportedEncodingsCount();
127 wxString
*encodingNamesTranslated
= new wxString
[count
];
129 for ( size_t i
= 0; i
< count
; i
++ )
131 encodingNamesTranslated
[i
] = GetEncodingDescription(GetEncoding(i
));
135 wxWindow
*parent
= m_windowParent
;
137 parent
= wxTheApp
->GetTopWindow();
139 // do ask the user and get back the index in encodings table
140 int n
= wxGetSingleChoiceIndex(msg
, title
,
142 encodingNamesTranslated
,
145 delete [] encodingNamesTranslated
;
149 encoding
= GetEncoding(n
);
153 // save the result in the config now
154 wxFontMapperPathChanger
path(this, FONTMAPPER_CHARSET_PATH
);
157 wxConfigBase
*config
= GetConfig();
159 // remember the alt encoding for this charset -- or remember that
161 long value
= n
== -1 ? wxFONTENCODING_UNKNOWN
: (long)encoding
;
162 if ( !config
->Write(charset
, value
) )
164 wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset
.c_str());
167 #endif // wxUSE_CONFIG
173 // ----------------------------------------------------------------------------
174 // support for unknown encodings: we maintain a map between the
175 // (platform-specific) strings identifying them and our wxFontEncodings they
176 // correspond to which is used by GetFontForEncoding() function
177 // ----------------------------------------------------------------------------
179 bool wxFontMapper::TestAltEncoding(const wxString
& configEntry
,
180 wxFontEncoding encReplacement
,
181 wxNativeEncodingInfo
*info
)
183 if ( wxGetNativeFontEncoding(encReplacement
, info
) &&
184 wxTestFontEncoding(*info
) )
187 // remember the mapping in the config
188 wxFontMapperPathChanger
path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH
);
192 GetConfig()->Write(configEntry
, info
->ToString());
194 #endif // wxUSE_CONFIG
201 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
202 wxNativeEncodingInfo
*info
,
203 const wxString
& facename
,
207 // we need a flag to prevent infinite recursion which happens, for
208 // example, when GetAltForEncoding() is called from an OnPaint() handler:
209 // in this case, wxYield() which is called from wxMessageBox() we use here
210 // will lead to another call of OnPaint() and hence to another call of
211 // GetAltForEncoding() -- and it is impossible to catch this from the user
212 // code because we are called from wxFont ctor implicitly.
214 // assume we're always called from the main thread, so that it is safe to
216 static bool s_inGetAltForEncoding
= false;
218 if ( interactive
&& s_inGetAltForEncoding
)
221 ReentrancyBlocker
blocker(s_inGetAltForEncoding
);
224 wxCHECK_MSG( info
, false, wxT("bad pointer in GetAltForEncoding") );
226 info
->facename
= facename
;
228 if ( encoding
== wxFONTENCODING_DEFAULT
)
230 encoding
= wxFont::GetDefaultEncoding();
233 // if we failed to load the system default encoding, something is really
234 // wrong and we'd better stop now -- otherwise we will go into endless
235 // recursion trying to create the font in the msg box with the error
237 if ( encoding
== wxFONTENCODING_SYSTEM
)
239 wxLogFatalError(_("can't load any font, aborting"));
241 // wxLogFatalError doesn't return
244 wxString configEntry
,
245 encName
= GetEncodingName(encoding
);
248 configEntry
= facename
+ _T("_");
250 configEntry
+= encName
;
253 // do we have a font spec for this encoding?
255 wxFontMapperPathChanger
path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH
);
258 fontinfo
= GetConfig()->Read(configEntry
);
261 // this special value means that we don't know of fonts for this
262 // encoding but, moreover, have already asked the user as well and he
263 // didn't specify any font neither
264 if ( fontinfo
== FONTMAPPER_FONT_DONT_ASK
)
268 else // use the info entered the last time
270 if ( !!fontinfo
&& !!facename
)
272 // we tried to find a match with facename -- now try without it
273 fontinfo
= GetConfig()->Read(encName
);
278 if ( info
->FromString(fontinfo
) )
280 if ( wxTestFontEncoding(*info
) )
285 //else: no such fonts, look for something else
286 // (should we erase the outdated value?)
290 wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"),
294 //else: there is no information in config about this encoding
296 #endif // wxUSE_CONFIG
298 // now try to map this encoding to a compatible one which we have on this
300 wxFontEncodingArray equiv
= wxEncodingConverter::GetAllEquivalents(encoding
);
301 size_t count
= equiv
.GetCount();
302 bool foundEquivEncoding
= false;
303 wxFontEncoding equivEncoding
= wxFONTENCODING_SYSTEM
;
306 for ( size_t i
= 0; i
< count
&& !foundEquivEncoding
; i
++ )
308 // don't test for encoding itself, we already know we don't have it
309 if ( equiv
[i
] == encoding
)
312 if ( TestAltEncoding(configEntry
, equiv
[i
], info
) )
314 equivEncoding
= equiv
[i
];
316 foundEquivEncoding
= true;
325 wxString
title(m_titleDialog
);
327 title
<< wxTheApp
->GetAppName() << _(": unknown encoding");
330 wxString encDesc
= GetEncodingDescription(encoding
),
332 if ( foundEquivEncoding
)
334 // ask the user if he wants to override found alternative encoding
335 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)?"),
336 encDesc
.c_str(), GetEncodingDescription(equivEncoding
).c_str());
340 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)?"),
344 // the question is different in 2 cases so the answer has to be
345 // interpreted differently as well
346 int answer
= foundEquivEncoding
? wxNO
: wxYES
;
348 if ( wxMessageBox(msg
, title
,
349 wxICON_QUESTION
| wxYES_NO
,
350 m_windowParent
) == answer
)
353 data
.SetEncoding(encoding
);
354 data
.EncodingInfo() = *info
;
355 wxFontDialog
dialog(m_windowParent
, data
);
356 if ( dialog
.ShowModal() == wxID_OK
)
358 wxFontData retData
= dialog
.GetFontData();
359 wxFont font
= retData
.GetChosenFont();
361 *info
= retData
.EncodingInfo();
362 info
->encoding
= retData
.GetEncoding();
365 // remember this in the config
366 wxFontMapperPathChanger
path(this,
367 FONTMAPPER_FONT_FROM_ENCODING_PATH
);
370 GetConfig()->Write(configEntry
, info
->ToString());
372 #endif // wxUSE_CONFIG
376 //else: the user canceled the font selection dialog
380 // the user doesn't want to select a font for this encoding
381 // or selected to use equivalent encoding
383 // remember it to avoid asking the same question again later
385 wxFontMapperPathChanger
path(this,
386 FONTMAPPER_FONT_FROM_ENCODING_PATH
);
392 foundEquivEncoding
? info
->ToString().c_str()
393 : FONTMAPPER_FONT_DONT_ASK
396 #endif // wxUSE_CONFIG
399 //else: we're in non-interactive mode
400 #endif // wxUSE_FONTDLG
402 return foundEquivEncoding
;
405 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding
,
406 wxFontEncoding
*encodingAlt
,
407 const wxString
& facename
,
410 wxNativeEncodingInfo info
;
411 if ( !GetAltForEncoding(encoding
, &info
, facename
, interactive
) )
414 wxCHECK_MSG( encodingAlt
, false,
415 _T("wxFontEncoding::GetAltForEncoding(): NULL pointer") );
417 *encodingAlt
= info
.encoding
;
422 bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding
,
423 const wxString
& facename
)
425 wxNativeEncodingInfo info
;
427 if ( !wxGetNativeFontEncoding(encoding
, &info
) )
430 info
.facename
= facename
;
431 return wxTestFontEncoding(info
);
434 #endif // wxUSE_FONTMAP