#pragma hdrstop
#endif
+#if wxUSE_FONTMAP
+
#ifndef WX_PRECOMP
#include "wx/app.h"
#include "wx/log.h"
#include "wx/intl.h"
#endif // PCH
+#include "wx/module.h"
#include "wx/fontmap.h"
#if wxUSE_CONFIG
// ----------------------------------------------------------------------------
// the config paths we use
+#if wxUSE_CONFIG
static const wxChar* FONTMAPPER_ROOT_PATH = wxT("/wxWindows/FontMapper");
static const wxChar* FONTMAPPER_CHARSET_PATH = wxT("Charsets");
static const wxChar* FONTMAPPER_CHARSET_ALIAS_PATH = wxT("Aliases");
+
+// we only ask questions in GUI mode
#if wxUSE_GUI
static const wxChar* FONTMAPPER_FONT_FROM_ENCODING_PATH = wxT("Encodings");
+ static const wxChar* FONTMAPPER_FONT_DONT_ASK = wxT("none");
#endif // wxUSE_GUI
+#endif // wxUSE_CONFIG
// encodings supported by GetEncodingDescription
static wxFontEncoding gs_encodings[] =
wxFONTENCODING_ISO8859_14,
wxFONTENCODING_ISO8859_15,
wxFONTENCODING_KOI8,
+ wxFONTENCODING_CP932,
+ wxFONTENCODING_CP936,
+ wxFONTENCODING_CP949,
+ wxFONTENCODING_CP950,
wxFONTENCODING_CP1250,
wxFONTENCODING_CP1251,
wxFONTENCODING_CP1252,
wxFONTENCODING_CP1256,
wxFONTENCODING_CP1257,
wxFONTENCODING_CP437,
+ wxFONTENCODING_UTF7,
+ wxFONTENCODING_UTF8,
};
// the descriptions for them
wxTRANSLATE( "Celtic (ISO-8859-14)" ),
wxTRANSLATE( "Western European with Euro (ISO-8859-15)" ),
wxTRANSLATE( "KOI8-R" ),
+ wxTRANSLATE( "Windows Japanese (CP 932)" ),
+ wxTRANSLATE( "Windows Chinese Simplified (CP 936)" ),
+ wxTRANSLATE( "Windows Korean (CP 949)" ),
+ wxTRANSLATE( "Windows Chinese Traditional (CP 950)" ),
wxTRANSLATE( "Windows Central European (CP 1250)" ),
wxTRANSLATE( "Windows Cyrillic (CP 1251)" ),
wxTRANSLATE( "Windows Western European (CP 1252)" ),
wxTRANSLATE( "Windows Arabic (CP 1256)" ),
wxTRANSLATE( "Windows Baltic (CP 1257)" ),
wxTRANSLATE( "Windows/DOS OEM (CP 437)" ),
+ wxTRANSLATE( "Unicode 7 bit (UTF-7)" ),
+ wxTRANSLATE( "Unicode 8 bit (UTF-8)" ),
};
-// and the internal names
+// and the internal names (these are not translated on purpose!)
static const wxChar* gs_encodingNames[] =
{
- wxT( "iso8859-1" ),
- wxT( "iso8859-2" ),
- wxT( "iso8859-3" ),
- wxT( "iso8859-4" ),
- wxT( "iso8859-5" ),
- wxT( "iso8859-6" ),
- wxT( "iso8859-7" ),
- wxT( "iso8859-8" ),
- wxT( "iso8859-9" ),
- wxT( "iso8859-10" ),
- wxT( "iso8859-11" ),
- wxT( "iso8859-12" ),
- wxT( "iso8859-13" ),
- wxT( "iso8859-14" ),
- wxT( "iso8859-15" ),
+ wxT( "iso-8859-1" ),
+ wxT( "iso-8859-2" ),
+ wxT( "iso-8859-3" ),
+ wxT( "iso-8859-4" ),
+ wxT( "iso-8859-5" ),
+ wxT( "iso-8859-6" ),
+ wxT( "iso-8859-7" ),
+ wxT( "iso-8859-8" ),
+ wxT( "iso-8859-9" ),
+ wxT( "iso-8859-10" ),
+ wxT( "iso-8859-11" ),
+ wxT( "iso-8859-12" ),
+ wxT( "iso-8859-13" ),
+ wxT( "iso-8859-14" ),
+ wxT( "iso-8859-15" ),
wxT( "koi8-r" ),
- wxT( "windows1250" ),
- wxT( "windows1251" ),
- wxT( "windows1252" ),
- wxT( "windows1253" ),
- wxT( "windows1254" ),
- wxT( "windows1255" ),
- wxT( "windows1256" ),
- wxT( "windows1257" ),
- wxT( "windows437" ),
+ wxT( "windows-932" ),
+ wxT( "windows-936" ),
+ wxT( "windows-949" ),
+ wxT( "windows-950" ),
+ wxT( "windows-1250" ),
+ wxT( "windows-1251" ),
+ wxT( "windows-1252" ),
+ wxT( "windows-1253" ),
+ wxT( "windows-1254" ),
+ wxT( "windows-1255" ),
+ wxT( "windows-1256" ),
+ wxT( "windows-1257" ),
+ wxT( "windows-437" ),
+ wxT( "utf-7" ),
+ wxT( "utf-8" ),
};
-// ----------------------------------------------------------------------------
-// global data
-// ----------------------------------------------------------------------------
-
-// private object
-static wxFontMapper gs_fontMapper;
-
-// and public pointer
-wxFontMapper * wxTheFontMapper = &gs_fontMapper;
// ----------------------------------------------------------------------------
// private classes
{
#if wxUSE_CONFIG
m_config = NULL;
+ m_configIsDummy = FALSE;
#endif // wxUSE_CONFIG
#if wxUSE_GUI
wxFontMapper::~wxFontMapper()
{
+#if wxUSE_CONFIG
+ if ( m_configIsDummy )
+ delete m_config;
+#endif // wxUSE_CONFIG
+}
+
+wxFontMapper *wxFontMapper::sm_instance = NULL;
+
+/*static*/ wxFontMapper *wxFontMapper::Get()
+{
+ if ( !sm_instance )
+ sm_instance = new wxFontMapper;
+ return sm_instance;
+}
+
+/*static*/ wxFontMapper *wxFontMapper::Set(wxFontMapper *mapper)
+{
+ wxFontMapper *old = sm_instance;
+ sm_instance = mapper;
+ return old;
}
+class wxFontMapperModule: public wxModule
+{
+public:
+ wxFontMapperModule() : wxModule() {}
+ virtual bool OnInit() { return TRUE; }
+ virtual void OnExit() { delete wxFontMapper::Set(NULL); }
+
+ DECLARE_DYNAMIC_CLASS(wxFontMapperModule)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxFontMapperModule, wxModule)
+
// ----------------------------------------------------------------------------
// customisation
// ----------------------------------------------------------------------------
// but will allow us to remember the results of the questions at
// least during this run
m_config = new wxMemoryConfig;
- wxConfig::Set(m_config);
+ m_configIsDummy = TRUE;
+ // VS: we can't call wxConfig::Set(m_config) here because that would
+ // disable automatic wxConfig instance creation if this code was
+ // called before wxApp::OnInit (this happens in wxGTK -- it sets
+ // default wxFont encoding in wxApp::Initialize())
}
}
+ if ( m_configIsDummy && wxConfig::Get(FALSE) != NULL )
+ {
+ // VS: in case we created dummy m_config (see above), we want to switch back
+ // to the real one as soon as one becomes available.
+ delete m_config;
+ m_config = wxConfig::Get(FALSE);
+ m_configIsDummy = FALSE;
+ // FIXME: ideally, we should add keys from dummy config to the real one now,
+ // but it is a low-priority task because typical wxWin application
+ // either doesn't use wxConfig at all or creates wxConfig object in
+ // wxApp::OnInit(), before any real interaction with the user takes
+ // place...
+ }
+
return m_config;
}
/* static */
wxString wxFontMapper::GetEncodingDescription(wxFontEncoding encoding)
{
+ if ( encoding == wxFONTENCODING_DEFAULT )
+ {
+ return _("Default encoding");
+ }
+
size_t count = WXSIZEOF(gs_encodingDescs);
wxASSERT_MSG( count == WXSIZEOF(gs_encodings),
/* static */
wxString wxFontMapper::GetEncodingName(wxFontEncoding encoding)
{
+ if ( encoding == wxFONTENCODING_DEFAULT )
+ {
+ return _("default");
+ }
+
size_t count = WXSIZEOF(gs_encodingNames);
wxASSERT_MSG( count == WXSIZEOF(gs_encodings),
{
if ( gs_encodings[i] == encoding )
{
- return wxGetTranslation(gs_encodingNames[i]);
+ return gs_encodingNames[i];
}
}
wxFontEncoding wxFontMapper::CharsetToEncoding(const wxString& charset,
bool interactive)
{
+ // a special pseudo encoding which means "don't ask me about this charset
+ // any more" - we need it to avoid driving the user crazy with asking him
+ // time after time about the same charset which he [presumably] doesn't
+ // have the fonts fot
+ static const int wxFONTENCODING_UNKNOWN = -2;
+
wxFontEncoding encoding = wxFONTENCODING_SYSTEM;
// we're going to modify it, make a copy
long value = config->Read(charset, -1l);
if ( value != -1 )
{
+ if ( value == wxFONTENCODING_UNKNOWN )
+ {
+ // don't try to find it, in particular don't ask the user
+ return wxFONTENCODING_SYSTEM;
+ }
+
if ( value >= 0 && value <= wxFONTENCODING_MAX )
{
encoding = (wxFontEncoding)value;
RestorePath(pathOld);
}
-#endif
+#endif // wxUSE_CONFIG
- // if didn't find it there, try to reckognise it ourselves
+ // if didn't find it there, try to recognize it ourselves
if ( encoding == wxFONTENCODING_SYSTEM )
{
+ // trim any spaces
+ cs.Trim(TRUE);
+ cs.Trim(FALSE);
+
// discard the optional quotes
- if ( !!cs )
+ if ( !cs.empty() )
{
if ( cs[0u] == _T('"') && cs.Last() == _T('"') )
{
cs.MakeUpper();
- if ( !cs || cs == wxT("US-ASCII") )
+ if ( cs.empty() || cs == _T("US-ASCII") )
+ {
encoding = wxFONTENCODING_DEFAULT;
- else if ( cs == wxT("KOI8-R") || cs == wxT("KOI8-U") )
+ }
+ else if ( cs == wxT("UTF-7") )
+ {
+ encoding = wxFONTENCODING_UTF7;
+ }
+ else if ( cs == wxT("UTF-8") )
+ {
+ encoding = wxFONTENCODING_UTF8;
+ }
+ else if ( cs == wxT("KOI8-R") ||
+ cs == wxT("KOI8-U") ||
+ cs == wxT("KOI8-RU") )
+ {
+ // although koi8-ru is not strictly speaking the same as koi8-r,
+ // they are similar enough to make mapping it to koi8 better than
+ // not reckognizing it at all
encoding = wxFONTENCODING_KOI8;
+ }
else if ( cs.Left(3) == wxT("ISO") )
{
// the dash is optional (or, to be exact, it is not, but
unsigned int value;
if ( wxSscanf(p, wxT("8859-%u"), &value) == 1 )
{
- if ( value < wxFONTENCODING_ISO8859_MAX -
- wxFONTENCODING_ISO8859_1 )
+ // make it 0 based and check that it is strictly positive in
+ // the process (no such thing as iso8859-0 encoding)
+ if ( (value-- > 0) &&
+ (value < wxFONTENCODING_ISO8859_MAX -
+ wxFONTENCODING_ISO8859_1) )
{
// it's a valid ISO8859 encoding
- value += wxFONTENCODING_ISO8859_1 - 1;
+ value += wxFONTENCODING_ISO8859_1;
encoding = (wxFontEncoding)value;
}
}
}
- else if ( cs.Left(8) == wxT("WINDOWS-") )
+ else // check for Windows charsets
{
- int value;
- if ( wxSscanf(cs.c_str() + 8, wxT("%u"), &value) == 1 )
+ size_t len;
+ if ( cs.Left(7) == wxT("WINDOWS") )
+ {
+ len = 7;
+ }
+ else if ( cs.Left(2) == wxT("CP") )
+ {
+ len = 2;
+ }
+ else // not a Windows encoding
+ {
+ len = 0;
+ }
+
+ if ( len )
{
- if ( value >= 1250 )
+ const wxChar *p = cs.c_str() + len;
+ if ( *p == wxT('-') )
+ p++;
+
+ int value;
+ if ( wxSscanf(p, wxT("%u"), &value) == 1 )
{
- value -= 1250;
- if ( value < wxFONTENCODING_CP12_MAX -
- wxFONTENCODING_CP1250 )
+ if ( value >= 1250 )
+ {
+ value -= 1250;
+ if ( value < wxFONTENCODING_CP12_MAX -
+ wxFONTENCODING_CP1250 )
+ {
+ // a valid Windows code page
+ value += wxFONTENCODING_CP1250;
+ encoding = (wxFontEncoding)value;
+ }
+ }
+
+ switch ( value )
{
- // a valid Windows code page
- value += wxFONTENCODING_CP1250;
- encoding = (wxFontEncoding)value;
+ case 932:
+ encoding = wxFONTENCODING_CP932;
+ break;
+
+ case 936:
+ encoding = wxFONTENCODING_CP936;
+ break;
+
+ case 949:
+ encoding = wxFONTENCODING_CP949;
+ break;
+
+ case 950:
+ encoding = wxFONTENCODING_CP950;
+ break;
}
}
}
if ( n != -1 )
{
encoding = gs_encodings[n];
+ }
#if wxUSE_CONFIG
// save the result in the config now
- if ( ChangePath(FONTMAPPER_CHARSET_PATH, &pathOld) )
- {
- wxConfigBase *config = GetConfig();
-
- // remember the alt encoding for this charset
- if ( !config->Write(charset, (long)encoding) )
- {
- wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset.c_str());
- }
+ if ( ChangePath(FONTMAPPER_CHARSET_PATH, &pathOld) )
+ {
+ wxConfigBase *config = GetConfig();
- RestorePath(pathOld);
+ // remember the alt encoding for this charset - or remember that
+ // we don't know it
+ long value = n == -1 ? wxFONTENCODING_UNKNOWN : (long)encoding;
+ if ( !config->Write(charset, value) )
+ {
+ wxLogError(_("Failed to remember the encoding for the charset '%s'."), charset.c_str());
}
-#endif // wxUSE_CONFIG
+
+ RestorePath(pathOld);
}
- //else: cancelled
+#endif // wxUSE_CONFIG
}
#endif // wxUSE_GUI
// message
if ( encoding == wxFONTENCODING_SYSTEM )
{
- wxFatalError(_("can't load any font, aborting"));
+ wxLogFatalError(_("can't load any font, aborting"));
- // wxFatalError doesn't return
+ // wxLogFatalError doesn't return
}
- wxString configEntry, encName = GetEncodingName(encoding);
+ wxString configEntry,
+ encName = GetEncodingName(encoding);
if ( !!facename )
{
configEntry = facename + _T("_");
RestorePath(pathOld);
- if ( !!fontinfo && !!facename )
+ // this special value means that we don't know of fonts for this
+ // encoding but, moreover, have already asked the user as well and he
+ // didn't specify any font neither
+ if ( fontinfo == FONTMAPPER_FONT_DONT_ASK )
{
- // we tried to find a match with facename - now try without it
- fontinfo = config->Read(encName);
+ interactive = FALSE;
}
-
- if ( !!fontinfo )
+ else // use the info entered the last time
{
- if ( info->FromString(fontinfo) )
+ if ( !!fontinfo && !!facename )
{
- if ( wxTestFontEncoding(*info) )
+ // we tried to find a match with facename - now try without it
+ fontinfo = config->Read(encName);
+ }
+
+ if ( !!fontinfo )
+ {
+ if ( info->FromString(fontinfo) )
{
- // ok, got something
- return TRUE;
+ if ( wxTestFontEncoding(*info) )
+ {
+ // ok, got something
+ return TRUE;
+ }
+ //else: no such fonts, look for something else
+ // (should we erase the outdated value?)
+ }
+ else
+ {
+ wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"),
+ fontinfo.c_str());
}
- //else: no such fonts, look for something else
}
- else
+ //else: there is no information in config about this encoding
+ }
+ }
+#endif // wxUSE_CONFIG
+
+ // now try to map this encoding to a compatible one which we have on this
+ // system
+ wxFontEncodingArray equiv = wxEncodingConverter::GetAllEquivalents(encoding);
+ size_t count = equiv.GetCount();
+ bool foundEquivEncoding = FALSE;
+ wxFontEncoding equivEncoding = wxFONTENCODING_SYSTEM;
+ if ( count )
+ {
+ for ( size_t i = 0; i < count && !foundEquivEncoding; i++ )
+ {
+ // don't test for encoding itself, we already know we don't have it
+ if ( equiv[i] == encoding )
+ continue;
+
+ if ( TestAltEncoding(configEntry, equiv[i], info) )
{
- wxLogDebug(wxT("corrupted config data: string '%s' is not a valid font encoding info"), fontinfo.c_str());
+ equivEncoding = equiv[i];
+
+ foundEquivEncoding = TRUE;
}
}
- //else: there is no information in config about this encoding
}
-#endif // wxUSE_CONFIG
// ask the user
+#if wxUSE_FONTDLG
if ( interactive )
{
wxString title(m_titleDialog);
if ( !title )
title << wxTheApp->GetAppName() << _(": unknown encoding");
- // the message
- wxString msg;
- msg.Printf(_("The encoding '%s' is unknown.\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)?"),
- GetEncodingDescription(encoding).c_str());
+ // built the message
+ wxString encDesc = GetEncodingDescription(encoding),
+ msg;
+ if ( foundEquivEncoding )
+ {
+ // ask the user if he wants to override found alternative encoding
+ 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)?"),
+ encDesc.c_str(), GetEncodingDescription(equivEncoding).c_str());
+ }
+ else
+ {
+ 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)?"),
+ encDesc.c_str());
+ }
- wxWindow *parent = m_windowParent;
- if ( !parent )
- parent = wxTheApp->GetTopWindow();
+ // the question is different in 2 cases so the answer has to be
+ // interpreted differently as well
+ int answer = foundEquivEncoding ? wxNO : wxYES;
if ( wxMessageBox(msg, title,
- wxICON_QUESTION | wxYES_NO, parent) == wxYES )
+ wxICON_QUESTION | wxYES_NO,
+ m_windowParent) == answer )
{
wxFontData data;
data.SetEncoding(encoding);
data.EncodingInfo() = *info;
- wxFontDialog dialog(parent, &data);
+ wxFontDialog dialog(m_windowParent, data);
if ( dialog.ShowModal() == wxID_OK )
{
wxFontData retData = dialog.GetFontData();
RestorePath(pathOld);
}
-#endif
+#endif // wxUSE_CONFIG
return TRUE;
}
//else: the user canceled the font selection dialog
}
- //else: the user doesn't want to select a font
- }
- //else: we're in non-interactive mode
-
- // now try the default mappings:
- wxFontEncodingArray equiv = wxEncodingConverter::GetAllEquivalents(encoding);
- size_t count = equiv.GetCount();
- if ( count )
- {
- for ( size_t i = (equiv[0] == encoding) ? 1 : 0; i < count; i++ )
+ else
{
- if ( TestAltEncoding(configEntry, equiv[i], info) )
- return TRUE;
+ // the user doesn't want to select a font for this encoding
+ // or selected to use equivalent encoding
+ //
+ // remember it to avoid asking the same question again later
+#if wxUSE_CONFIG
+ if ( ChangePath(FONTMAPPER_FONT_FROM_ENCODING_PATH, &pathOld) )
+ {
+ GetConfig()->Write
+ (
+ configEntry,
+ foundEquivEncoding ? info->ToString().c_str()
+ : FONTMAPPER_FONT_DONT_ASK
+ );
+
+ RestorePath(pathOld);
+ }
+#endif // wxUSE_CONFIG
}
}
+ //else: we're in non-interactive mode
+#endif // wxUSE_FONTDLG
- return FALSE;
+ return foundEquivEncoding;
}
bool wxFontMapper::GetAltForEncoding(wxFontEncoding encoding,
}
#endif // wxUSE_GUI
+
+#endif // wxUSE_FONTMAP