]> git.saurik.com Git - wxWidgets.git/blame - src/common/fontmap.cpp
make string at least empty (instead of containing garbage) if malloc() failed
[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$
e2478fde 8// Copyright: (c) 1999-2003 Vadim Zeitlin <vadim@wxwindows.org>
55d99c7a 9// Licence: wxWindows licence
3c1866e8
VZ
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
1e6feb95
VZ
31#if wxUSE_FONTMAP
32
3c1866e8
VZ
33#ifndef WX_PRECOMP
34 #include "wx/app.h"
35 #include "wx/log.h"
36 #include "wx/intl.h"
37#endif // PCH
38
39#include "wx/fontmap.h"
e2478fde 40#include "wx/fmappriv.h"
7beba2fc 41
f6bcfd97
BP
42#if wxUSE_CONFIG
43 #include "wx/config.h"
e2478fde 44#endif // wxUSE_CONFIG
f6bcfd97 45
e2478fde
VZ
46#include "wx/fontutil.h"
47#include "wx/msgdlg.h"
48#include "wx/fontdlg.h"
49#include "wx/choicdlg.h"
f6bcfd97 50
82545b58 51#include "wx/encconv.h"
3c1866e8
VZ
52
53// ----------------------------------------------------------------------------
54// constants
55// ----------------------------------------------------------------------------
56
57// the config paths we use
1e6feb95 58#if wxUSE_CONFIG
7beba2fc 59
e2478fde
VZ
60static const wxChar* FONTMAPPER_FONT_FROM_ENCODING_PATH = wxT("Encodings");
61static const wxChar* FONTMAPPER_FONT_DONT_ASK = wxT("none");
7beba2fc 62
e2478fde 63#endif // wxUSE_CONFIG
7beba2fc
VZ
64
65// ----------------------------------------------------------------------------
66// private classes
67// ----------------------------------------------------------------------------
68
e2478fde
VZ
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
74class ReentrancyBlocker
7beba2fc
VZ
75{
76public:
e2478fde
VZ
77 ReentrancyBlocker(bool& flag) : m_flagOld(flag), m_flag(flag)
78 { m_flag = true; }
79 ~ReentrancyBlocker() { m_flag = m_flagOld; }
7beba2fc
VZ
80
81private:
e2478fde
VZ
82 bool m_flagOld;
83 bool& m_flag;
7beba2fc 84};
3c1866e8
VZ
85
86// ============================================================================
87// implementation
88// ============================================================================
89
90// ----------------------------------------------------------------------------
91// ctor and dtor
92// ----------------------------------------------------------------------------
93
94wxFontMapper::wxFontMapper()
95{
3c1866e8
VZ
96 m_windowParent = NULL;
97}
98
99wxFontMapper::~wxFontMapper()
100{
3c1866e8
VZ
101}
102
e2478fde
VZ
103wxFontEncoding
104wxFontMapper::CharsetToEncoding(const wxString& charset, bool interactive)
3c1866e8 105{
e2478fde
VZ
106 // try the ways not needing the users intervention first
107 wxFontEncoding
108 encoding = wxFontMapperBase::CharsetToEncoding(charset, interactive);
7beba2fc 109
e2478fde 110 // if we failed to find the encoding, ask the user -- unless disabled
3c1866e8
VZ
111 if ( (encoding == wxFONTENCODING_SYSTEM) && interactive )
112 {
113 // prepare the dialog data
114
115 // the dialog title
116 wxString title(m_titleDialog);
117 if ( !title )
118 title << wxTheApp->GetAppName() << _(": unknown charset");
119
120 // the message
121 wxString msg;
f6bcfd97 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());
3c1866e8
VZ
123
124 // the list of choices
e2478fde 125 const size_t count = GetSupportedEncodingsCount();
3c1866e8
VZ
126
127 wxString *encodingNamesTranslated = new wxString[count];
128
11c7d5b6 129 for ( size_t i = 0; i < count; i++ )
3c1866e8 130 {
e2478fde 131 encodingNamesTranslated[i] = GetEncodingDescription(GetEncoding(i));
3c1866e8
VZ
132 }
133
134 // the parent window
135 wxWindow *parent = m_windowParent;
136 if ( !parent )
137 parent = wxTheApp->GetTopWindow();
138
139 // do ask the user and get back the index in encodings table
140 int n = wxGetSingleChoiceIndex(msg, title,
141 count,
142 encodingNamesTranslated,
143 parent);
144
145 delete [] encodingNamesTranslated;
146
147 if ( n != -1 )
148 {
e2478fde 149 encoding = GetEncoding(n);
3e7fb236 150 }
1d910ac1 151
f6bcfd97
BP
152#if wxUSE_CONFIG
153 // save the result in the config now
e2478fde
VZ
154 wxFontMapperPathChanger path(this, FONTMAPPER_CHARSET_PATH);
155 if ( path.IsOk() )
3e7fb236
VZ
156 {
157 wxConfigBase *config = GetConfig();
1d910ac1 158
e2478fde 159 // remember the alt encoding for this charset -- or remember that
3e7fb236
VZ
160 // we don't know it
161 long value = n == -1 ? wxFONTENCODING_UNKNOWN : (long)encoding;
162 if ( !config->Write(charset, value) )
163 {
164 wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset.c_str());
1d910ac1 165 }
3c1866e8 166 }
3e7fb236 167#endif // wxUSE_CONFIG
3c1866e8
VZ
168 }
169
170 return encoding;
171}
172
7beba2fc
VZ
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// ----------------------------------------------------------------------------
178
179bool wxFontMapper::TestAltEncoding(const wxString& configEntry,
180 wxFontEncoding encReplacement,
181 wxNativeEncodingInfo *info)
182{
183 if ( wxGetNativeFontEncoding(encReplacement, info) &&
184 wxTestFontEncoding(*info) )
185 {
f6bcfd97 186#if wxUSE_CONFIG
7beba2fc
VZ
187 // remember the mapping in the config
188 wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH);
189
190 if ( path.IsOk() )
191 {
192 GetConfig()->Write(configEntry, info->ToString());
193 }
f6bcfd97 194#endif // wxUSE_CONFIG
e2478fde 195 return true;
7beba2fc
VZ
196 }
197
e2478fde 198 return false;
7beba2fc
VZ
199}
200
201bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
202 wxNativeEncodingInfo *info,
6648cd46 203 const wxString& facename,
7beba2fc
VZ
204 bool interactive)
205{
f6bcfd97
BP
206#if wxUSE_GUI
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
e2478fde 211 // GetAltForEncoding() -- and it is impossible to catch this from the user
f6bcfd97
BP
212 // code because we are called from wxFont ctor implicitly.
213
214 // assume we're always called from the main thread, so that it is safe to
215 // use a static var
e2478fde 216 static bool s_inGetAltForEncoding = false;
f6bcfd97
BP
217
218 if ( interactive && s_inGetAltForEncoding )
e2478fde 219 return false;
f6bcfd97
BP
220
221 ReentrancyBlocker blocker(s_inGetAltForEncoding);
222#endif // wxUSE_GUI
223
e2478fde 224 wxCHECK_MSG( info, false, wxT("bad pointer in GetAltForEncoding") );
7beba2fc 225
6648cd46
VS
226 info->facename = facename;
227
97d3f0ee
VZ
228 if ( encoding == wxFONTENCODING_DEFAULT )
229 {
230 encoding = wxFont::GetDefaultEncoding();
231 }
232
233 // if we failed to load the system default encoding, something is really
e2478fde 234 // wrong and we'd better stop now -- otherwise we will go into endless
97d3f0ee
VZ
235 // recursion trying to create the font in the msg box with the error
236 // message
237 if ( encoding == wxFONTENCODING_SYSTEM )
238 {
73deed44 239 wxLogFatalError(_("can't load any font, aborting"));
97d3f0ee 240
73deed44 241 // wxLogFatalError doesn't return
97d3f0ee
VZ
242 }
243
a4a6984d
VZ
244 wxString configEntry,
245 encName = GetEncodingName(encoding);
1d910ac1
VZ
246 if ( !!facename )
247 {
248 configEntry = facename + _T("_");
249 }
250 configEntry += encName;
7beba2fc 251
f6bcfd97 252#if wxUSE_CONFIG
7beba2fc 253 // do we have a font spec for this encoding?
e2478fde
VZ
254 wxString fontinfo;
255 wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH);
256 if ( path.IsOk() )
7beba2fc 257 {
e2478fde
VZ
258 fontinfo = GetConfig()->Read(configEntry);
259 }
7beba2fc 260
e2478fde
VZ
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 )
265 {
266 interactive = false;
267 }
268 else // use the info entered the last time
269 {
270 if ( !!fontinfo && !!facename )
1d910ac1 271 {
e2478fde
VZ
272 // we tried to find a match with facename -- now try without it
273 fontinfo = GetConfig()->Read(encName);
1d910ac1 274 }
6603907d 275
e2478fde
VZ
276 if ( !!fontinfo )
277 {
278 if ( info->FromString(fontinfo) )
7beba2fc 279 {
e2478fde 280 if ( wxTestFontEncoding(*info) )
6603907d 281 {
e2478fde
VZ
282 // ok, got something
283 return true;
6603907d 284 }
e2478fde
VZ
285 //else: no such fonts, look for something else
286 // (should we erase the outdated value?)
287 }
288 else
289 {
290 wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"),
291 fontinfo.c_str());
7beba2fc
VZ
292 }
293 }
e2478fde 294 //else: there is no information in config about this encoding
7beba2fc 295 }
f6bcfd97 296#endif // wxUSE_CONFIG
7beba2fc 297
3a989c8a
VZ
298 // now try to map this encoding to a compatible one which we have on this
299 // system
300 wxFontEncodingArray equiv = wxEncodingConverter::GetAllEquivalents(encoding);
301 size_t count = equiv.GetCount();
e2478fde 302 bool foundEquivEncoding = false;
c6465c96 303 wxFontEncoding equivEncoding = wxFONTENCODING_SYSTEM;
3a989c8a
VZ
304 if ( count )
305 {
306 for ( size_t i = 0; i < count && !foundEquivEncoding; i++ )
307 {
308 // don't test for encoding itself, we already know we don't have it
309 if ( equiv[i] == encoding )
310 continue;
311
312 if ( TestAltEncoding(configEntry, equiv[i], info) )
313 {
314 equivEncoding = equiv[i];
315
e2478fde 316 foundEquivEncoding = true;
3a989c8a
VZ
317 }
318 }
319 }
320
7beba2fc 321 // ask the user
3379ed37 322#if wxUSE_FONTDLG
7beba2fc
VZ
323 if ( interactive )
324 {
325 wxString title(m_titleDialog);
326 if ( !title )
327 title << wxTheApp->GetAppName() << _(": unknown encoding");
328
3a989c8a
VZ
329 // built the message
330 wxString encDesc = GetEncodingDescription(encoding),
331 msg;
332 if ( foundEquivEncoding )
333 {
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());
337 }
338 else
339 {
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)?"),
341 encDesc.c_str());
342 }
7beba2fc 343
3a989c8a
VZ
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;
7beba2fc
VZ
347
348 if ( wxMessageBox(msg, title,
3a989c8a
VZ
349 wxICON_QUESTION | wxYES_NO,
350 m_windowParent) == answer )
7beba2fc
VZ
351 {
352 wxFontData data;
353 data.SetEncoding(encoding);
354 data.EncodingInfo() = *info;
baaae89f 355 wxFontDialog dialog(m_windowParent, data);
7beba2fc
VZ
356 if ( dialog.ShowModal() == wxID_OK )
357 {
358 wxFontData retData = dialog.GetFontData();
359 wxFont font = retData.GetChosenFont();
360
11c7d5b6 361 *info = retData.EncodingInfo();
3a989c8a 362 info->encoding = retData.GetEncoding();
7beba2fc 363
f6bcfd97 364#if wxUSE_CONFIG
6603907d 365 // remember this in the config
e2478fde
VZ
366 wxFontMapperPathChanger path(this,
367 FONTMAPPER_FONT_FROM_ENCODING_PATH);
368 if ( path.IsOk() )
7beba2fc
VZ
369 {
370 GetConfig()->Write(configEntry, info->ToString());
7beba2fc 371 }
bb84929e 372#endif // wxUSE_CONFIG
7beba2fc 373
e2478fde 374 return true;
7beba2fc
VZ
375 }
376 //else: the user canceled the font selection dialog
377 }
6603907d
VZ
378 else
379 {
3a989c8a
VZ
380 // the user doesn't want to select a font for this encoding
381 // or selected to use equivalent encoding
382 //
6603907d
VZ
383 // remember it to avoid asking the same question again later
384#if wxUSE_CONFIG
e2478fde
VZ
385 wxFontMapperPathChanger path(this,
386 FONTMAPPER_FONT_FROM_ENCODING_PATH);
387 if ( path.IsOk() )
6603907d 388 {
3a989c8a
VZ
389 GetConfig()->Write
390 (
391 configEntry,
392 foundEquivEncoding ? info->ToString().c_str()
393 : FONTMAPPER_FONT_DONT_ASK
394 );
6603907d
VZ
395 }
396#endif // wxUSE_CONFIG
397 }
7beba2fc
VZ
398 }
399 //else: we're in non-interactive mode
3379ed37 400#endif // wxUSE_FONTDLG
7beba2fc 401
3a989c8a 402 return foundEquivEncoding;
7beba2fc 403}
6648cd46 404
6648cd46 405bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
e2478fde 406 wxFontEncoding *encodingAlt,
6648cd46
VS
407 const wxString& facename,
408 bool interactive)
409{
410 wxNativeEncodingInfo info;
e2478fde
VZ
411 if ( !GetAltForEncoding(encoding, &info, facename, interactive) )
412 return false;
413
414 wxCHECK_MSG( encodingAlt, false,
415 _T("wxFontEncoding::GetAltForEncoding(): NULL pointer") );
416
417 *encodingAlt = info.encoding;
418
419 return true;
6648cd46
VS
420}
421
6648cd46
VS
422bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding,
423 const wxString& facename)
424{
425 wxNativeEncodingInfo info;
62ea506e 426
e2478fde
VZ
427 if ( !wxGetNativeFontEncoding(encoding, &info) )
428 return false;
3ca6a5f0 429
e2478fde
VZ
430 info.facename = facename;
431 return wxTestFontEncoding(info);
6648cd46 432}
f6bcfd97 433
1e6feb95 434#endif // wxUSE_FONTMAP