]> git.saurik.com Git - wxWidgets.git/blob - src/common/fontmap.cpp
Partially applied patch [ 763900 ] fix for vertical toolbar
[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) 1999-2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // Licence: wxWindows licence
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 #if wxUSE_FONTMAP
32
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"
40 #include "wx/fmappriv.h"
41
42 #if wxUSE_CONFIG
43 #include "wx/config.h"
44 #endif // wxUSE_CONFIG
45
46 #include "wx/fontutil.h"
47 #include "wx/msgdlg.h"
48 #include "wx/fontdlg.h"
49 #include "wx/choicdlg.h"
50
51 #include "wx/encconv.h"
52
53 // ----------------------------------------------------------------------------
54 // constants
55 // ----------------------------------------------------------------------------
56
57 // the config paths we use
58 #if wxUSE_CONFIG
59
60 static const wxChar* FONTMAPPER_FONT_FROM_ENCODING_PATH = wxT("Encodings");
61 static const wxChar* FONTMAPPER_FONT_DONT_ASK = wxT("none");
62
63 #endif // wxUSE_CONFIG
64
65 // ----------------------------------------------------------------------------
66 // private classes
67 // ----------------------------------------------------------------------------
68
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
75 {
76 public:
77 ReentrancyBlocker(bool& flag) : m_flagOld(flag), m_flag(flag)
78 { m_flag = true; }
79 ~ReentrancyBlocker() { m_flag = m_flagOld; }
80
81 private:
82 bool m_flagOld;
83 bool& m_flag;
84 };
85
86 // ============================================================================
87 // implementation
88 // ============================================================================
89
90 // ----------------------------------------------------------------------------
91 // ctor and dtor
92 // ----------------------------------------------------------------------------
93
94 wxFontMapper::wxFontMapper()
95 {
96 m_windowParent = NULL;
97 }
98
99 wxFontMapper::~wxFontMapper()
100 {
101 }
102
103 wxFontEncoding
104 wxFontMapper::CharsetToEncoding(const wxString& charset, bool interactive)
105 {
106 // try the ways not needing the users intervention first
107 wxFontEncoding
108 encoding = wxFontMapperBase::CharsetToEncoding(charset, interactive);
109
110 // if we failed to find the encoding, ask the user -- unless disabled
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;
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());
123
124 // the list of choices
125 const size_t count = GetSupportedEncodingsCount();
126
127 wxString *encodingNamesTranslated = new wxString[count];
128
129 for ( size_t i = 0; i < count; i++ )
130 {
131 encodingNamesTranslated[i] = GetEncodingDescription(GetEncoding(i));
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 {
149 encoding = GetEncoding(n);
150 }
151
152 #if wxUSE_CONFIG
153 // save the result in the config now
154 wxFontMapperPathChanger path(this, FONTMAPPER_CHARSET_PATH);
155 if ( path.IsOk() )
156 {
157 wxConfigBase *config = GetConfig();
158
159 // remember the alt encoding for this charset -- or remember that
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());
165 }
166 }
167 #endif // wxUSE_CONFIG
168 }
169
170 return encoding;
171 }
172
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
179 bool wxFontMapper::TestAltEncoding(const wxString& configEntry,
180 wxFontEncoding encReplacement,
181 wxNativeEncodingInfo *info)
182 {
183 if ( wxGetNativeFontEncoding(encReplacement, info) &&
184 wxTestFontEncoding(*info) )
185 {
186 #if wxUSE_CONFIG
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 }
194 #endif // wxUSE_CONFIG
195 return true;
196 }
197
198 return false;
199 }
200
201 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
202 wxNativeEncodingInfo *info,
203 const wxString& facename,
204 bool interactive)
205 {
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
211 // GetAltForEncoding() -- and it is impossible to catch this from the user
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
216 static bool s_inGetAltForEncoding = false;
217
218 if ( interactive && s_inGetAltForEncoding )
219 return false;
220
221 ReentrancyBlocker blocker(s_inGetAltForEncoding);
222 #endif // wxUSE_GUI
223
224 wxCHECK_MSG( info, false, wxT("bad pointer in GetAltForEncoding") );
225
226 info->facename = facename;
227
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
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
236 // message
237 if ( encoding == wxFONTENCODING_SYSTEM )
238 {
239 wxLogFatalError(_("can't load any font, aborting"));
240
241 // wxLogFatalError doesn't return
242 }
243
244 wxString configEntry,
245 encName = GetEncodingName(encoding);
246 if ( !!facename )
247 {
248 configEntry = facename + _T("_");
249 }
250 configEntry += encName;
251
252 #if wxUSE_CONFIG
253 // do we have a font spec for this encoding?
254 wxString fontinfo;
255 wxFontMapperPathChanger path(this, FONTMAPPER_FONT_FROM_ENCODING_PATH);
256 if ( path.IsOk() )
257 {
258 fontinfo = GetConfig()->Read(configEntry);
259 }
260
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 )
271 {
272 // we tried to find a match with facename -- now try without it
273 fontinfo = GetConfig()->Read(encName);
274 }
275
276 if ( !!fontinfo )
277 {
278 if ( info->FromString(fontinfo) )
279 {
280 if ( wxTestFontEncoding(*info) )
281 {
282 // ok, got something
283 return true;
284 }
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());
292 }
293 }
294 //else: there is no information in config about this encoding
295 }
296 #endif // wxUSE_CONFIG
297
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();
302 bool foundEquivEncoding = false;
303 wxFontEncoding equivEncoding = wxFONTENCODING_SYSTEM;
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
316 foundEquivEncoding = true;
317 }
318 }
319 }
320
321 // ask the user
322 #if wxUSE_FONTDLG
323 if ( interactive )
324 {
325 wxString title(m_titleDialog);
326 if ( !title )
327 title << wxTheApp->GetAppName() << _(": unknown encoding");
328
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 }
343
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;
347
348 if ( wxMessageBox(msg, title,
349 wxICON_QUESTION | wxYES_NO,
350 m_windowParent) == answer )
351 {
352 wxFontData data;
353 data.SetEncoding(encoding);
354 data.EncodingInfo() = *info;
355 wxFontDialog dialog(m_windowParent, data);
356 if ( dialog.ShowModal() == wxID_OK )
357 {
358 wxFontData retData = dialog.GetFontData();
359 wxFont font = retData.GetChosenFont();
360
361 *info = retData.EncodingInfo();
362 info->encoding = retData.GetEncoding();
363
364 #if wxUSE_CONFIG
365 // remember this in the config
366 wxFontMapperPathChanger path(this,
367 FONTMAPPER_FONT_FROM_ENCODING_PATH);
368 if ( path.IsOk() )
369 {
370 GetConfig()->Write(configEntry, info->ToString());
371 }
372 #endif // wxUSE_CONFIG
373
374 return true;
375 }
376 //else: the user canceled the font selection dialog
377 }
378 else
379 {
380 // the user doesn't want to select a font for this encoding
381 // or selected to use equivalent encoding
382 //
383 // remember it to avoid asking the same question again later
384 #if wxUSE_CONFIG
385 wxFontMapperPathChanger path(this,
386 FONTMAPPER_FONT_FROM_ENCODING_PATH);
387 if ( path.IsOk() )
388 {
389 GetConfig()->Write
390 (
391 configEntry,
392 foundEquivEncoding ? info->ToString().c_str()
393 : FONTMAPPER_FONT_DONT_ASK
394 );
395 }
396 #endif // wxUSE_CONFIG
397 }
398 }
399 //else: we're in non-interactive mode
400 #endif // wxUSE_FONTDLG
401
402 return foundEquivEncoding;
403 }
404
405 bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
406 wxFontEncoding *encodingAlt,
407 const wxString& facename,
408 bool interactive)
409 {
410 wxNativeEncodingInfo info;
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;
420 }
421
422 bool wxFontMapper::IsEncodingAvailable(wxFontEncoding encoding,
423 const wxString& facename)
424 {
425 wxNativeEncodingInfo info;
426
427 if ( !wxGetNativeFontEncoding(encoding, &info) )
428 return false;
429
430 info.facename = facename;
431 return wxTestFontEncoding(info);
432 }
433
434 #endif // wxUSE_FONTMAP