/////////////////////////////////////////////////////////////////////////////
#ifdef __GNUG__
- #pragma implementation "mimetype.h"
+#pragma implementation "mimetype.h"
#endif
-// ============================================================================
-// declarations
-// ============================================================================
-
-// ----------------------------------------------------------------------------
-// headers
-// ----------------------------------------------------------------------------
-
// for compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
- #pragma hdrstop
+ #pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+ #include "wx/defs.h"
#endif
-// wxWindows
+#if (wxUSE_FILE && wxUSE_TEXTFILE) || defined(__WXMSW__)
+
#ifndef WX_PRECOMP
- #include "wx/string.h"
- #include "wx/icon.h"
+ #include "wx/string.h"
+ #if wxUSE_GUI
+ #include "wx/icon.h"
+ #endif
#endif //WX_PRECOMP
// Doesn't compile in WIN16 mode
#ifndef __WIN16__
#include "wx/log.h"
+#include "wx/file.h"
#include "wx/intl.h"
#include "wx/dynarray.h"
#include "wx/confbase.h"
#ifdef __WXMSW__
#include "wx/msw/registry.h"
#include "windows.h"
-#else // Unix
+#elif defined(__UNIX__) || defined(__WXPM__)
+ #include "wx/ffile.h"
#include "wx/textfile.h"
+ #include "wx/dir.h"
+ #include "wx/utils.h"
#endif // OS
#include "wx/mimetype.h"
// other standard headers
#include <ctype.h>
+// in case we're compiling in non-GUI mode
+class WXDLLEXPORT wxIcon;
+
// ----------------------------------------------------------------------------
// private classes
// ----------------------------------------------------------------------------
// to open/print the file (the positional parameters are introduced by %1,
// %2, ... in these strings, we change them to %s ourselves)
+// although I don't know of any official documentation which mentions this
+// location, uses it, so it isn't likely to change
+static const wxChar *MIME_DATABASE_KEY = wxT("MIME\\Database\\Content Type\\");
+
class wxFileTypeImpl
{
public:
// ctor
- wxFileTypeImpl() { }
+ wxFileTypeImpl() { m_info = NULL; }
- // initialize us with our file type name
- void SetFileType(const wxString& strFileType)
- { m_strFileType = strFileType; }
- void SetExt(const wxString& ext)
- { m_ext = ext; }
+ // one of these Init() function must be called (ctor can't take any
+ // arguments because it's common)
+
+ // initialize us with our file type name and extension - in this case
+ // we will read all other data from the registry
+ void Init(const wxString& strFileType, const wxString& ext)
+ { m_strFileType = strFileType; m_ext = ext; }
+
+ // initialize us with a wxFileTypeInfo object - it contains all the
+ // data
+ void Init(const wxFileTypeInfo& info)
+ { m_info = &info; }
// implement accessor functions
bool GetExtensions(wxArrayString& extensions);
bool GetIcon(wxIcon *icon) const;
bool GetDescription(wxString *desc) const;
bool GetOpenCommand(wxString *openCmd,
- const wxFileType::MessageParameters&) const
- { return GetCommand(openCmd, "open"); }
+ const wxFileType::MessageParameters& params) const;
bool GetPrintCommand(wxString *printCmd,
- const wxFileType::MessageParameters&) const
- { return GetCommand(printCmd, "print"); }
+ const wxFileType::MessageParameters& params) const;
private:
- // helper function
- bool GetCommand(wxString *command, const char *verb) const;
-
- wxString m_strFileType, m_ext;
+ // helper function: reads the command corresponding to the specified verb
+ // from the registry (returns an empty string if not found)
+ wxString GetCommand(const wxChar *verb) const;
+
+ // we use either m_info or read the data from the registry if m_info == NULL
+ const wxFileTypeInfo *m_info;
+ wxString m_strFileType, // may be empty
+ m_ext;
};
+WX_DECLARE_EXPORTED_OBJARRAY(wxFileTypeInfo, wxArrayFileTypeInfo);
+#include "wx/arrimpl.cpp"
+WX_DEFINE_OBJARRAY(wxArrayFileTypeInfo);
+
class wxMimeTypesManagerImpl
{
public:
wxFileType *GetFileTypeFromExtension(const wxString& ext);
wxFileType *GetFileTypeFromMimeType(const wxString& mimeType);
+ size_t EnumAllFileTypes(wxArrayString& mimetypes);
+
// this are NOPs under Windows
- bool ReadMailcap(const wxString& filename, bool fallback = TRUE) { }
- bool ReadMimeTypes(const wxString& filename) { }
+ bool ReadMailcap(const wxString& filename, bool fallback = TRUE)
+ { return TRUE; }
+ bool ReadMimeTypes(const wxString& filename)
+ { return TRUE; }
+
+ void AddFallback(const wxFileTypeInfo& ft) { m_fallbacks.Add(ft); }
+
+private:
+ wxArrayFileTypeInfo m_fallbacks;
+};
+
+#elif defined( __WXMAC__ )
+
+WX_DECLARE_EXPORTED_OBJARRAY(wxFileTypeInfo, wxArrayFileTypeInfo);
+#include "wx/arrimpl.cpp"
+WX_DEFINE_OBJARRAY(wxArrayFileTypeInfo);
+
+class wxMimeTypesManagerImpl
+{
+public :
+ wxMimeTypesManagerImpl() { }
+
+ // implement containing class functions
+ wxFileType *GetFileTypeFromExtension(const wxString& ext);
+ wxFileType *GetFileTypeFromMimeType(const wxString& mimeType);
+
+ size_t EnumAllFileTypes(wxArrayString& mimetypes);
+
+ // this are NOPs under MacOS
+ bool ReadMailcap(const wxString& filename, bool fallback = TRUE) { return TRUE; }
+ bool ReadMimeTypes(const wxString& filename) { return TRUE; }
+
+ void AddFallback(const wxFileTypeInfo& ft) { m_fallbacks.Add(ft); }
+
+private:
+ wxArrayFileTypeInfo m_fallbacks;
+};
+
+class wxFileTypeImpl
+{
+public:
+ // initialize us with our file type name
+ void SetFileType(const wxString& strFileType)
+ { m_strFileType = strFileType; }
+ void SetExt(const wxString& ext)
+ { m_ext = ext; }
+
+ // implement accessor functions
+ bool GetExtensions(wxArrayString& extensions);
+ bool GetMimeType(wxString *mimeType) const;
+ bool GetIcon(wxIcon *icon) const;
+ bool GetDescription(wxString *desc) const;
+ bool GetOpenCommand(wxString *openCmd,
+ const wxFileType::MessageParameters&) const
+ { return GetCommand(openCmd, "open"); }
+ bool GetPrintCommand(wxString *printCmd,
+ const wxFileType::MessageParameters&) const
+ { return GetCommand(printCmd, "print"); }
+
+private:
+ // helper function
+ bool GetCommand(wxString *command, const char *verb) const;
+
+ wxString m_strFileType, m_ext;
};
#else // Unix
break;
}
- wxASSERT_MSG( n == pos, "invalid position in MailCapEntry::Insert" );
+ wxASSERT_MSG( n == pos, wxT("invalid position in MailCapEntry::Insert") );
m_next = cur->m_next;
cur->m_next = this;
// append this element to the list
void Append(MailCapEntry *next)
{
- wxCHECK_RET( next != NULL, "Append()ing to what?" );
+ wxCHECK_RET( next != NULL, wxT("Append()ing to what?") );
// FIXME slooow...
MailCapEntry *cur;
cur->m_next = this;
- wxASSERT_MSG( !m_next, "Append()ing element already in the list?" );
+ wxASSERT_MSG( !m_next, wxT("Append()ing element already in the list?") );
}
private:
WX_DEFINE_ARRAY(MailCapEntry *, ArrayTypeEntries);
+// the base class which may be used to find an icon for the MIME type
+class wxMimeTypeIconHandler
+{
+public:
+ virtual bool GetIcon(const wxString& mimetype, wxIcon *icon) = 0;
+};
+
+WX_DEFINE_ARRAY(wxMimeTypeIconHandler *, ArrayIconHandlers);
+
+// the icon handler which uses GNOME MIME database
+class wxGNOMEIconHandler : public wxMimeTypeIconHandler
+{
+public:
+ virtual bool GetIcon(const wxString& mimetype, wxIcon *icon);
+
+private:
+ void Init();
+ void LoadIconsFromKeyFile(const wxString& filename);
+ void LoadKeyFilesFromDir(const wxString& dirbase);
+
+ static bool m_inited;
+
+ static wxSortedArrayString ms_mimetypes;
+ static wxArrayString ms_icons;
+};
+
+// the icon handler which uses KDE MIME database
+class wxKDEIconHandler : public wxMimeTypeIconHandler
+{
+public:
+ virtual bool GetIcon(const wxString& mimetype, wxIcon *icon);
+
+private:
+ void LoadLinksForMimeSubtype(const wxString& dirbase,
+ const wxString& subdir,
+ const wxString& filename);
+ void LoadLinksForMimeType(const wxString& dirbase,
+ const wxString& subdir);
+ void LoadLinkFilesFromDir(const wxString& dirbase);
+ void Init();
+
+ static bool m_inited;
+
+ static wxSortedArrayString ms_mimetypes;
+ static wxArrayString ms_icons;
+};
+
+// this is the real wxMimeTypesManager for Unix
class wxMimeTypesManagerImpl
{
friend class wxFileTypeImpl; // give it access to m_aXXX variables
wxFileType *GetFileTypeFromExtension(const wxString& ext);
wxFileType *GetFileTypeFromMimeType(const wxString& mimeType);
+ size_t EnumAllFileTypes(wxArrayString& mimetypes);
+
bool ReadMailcap(const wxString& filename, bool fallback = FALSE);
bool ReadMimeTypes(const wxString& filename);
+ void AddFallback(const wxFileTypeInfo& filetype);
+
+ // add information about the given mimetype
+ void AddMimeTypeInfo(const wxString& mimetype,
+ const wxString& extensions,
+ const wxString& description);
+ void AddMailcapInfo(const wxString& strType,
+ const wxString& strOpenCmd,
+ const wxString& strPrintCmd,
+ const wxString& strTest,
+ const wxString& strDesc);
+
// accessors
// get the string containing space separated extensions for the given
// file type
wxString GetExtension(size_t index) { return m_aExtensions[index]; }
+ // get the array of icon handlers
+ static ArrayIconHandlers& GetIconHandlers();
+
private:
wxArrayString m_aTypes, // MIME types
m_aDescriptions, // descriptions (just some text)
m_aExtensions; // space separated list of extensions
ArrayTypeEntries m_aEntries; // commands and tests for this file type
+
+ // head of the linked list of the icon handlers
+ static ArrayIconHandlers ms_iconHandlers;
};
class wxFileTypeImpl
bool GetExtensions(wxArrayString& extensions);
bool GetMimeType(wxString *mimeType) const
{ *mimeType = m_manager->m_aTypes[m_index]; return TRUE; }
- bool GetIcon(wxIcon * WXUNUSED(icon)) const
- { return FALSE; } // TODO maybe with Gnome/KDE integration...
+ bool GetIcon(wxIcon *icon) const;
bool GetDescription(wxString *desc) const
{ *desc = m_manager->m_aDescriptions[m_index]; return TRUE; }
#endif // OS type
+// ============================================================================
+// common classes
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// wxFileTypeInfo
+// ----------------------------------------------------------------------------
+
+wxFileTypeInfo::wxFileTypeInfo(const char *mimeType,
+ const char *openCmd,
+ const char *printCmd,
+ const char *desc,
+ ...)
+ : m_mimeType(mimeType),
+ m_openCmd(openCmd),
+ m_printCmd(printCmd),
+ m_desc(desc)
+{
+ va_list argptr;
+ va_start(argptr, desc);
+
+ for ( ;; )
+ {
+ const char *ext = va_arg(argptr, const char *);
+ if ( !ext )
+ {
+ // NULL terminates the list
+ break;
+ }
+
+ m_exts.Add(ext);
+ }
+
+ va_end(argptr);
+}
+
// ============================================================================
// implementation of the wrapper classes
// ============================================================================
bool hasFilename = FALSE;
wxString str;
- for ( const char *pc = command.c_str(); *pc != '\0'; pc++ ) {
- if ( *pc == '%' ) {
+ for ( const wxChar *pc = command.c_str(); *pc != wxT('\0'); pc++ ) {
+ if ( *pc == wxT('%') ) {
switch ( *++pc ) {
- case 's':
+ case wxT('s'):
// '%s' expands into file name (quoted because it might
// contain spaces) - except if there are already quotes
// there because otherwise some programs may get confused
// by double double quotes
#if 0
- if ( *(pc - 2) == '"' )
+ if ( *(pc - 2) == wxT('"') )
str << params.GetFileName();
else
- str << '"' << params.GetFileName() << '"';
+ str << wxT('"') << params.GetFileName() << wxT('"');
#endif
str << params.GetFileName();
hasFilename = TRUE;
break;
- case 't':
+ case wxT('t'):
// '%t' expands into MIME type (quote it too just to be
// consistent)
- str << '\'' << params.GetMimeType() << '\'';
+ str << wxT('\'') << params.GetMimeType() << wxT('\'');
break;
- case '{':
+ case wxT('{'):
{
- const char *pEnd = strchr(pc, '}');
+ const wxChar *pEnd = wxStrchr(pc, wxT('}'));
if ( pEnd == NULL ) {
wxString mimetype;
wxLogWarning(_("Unmatched '{' in an entry for "
"mime type %s."),
params.GetMimeType().c_str());
- str << "%{";
+ str << wxT("%{");
}
else {
wxString param(pc + 1, pEnd - pc - 1);
- str << '\'' << params.GetParamValue(param) << '\'';
+ str << wxT('\'') << params.GetParamValue(param) << wxT('\'');
pc = pEnd;
}
}
break;
- case 'n':
- case 'F':
+ case wxT('n'):
+ case wxT('F'):
// TODO %n is the number of parts, %F is an array containing
// the names of temp files these parts were written to
// and their mime types.
break;
default:
- wxLogDebug("Unknown field %%%c in command '%s'.",
+ wxLogDebug(wxT("Unknown field %%%c in command '%s'."),
*pc, command.c_str());
str << *pc;
}
// metamail(1) man page states that if the mailcap entry doesn't have '%s'
// the program will accept the data on stdin: so give it to it!
if ( !hasFilename && !str.IsEmpty() ) {
- str << " < '" << params.GetFileName() << '\'';
+ str << wxT(" < '") << params.GetFileName() << wxT('\'');
}
return str;
bool wxMimeTypesManager::IsOfType(const wxString& mimeType,
const wxString& wildcard)
{
- wxASSERT_MSG( mimeType.Find('*') == wxNOT_FOUND,
- "first MIME type can't contain wildcards" );
+ wxASSERT_MSG( mimeType.Find(wxT('*')) == wxNOT_FOUND,
+ wxT("first MIME type can't contain wildcards") );
// all comparaisons are case insensitive (2nd arg of IsSameAs() is FALSE)
- if ( wildcard.BeforeFirst('/').IsSameAs(mimeType.BeforeFirst('/'), FALSE) )
+ if ( wildcard.BeforeFirst(wxT('/')).IsSameAs(mimeType.BeforeFirst(wxT('/')), FALSE) )
{
- wxString strSubtype = wildcard.AfterFirst('/');
+ wxString strSubtype = wildcard.AfterFirst(wxT('/'));
- if ( strSubtype == '*' ||
- strSubtype.IsSameAs(mimeType.AfterFirst('/'), FALSE) )
+ if ( strSubtype == wxT("*") ||
+ strSubtype.IsSameAs(mimeType.AfterFirst(wxT('/')), FALSE) )
{
// matches (either exactly or it's a wildcard)
return TRUE;
return m_impl->ReadMimeTypes(filename);
}
+void wxMimeTypesManager::AddFallbacks(const wxFileTypeInfo *filetypes)
+{
+ for ( const wxFileTypeInfo *ft = filetypes; ft->IsValid(); ft++ ) {
+ m_impl->AddFallback(*ft);
+ }
+}
+
+size_t wxMimeTypesManager::EnumAllFileTypes(wxArrayString& mimetypes)
+{
+ return m_impl->EnumAllFileTypes(mimetypes);
+}
+
// ============================================================================
// real (OS specific) implementation
// ============================================================================
#ifdef __WXMSW__
-bool wxFileTypeImpl::GetCommand(wxString *command, const char *verb) const
+wxString wxFileTypeImpl::GetCommand(const wxChar *verb) const
{
// suppress possible error messages
wxLogNull nolog;
wxString strKey;
- strKey << m_strFileType << "\\shell\\" << verb << "\\command";
- wxRegKey key(wxRegKey::HKCR, strKey);
+ if ( wxRegKey(wxRegKey::HKCR, m_ext + _T("\\shell")).Exists() )
+ strKey = m_ext;
+ if ( wxRegKey(wxRegKey::HKCR, m_strFileType + _T("\\shell")).Exists() )
+ strKey = m_strFileType;
+
+ if ( !strKey )
+ {
+ // no info
+ return wxEmptyString;
+ }
+
+ strKey << wxT("\\shell\\") << verb << wxT("\\command");
+ wxRegKey key(wxRegKey::HKCR, strKey);
+ wxString command;
if ( key.Open() ) {
// it's the default value of the key
- if ( key.QueryValue("", *command) ) {
+ if ( key.QueryValue(wxT(""), command) ) {
// transform it from '%1' to '%s' style format string
+
// NB: we don't make any attempt to verify that the string is valid,
// i.e. doesn't contain %2, or second %1 or .... But we do make
// sure that we return a string with _exactly_ one '%s'!
- size_t len = command->Len();
- for ( size_t n = 0; n < len; n++ ) {
- if ( command->GetChar(n) == '%' &&
- (n + 1 < len) && command->GetChar(n + 1) == '1' ) {
+ bool foundFilename = FALSE;
+ size_t len = command.Len();
+ for ( size_t n = 0; (n < len) && !foundFilename; n++ ) {
+ if ( command[n] == wxT('%') &&
+ (n + 1 < len) && command[n + 1] == wxT('1') ) {
// replace it with '%s'
- command->SetChar(n + 1, 's');
+ command[n + 1] = wxT('s');
- return TRUE;
+ foundFilename = TRUE;
}
}
- // we didn't find any '%1'!
- // HACK: append the filename at the end, hope that it will do
- *command << " %s";
-
- return TRUE;
+ if ( !foundFilename ) {
+ // we didn't find any '%1'!
+ // HACK: append the filename at the end, hope that it will do
+ command << wxT(" %s");
+ }
}
}
+ //else: no such file type or no value, will return empty string
- // no such file type or no value
- return FALSE;
+ return command;
+}
+
+bool
+wxFileTypeImpl::GetOpenCommand(wxString *openCmd,
+ const wxFileType::MessageParameters& params)
+ const
+{
+ wxString cmd;
+ if ( m_info ) {
+ cmd = m_info->GetOpenCommand();
+ }
+ else {
+ cmd = GetCommand(wxT("open"));
+ }
+
+ *openCmd = wxFileType::ExpandCommand(cmd, params);
+
+ return !openCmd->IsEmpty();
+}
+
+bool
+wxFileTypeImpl::GetPrintCommand(wxString *printCmd,
+ const wxFileType::MessageParameters& params)
+ const
+{
+ wxString cmd;
+ if ( m_info ) {
+ cmd = m_info->GetPrintCommand();
+ }
+ else {
+ cmd = GetCommand(wxT("print"));
+ }
+
+ *printCmd = wxFileType::ExpandCommand(cmd, params);
+
+ return !printCmd->IsEmpty();
}
// TODO this function is half implemented
bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions)
{
- if ( m_ext.IsEmpty() ) {
+ if ( m_info ) {
+ extensions = m_info->GetExtensions();
+
+ return TRUE;
+ }
+ else if ( m_ext.IsEmpty() ) {
// the only way to get the list of extensions from the file type is to
// scan through all extensions in the registry - too slow...
return FALSE;
bool wxFileTypeImpl::GetMimeType(wxString *mimeType) const
{
+ if ( m_info ) {
+ // we already have it
+ *mimeType = m_info->GetMimeType();
+
+ return TRUE;
+ }
+
// suppress possible error messages
wxLogNull nolog;
- wxRegKey key(wxRegKey::HKCR, /*m_strFileType*/ "." + m_ext);
- if ( key.Open() && key.QueryValue("Content Type", *mimeType) ) {
+ wxRegKey key(wxRegKey::HKCR, wxT(".") + m_ext);
+ if ( key.Open() && key.QueryValue(wxT("Content Type"), *mimeType) ) {
return TRUE;
}
else {
bool wxFileTypeImpl::GetIcon(wxIcon *icon) const
{
+#if wxUSE_GUI
+ if ( m_info ) {
+ // we don't have icons in the fallback resources
+ return FALSE;
+ }
+
wxString strIconKey;
- strIconKey << m_strFileType << "\\DefaultIcon";
+ strIconKey << m_strFileType << wxT("\\DefaultIcon");
// suppress possible error messages
wxLogNull nolog;
if ( key.Open() ) {
wxString strIcon;
// it's the default value of the key
- if ( key.QueryValue("", strIcon) ) {
+ if ( key.QueryValue(wxT(""), strIcon) ) {
// the format is the following: <full path to file>, <icon index>
// NB: icon index may be negative as well as positive and the full
// path may contain the environment variables inside '%'
- wxString strFullPath = strIcon.BeforeLast(','),
- strIndex = strIcon.AfterLast(',');
+ wxString strFullPath = strIcon.BeforeLast(wxT(',')),
+ strIndex = strIcon.AfterLast(wxT(','));
// index may be omitted, in which case BeforeLast(',') is empty and
// AfterLast(',') is the whole string
if ( strFullPath.IsEmpty() ) {
strFullPath = strIndex;
- strIndex = "0";
+ strIndex = wxT("0");
}
wxString strExpPath = wxExpandEnvVars(strFullPath);
- int nIndex = atoi(strIndex);
+ int nIndex = wxAtoi(strIndex);
HICON hIcon = ExtractIcon(GetModuleHandle(NULL), strExpPath, nIndex);
switch ( (int)hIcon ) {
case 0: // means no icons were found
case 1: // means no such file or it wasn't a DLL/EXE/OCX/ICO/...
- wxLogDebug("incorrect registry entry '%s': no such icon.",
+ wxLogDebug(wxT("incorrect registry entry '%s': no such icon."),
key.GetName().c_str());
break;
}
// no such file type or no value or incorrect icon entry
+#endif // wxUSE_GUI
+
return FALSE;
}
bool wxFileTypeImpl::GetDescription(wxString *desc) const
{
+ if ( m_info ) {
+ // we already have it
+ *desc = m_info->GetDescription();
+
+ return TRUE;
+ }
+
// suppress possible error messages
wxLogNull nolog;
wxRegKey key(wxRegKey::HKCR, m_strFileType);
if ( key.Open() ) {
// it's the default value of the key
- if ( key.QueryValue("", *desc) ) {
+ if ( key.QueryValue(wxT(""), *desc) ) {
return TRUE;
}
}
{
// add the leading point if necessary
wxString str;
- if ( ext[0u] != '.' ) {
- str = '.';
+ if ( ext[0u] != wxT('.') ) {
+ str = wxT('.');
}
str << ext;
// suppress possible error messages
wxLogNull nolog;
+ bool knownExtension = FALSE;
+
wxString strFileType;
wxRegKey key(wxRegKey::HKCR, str);
if ( key.Open() ) {
// it's the default value of the key
- if ( key.QueryValue("", strFileType) ) {
+ if ( key.QueryValue(wxT(""), strFileType) ) {
// create the new wxFileType object
wxFileType *fileType = new wxFileType;
- fileType->m_impl->SetFileType(strFileType);
- fileType->m_impl->SetExt(ext);
+ fileType->m_impl->Init(strFileType, ext);
+
+ return fileType;
+ }
+ else {
+ // this extension doesn't have a filetype, but it's known to the
+ // system and may be has some other useful keys (open command or
+ // content-type), so still return a file type object for it
+ knownExtension = TRUE;
+ }
+ }
+
+ // check the fallbacks
+ // TODO linear search is potentially slow, perhaps we should use a sorted
+ // array?
+ size_t count = m_fallbacks.GetCount();
+ for ( size_t n = 0; n < count; n++ ) {
+ if ( m_fallbacks[n].GetExtensions().Index(ext) != wxNOT_FOUND ) {
+ wxFileType *fileType = new wxFileType;
+ fileType->m_impl->Init(m_fallbacks[n]);
return fileType;
}
}
- // unknown extension
- return NULL;
+ if ( knownExtension )
+ {
+ wxFileType *fileType = new wxFileType;
+ fileType->m_impl->Init(wxEmptyString, ext);
+
+ return fileType;
+ }
+ else
+ {
+ // unknown extension
+ return NULL;
+ }
}
// MIME type -> extension -> file type
wxFileType *
wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType)
{
- // HACK I don't know of any official documentation which mentions this
- // location, but as a matter of fact IE uses it, so why not we?
- static const char *szMimeDbase = "MIME\\Database\\Content Type\\";
-
- wxString strKey = szMimeDbase;
+ wxString strKey = MIME_DATABASE_KEY;
strKey << mimeType;
// suppress possible error messages
wxString ext;
wxRegKey key(wxRegKey::HKCR, strKey);
if ( key.Open() ) {
- if ( key.QueryValue("Extension", ext) ) {
+ if ( key.QueryValue(wxT("Extension"), ext) ) {
return GetFileTypeFromExtension(ext);
}
}
+ // check the fallbacks
+ // TODO linear search is potentially slow, perhaps we should use a sorted
+ // array?
+ size_t count = m_fallbacks.GetCount();
+ for ( size_t n = 0; n < count; n++ ) {
+ if ( wxMimeTypesManager::IsOfType(mimeType,
+ m_fallbacks[n].GetMimeType()) ) {
+ wxFileType *fileType = new wxFileType;
+ fileType->m_impl->Init(m_fallbacks[n]);
+
+ return fileType;
+ }
+ }
+
// unknown MIME type
return NULL;
}
-#else // Unix
-
-MailCapEntry *
-wxFileTypeImpl::GetEntry(const wxFileType::MessageParameters& params) const
+size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString& mimetypes)
{
- wxString command;
- MailCapEntry *entry = m_manager->m_aEntries[m_index];
- while ( entry != NULL ) {
- // notice that an empty command would always succeed (it's ok)
- command = wxFileType::ExpandCommand(entry->GetTestCmd(), params);
+ // enumerate all keys under MIME_DATABASE_KEY
+ wxRegKey key(wxRegKey::HKCR, MIME_DATABASE_KEY);
- if ( command.IsEmpty() || (system(command) == 0) ) {
- // ok, passed
- wxLogTrace("Test '%s' for mime type '%s' succeeded.",
- command.c_str(), params.GetMimeType().c_str());
- break;
- }
- else {
- wxLogTrace("Test '%s' for mime type '%s' failed.",
- command.c_str(), params.GetMimeType().c_str());
- }
+ wxString type;
+ long cookie;
+ bool cont = key.GetFirstKey(type, cookie);
+ while ( cont )
+ {
+ mimetypes.Add(type);
- entry = entry->GetNext();
+ cont = key.GetNextKey(type, cookie);
}
- return entry;
+ return mimetypes.GetCount();
}
-bool
-wxFileTypeImpl::GetExpandedCommand(wxString *expandedCmd,
- const wxFileType::MessageParameters& params,
- bool open) const
+#elif defined ( __WXMAC__ )
+
+bool wxFileTypeImpl::GetCommand(wxString *command, const char *verb) const
{
- MailCapEntry *entry = GetEntry(params);
- if ( entry == NULL ) {
- // all tests failed...
- return FALSE;
- }
+ return FALSE;
+}
- wxString cmd = open ? entry->GetOpenCmd() : entry->GetPrintCmd();
- if ( cmd.IsEmpty() ) {
- // may happen, especially for "print"
- return FALSE;
- }
+// @@ this function is half implemented
+bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions)
+{
+ return FALSE;
+}
- *expandedCmd = wxFileType::ExpandCommand(cmd, params);
- return TRUE;
+bool wxFileTypeImpl::GetMimeType(wxString *mimeType) const
+{
+ if ( m_strFileType.Length() > 0 )
+ {
+ *mimeType = m_strFileType ;
+ return TRUE ;
+ }
+ else
+ return FALSE;
}
-bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions)
+bool wxFileTypeImpl::GetIcon(wxIcon *icon) const
{
- wxString strExtensions = m_manager->GetExtension(m_index);
- extensions.Empty();
+ // no such file type or no value or incorrect icon entry
+ return FALSE;
+}
+
+bool wxFileTypeImpl::GetDescription(wxString *desc) const
+{
+ return FALSE;
+}
+
+// extension -> file type
+wxFileType *
+wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& e)
+{
+ wxString ext = e ;
+ ext = ext.Lower() ;
+ if ( ext == "txt" )
+ {
+ wxFileType *fileType = new wxFileType;
+ fileType->m_impl->SetFileType("text/text");
+ fileType->m_impl->SetExt(ext);
+ return fileType;
+ }
+ else if ( ext == "htm" || ext == "html" )
+ {
+ wxFileType *fileType = new wxFileType;
+ fileType->m_impl->SetFileType("text/html");
+ fileType->m_impl->SetExt(ext);
+ return fileType;
+ }
+ else if ( ext == "gif" )
+ {
+ wxFileType *fileType = new wxFileType;
+ fileType->m_impl->SetFileType("image/gif");
+ fileType->m_impl->SetExt(ext);
+ return fileType;
+ }
+ else if ( ext == "png" )
+ {
+ wxFileType *fileType = new wxFileType;
+ fileType->m_impl->SetFileType("image/png");
+ fileType->m_impl->SetExt(ext);
+ return fileType;
+ }
+ else if ( ext == "jpg" || ext == "jpeg" )
+ {
+ wxFileType *fileType = new wxFileType;
+ fileType->m_impl->SetFileType("image/jpeg");
+ fileType->m_impl->SetExt(ext);
+ return fileType;
+ }
+ else if ( ext == "bmp" )
+ {
+ wxFileType *fileType = new wxFileType;
+ fileType->m_impl->SetFileType("image/bmp");
+ fileType->m_impl->SetExt(ext);
+ return fileType;
+ }
+ else if ( ext == "tif" || ext == "tiff" )
+ {
+ wxFileType *fileType = new wxFileType;
+ fileType->m_impl->SetFileType("image/tiff");
+ fileType->m_impl->SetExt(ext);
+ return fileType;
+ }
+ else if ( ext == "xpm" )
+ {
+ wxFileType *fileType = new wxFileType;
+ fileType->m_impl->SetFileType("image/xpm");
+ fileType->m_impl->SetExt(ext);
+ return fileType;
+ }
+ else if ( ext == "xbm" )
+ {
+ wxFileType *fileType = new wxFileType;
+ fileType->m_impl->SetFileType("image/xbm");
+ fileType->m_impl->SetExt(ext);
+ return fileType;
+ }
+
+ // unknown extension
+ return NULL;
+}
+
+// MIME type -> extension -> file type
+wxFileType *
+wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType)
+{
+ return NULL;
+}
+
+size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString& mimetypes)
+{
+ wxFAIL_MSG( _T("TODO") ); // VZ: don't know anything about this for Mac
+
+ return 0;
+}
+
+#else // Unix
+
+// ============================================================================
+// Unix implementation
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// various statics
+// ----------------------------------------------------------------------------
+
+static wxGNOMEIconHandler gs_iconHandlerGNOME;
+static wxKDEIconHandler gs_iconHandlerKDE;
+
+bool wxGNOMEIconHandler::m_inited = FALSE;
+wxSortedArrayString wxGNOMEIconHandler::ms_mimetypes;
+wxArrayString wxGNOMEIconHandler::ms_icons;
+
+bool wxKDEIconHandler::m_inited = FALSE;
+wxSortedArrayString wxKDEIconHandler::ms_mimetypes;
+wxArrayString wxKDEIconHandler::ms_icons;
+
+ArrayIconHandlers wxMimeTypesManagerImpl::ms_iconHandlers;
+
+// ----------------------------------------------------------------------------
+// wxGNOMEIconHandler
+// ----------------------------------------------------------------------------
+
+// GNOME stores the info we're interested in in several locations:
+// 1. xxx.keys files under /usr/share/mime-info
+// 2. xxx.keys files under ~/.gnome/mime-info
+//
+// The format of xxx.keys file is the following:
+//
+// mimetype/subtype:
+// field=value
+//
+// with blank lines separating the entries and indented lines starting with
+// TABs. We're interested in the field icon-filename whose value is the path
+// containing the icon.
+
+void wxGNOMEIconHandler::LoadIconsFromKeyFile(const wxString& filename)
+{
+ wxTextFile textfile(filename);
+ if ( !textfile.Open() )
+ return;
+
+ // values for the entry being parsed
+ wxString curMimeType, curIconFile;
+
+ const wxChar *pc;
+ size_t nLineCount = textfile.GetLineCount();
+ for ( size_t nLine = 0; ; nLine++ )
+ {
+ if ( nLine < nLineCount )
+ {
+ pc = textfile[nLine].c_str();
+ if ( *pc == _T('#') )
+ {
+ // skip comments
+ continue;
+ }
+ }
+ else
+ {
+ // so that we will fall into the "if" below
+ pc = NULL;
+ }
+
+ if ( !pc || !*pc )
+ {
+ // end of the entry
+ if ( !!curMimeType && !!curIconFile )
+ {
+ // do we already know this mimetype?
+ int i = ms_mimetypes.Index(curMimeType);
+ if ( i == wxNOT_FOUND )
+ {
+ // add a new entry
+ size_t n = ms_mimetypes.Add(curMimeType);
+ ms_icons.Insert(curIconFile, n);
+ }
+ else
+ {
+ // replace the existing one (this means that the directories
+ // should be searched in order of increased priority!)
+ ms_icons[(size_t)i] = curIconFile;
+ }
+ }
+
+ if ( !pc )
+ {
+ // the end - this can only happen if nLine == nLineCount
+ break;
+ }
+
+ curIconFile.Empty();
+
+ continue;
+ }
+
+ // what do we have here?
+ if ( *pc == _T('\t') )
+ {
+ // this is a field=value ling
+ pc++; // skip leading TAB
+
+ static const int lenField = 13; // strlen("icon-filename")
+ if ( wxStrncmp(pc, _T("icon-filename"), lenField) == 0 )
+ {
+ // skip '=' which follows and take everything left until the end
+ // of line
+ curIconFile = pc + lenField + 1;
+ }
+ //else: some other field, we don't care
+ }
+ else
+ {
+ // this is the start of the new section
+ curMimeType.Empty();
+
+ while ( *pc != _T(':') && *pc != _T('\0') )
+ {
+ curMimeType += *pc++;
+ }
+
+ if ( !*pc )
+ {
+ // we reached the end of line without finding the colon,
+ // something is wrong - ignore this line completely
+ wxLogDebug(_T("Unreckognized line %d in file '%s' ignored"),
+ nLine + 1, filename.c_str());
+
+ break;
+ }
+ }
+ }
+}
+
+void wxGNOMEIconHandler::LoadKeyFilesFromDir(const wxString& dirbase)
+{
+ wxASSERT_MSG( !!dirbase && !wxEndsWithPathSeparator(dirbase),
+ _T("base directory shouldn't end with a slash") );
+
+ wxString dirname = dirbase;
+ dirname << _T("/mime-info");
+
+ if ( !wxDir::Exists(dirname) )
+ return;
+
+ wxDir dir(dirname);
+ if ( !dir.IsOpened() )
+ return;
+
+ // we will concatenate it with filename to get the full path below
+ dirname += _T('/');
+
+ wxString filename;
+ bool cont = dir.GetFirst(&filename, _T("*.keys"), wxDIR_FILES);
+ while ( cont )
+ {
+ LoadIconsFromKeyFile(dirname + filename);
+
+ cont = dir.GetNext(&filename);
+ }
+}
+
+void wxGNOMEIconHandler::Init()
+{
+ wxArrayString dirs;
+ dirs.Add(_T("/usr/share"));
+
+ wxString gnomedir;
+ wxGetHomeDir( &gnomedir );
+ gnomedir += _T("/.gnome");
+ dirs.Add( gnomedir );
+
+ size_t nDirs = dirs.GetCount();
+ for ( size_t nDir = 0; nDir < nDirs; nDir++ )
+ {
+ LoadKeyFilesFromDir(dirs[nDir]);
+ }
+
+ m_inited = TRUE;
+}
+
+bool wxGNOMEIconHandler::GetIcon(const wxString& mimetype, wxIcon *icon)
+{
+ if ( !m_inited )
+ {
+ Init();
+ }
+
+ int index = ms_mimetypes.Index(mimetype);
+ if ( index == wxNOT_FOUND )
+ return FALSE;
+
+ wxString iconname = ms_icons[(size_t)index];
+
+#if wxUSE_GUI
+ *icon = wxIcon(iconname);
+#else
+ // helpful for testing in console mode
+ wxLogDebug(_T("Found GNOME icon for '%s': '%s'\n"),
+ mimetype.c_str(), iconname.c_str());
+#endif
+
+ return TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// wxKDEIconHandler
+// ----------------------------------------------------------------------------
+
+// KDE stores the icon info in its .kdelnk files. The file for mimetype/subtype
+// may be found in either of the following locations
+//
+// 1. $KDEDIR/share/mimelnk/mimetype/subtype.kdelnk
+// 2. ~/.kde/share/mimelnk/mimetype/subtype.kdelnk
+//
+// The format of a .kdelnk file is almost the same as the one used by
+// wxFileConfig, i.e. there are groups, comments and entries. The icon is the
+// value for the entry "Type"
+
+void wxKDEIconHandler::LoadLinksForMimeSubtype(const wxString& dirbase,
+ const wxString& subdir,
+ const wxString& filename)
+{
+ wxFFile file(dirbase + filename);
+ if ( !file.IsOpened() )
+ return;
+
+ // these files are small, slurp the entire file at once
+ wxString text;
+ if ( !file.ReadAll(&text) )
+ return;
+
+ int pos = text.Find(_T("Icon="));
+ if ( pos == wxNOT_FOUND )
+ {
+ // no icon info
+ return;
+ }
+
+ wxString icon;
+
+ const wxChar *pc = text.c_str() + pos + 5; // 5 == strlen("Icon=")
+ while ( *pc && *pc != _T('\n') )
+ {
+ icon += *pc++;
+ }
+
+ if ( !!icon )
+ {
+ // don't check that the file actually exists - would be too slow
+ icon.Prepend(_T("/usr/share/icons/"));
+
+ // construct mimetype from the directory name and the basename of the
+ // file (it always has .kdelnk extension)
+ wxString mimetype;
+ mimetype << subdir << _T('/') << filename.BeforeLast(_T('.'));
+
+ // do we already have this MIME type?
+ int i = ms_mimetypes.Index(mimetype);
+ if ( i == wxNOT_FOUND )
+ {
+ // add it
+ size_t n = ms_mimetypes.Add(mimetype);
+ ms_icons.Insert(icon, n);
+ }
+ else
+ {
+ // replace the old value
+ ms_icons[(size_t)i] = icon;
+ }
+ }
+}
+
+void wxKDEIconHandler::LoadLinksForMimeType(const wxString& dirbase,
+ const wxString& subdir)
+{
+ wxString dirname = dirbase;
+ dirname += subdir;
+ wxDir dir(dirname);
+ if ( !dir.IsOpened() )
+ return;
+
+ dirname += _T('/');
+
+ wxString filename;
+ bool cont = dir.GetFirst(&filename, _T("*.kdelnk"), wxDIR_FILES);
+ while ( cont )
+ {
+ LoadLinksForMimeSubtype(dirname, subdir, filename);
+
+ cont = dir.GetNext(&filename);
+ }
+}
+
+void wxKDEIconHandler::LoadLinkFilesFromDir(const wxString& dirbase)
+{
+ wxASSERT_MSG( !!dirbase && !wxEndsWithPathSeparator(dirbase),
+ _T("base directory shouldn't end with a slash") );
+
+ wxString dirname = dirbase;
+ dirname << _T("/mimelnk");
+
+ if ( !wxDir::Exists(dirname) )
+ return;
+
+ wxDir dir(dirname);
+ if ( !dir.IsOpened() )
+ return;
+
+ // we will concatenate it with dir name to get the full path below
+ dirname += _T('/');
+
+ wxString subdir;
+ bool cont = dir.GetFirst(&subdir, wxEmptyString, wxDIR_DIRS);
+ while ( cont )
+ {
+ LoadLinksForMimeType(dirname, subdir);
+
+ cont = dir.GetNext(&subdir);
+ }
+}
+
+void wxKDEIconHandler::Init()
+{
+ wxArrayString dirs;
+
+ // the variable KDEDIR is set when KDE is running
+ const char *kdedir = getenv("KDEDIR");
+ if ( kdedir )
+ {
+ dirs.Add(wxString(kdedir) + _T("/share"));
+ }
+ else
+ {
+ // try to guess KDEDIR
+ dirs.Add(_T("/usr/share"));
+ dirs.Add(_T("/opt/kde/share"));
+ }
+
+ dirs.Add(wxGetHomeDir() + _T("/.kde/share"));
+
+ size_t nDirs = dirs.GetCount();
+ for ( size_t nDir = 0; nDir < nDirs; nDir++ )
+ {
+ LoadLinkFilesFromDir(dirs[nDir]);
+ }
+
+ m_inited = TRUE;
+}
+
+bool wxKDEIconHandler::GetIcon(const wxString& mimetype, wxIcon *icon)
+{
+ if ( !m_inited )
+ {
+ Init();
+ }
+
+ int index = ms_mimetypes.Index(mimetype);
+ if ( index == wxNOT_FOUND )
+ return FALSE;
+
+ wxString iconname = ms_icons[(size_t)index];
+
+#if wxUSE_GUI
+ *icon = wxIcon(iconname);
+#else
+ // helpful for testing in console mode
+ wxLogDebug(_T("Found KDE icon for '%s': '%s'\n"),
+ mimetype.c_str(), iconname.c_str());
+#endif
+
+ return TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// wxFileTypeImpl (Unix)
+// ----------------------------------------------------------------------------
+
+MailCapEntry *
+wxFileTypeImpl::GetEntry(const wxFileType::MessageParameters& params) const
+{
+ wxString command;
+ MailCapEntry *entry = m_manager->m_aEntries[m_index];
+ while ( entry != NULL ) {
+ // notice that an empty command would always succeed (it's ok)
+ command = wxFileType::ExpandCommand(entry->GetTestCmd(), params);
+
+ if ( command.IsEmpty() || (wxSystem(command) == 0) ) {
+ // ok, passed
+ wxLogTrace(wxT("Test '%s' for mime type '%s' succeeded."),
+ command.c_str(), params.GetMimeType().c_str());
+ break;
+ }
+ else {
+ wxLogTrace(wxT("Test '%s' for mime type '%s' failed."),
+ command.c_str(), params.GetMimeType().c_str());
+ }
+
+ entry = entry->GetNext();
+ }
+
+ return entry;
+}
+
+bool wxFileTypeImpl::GetIcon(wxIcon *icon) const
+{
+ wxString mimetype;
+ (void)GetMimeType(&mimetype);
+
+ ArrayIconHandlers& handlers = m_manager->GetIconHandlers();
+ size_t count = handlers.GetCount();
+ for ( size_t n = 0; n < count; n++ )
+ {
+ if ( handlers[n]->GetIcon(mimetype, icon) )
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+bool
+wxFileTypeImpl::GetExpandedCommand(wxString *expandedCmd,
+ const wxFileType::MessageParameters& params,
+ bool open) const
+{
+ MailCapEntry *entry = GetEntry(params);
+ if ( entry == NULL ) {
+ // all tests failed...
+ return FALSE;
+ }
+
+ wxString cmd = open ? entry->GetOpenCmd() : entry->GetPrintCmd();
+ if ( cmd.IsEmpty() ) {
+ // may happen, especially for "print"
+ return FALSE;
+ }
+
+ *expandedCmd = wxFileType::ExpandCommand(cmd, params);
+ return TRUE;
+}
+
+bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions)
+{
+ wxString strExtensions = m_manager->GetExtension(m_index);
+ extensions.Empty();
// one extension in the space or comma delimitid list
wxString strExt;
- for ( const char *p = strExtensions; ; p++ ) {
- if ( *p == ' ' || *p == ',' || *p == '\0' ) {
+ for ( const wxChar *p = strExtensions; ; p++ ) {
+ if ( *p == wxT(' ') || *p == wxT(',') || *p == wxT('\0') ) {
if ( !strExt.IsEmpty() ) {
extensions.Add(strExt);
strExt.Empty();
//else: repeated spaces (shouldn't happen, but it's not that
// important if it does happen)
- if ( *p == '\0' )
+ if ( *p == wxT('\0') )
break;
}
- else if ( *p == '.' ) {
+ else if ( *p == wxT('.') ) {
// remove the dot from extension (but only if it's the first char)
if ( !strExt.IsEmpty() ) {
- strExt += '.';
+ strExt += wxT('.');
}
//else: no, don't append it
}
return TRUE;
}
+// ----------------------------------------------------------------------------
+// wxMimeTypesManagerImpl (Unix)
+// ----------------------------------------------------------------------------
+
+/* static */
+ArrayIconHandlers& wxMimeTypesManagerImpl::GetIconHandlers()
+{
+ if ( ms_iconHandlers.GetCount() == 0 )
+ {
+ ms_iconHandlers.Add(&gs_iconHandlerGNOME);
+ ms_iconHandlers.Add(&gs_iconHandlerKDE);
+ }
+
+ return ms_iconHandlers;
+}
+
// read system and user mailcaps (TODO implement mime.types support)
wxMimeTypesManagerImpl::wxMimeTypesManagerImpl()
{
// directories where we look for mailcap and mime.types by default
// (taken from metamail(1) sources)
- static const char *aStandardLocations[] =
+ static const wxChar *aStandardLocations[] =
{
- "/etc",
- "/usr/etc",
- "/usr/local/etc",
- "/etc/mail",
- "/usr/public/lib"
+ wxT("/etc"),
+ wxT("/usr/etc"),
+ wxT("/usr/local/etc"),
+ wxT("/etc/mail"),
+ wxT("/usr/public/lib")
};
// first read the system wide file(s)
for ( size_t n = 0; n < WXSIZEOF(aStandardLocations); n++ ) {
wxString dir = aStandardLocations[n];
- wxString file = dir + "/mailcap";
+ wxString file = dir + wxT("/mailcap");
if ( wxFile::Exists(file) ) {
ReadMailcap(file);
}
- file = dir + "/mime.types";
+ file = dir + wxT("/mime.types");
if ( wxFile::Exists(file) ) {
ReadMimeTypes(file);
}
}
- wxString strHome = getenv("HOME");
+ wxString strHome = wxGetenv(wxT("HOME"));
// and now the users mailcap
- wxString strUserMailcap = strHome + "/.mailcap";
+ wxString strUserMailcap = strHome + wxT("/.mailcap");
if ( wxFile::Exists(strUserMailcap) ) {
ReadMailcap(strUserMailcap);
}
// read the users mime.types
- wxString strUserMimeTypes = strHome + "/.mime.types";
+ wxString strUserMimeTypes = strHome + wxT("/.mime.types");
if ( wxFile::Exists(strUserMimeTypes) ) {
ReadMimeTypes(strUserMimeTypes);
}
for ( size_t n = 0; n < count; n++ ) {
wxString extensions = m_aExtensions[n];
while ( !extensions.IsEmpty() ) {
- wxString field = extensions.BeforeFirst(' ');
- extensions = extensions.AfterFirst(' ');
+ wxString field = extensions.BeforeFirst(wxT(' '));
+ extensions = extensions.AfterFirst(wxT(' '));
// consider extensions as not being case-sensitive
if ( field.IsSameAs(ext, FALSE /* no case */) ) {
// then try to find "text/*" as match for "text/plain" (for example)
// NB: if mimeType doesn't contain '/' at all, BeforeFirst() will return
// the whole string - ok.
- wxString strCategory = mimetype.BeforeFirst('/');
+ wxString strCategory = mimetype.BeforeFirst(wxT('/'));
size_t nCount = m_aTypes.Count();
for ( size_t n = 0; n < nCount; n++ ) {
- if ( (m_aTypes[n].BeforeFirst('/') == strCategory ) &&
- m_aTypes[n].AfterFirst('/') == "*" ) {
+ if ( (m_aTypes[n].BeforeFirst(wxT('/')) == strCategory ) &&
+ m_aTypes[n].AfterFirst(wxT('/')) == wxT("*") ) {
index = n;
break;
}
}
}
+void wxMimeTypesManagerImpl::AddFallback(const wxFileTypeInfo& filetype)
+{
+ wxString extensions;
+ const wxArrayString& exts = filetype.GetExtensions();
+ size_t nExts = exts.GetCount();
+ for ( size_t nExt = 0; nExt < nExts; nExt++ ) {
+ if ( nExt > 0 ) {
+ extensions += wxT(' ');
+ }
+ extensions += exts[nExt];
+ }
+
+ AddMimeTypeInfo(filetype.GetMimeType(),
+ extensions,
+ filetype.GetDescription());
+
+ AddMailcapInfo(filetype.GetMimeType(),
+ filetype.GetOpenCommand(),
+ filetype.GetPrintCommand(),
+ wxT(""),
+ filetype.GetDescription());
+}
+
+void wxMimeTypesManagerImpl::AddMimeTypeInfo(const wxString& strMimeType,
+ const wxString& strExtensions,
+ const wxString& strDesc)
+{
+ int index = m_aTypes.Index(strMimeType);
+ if ( index == wxNOT_FOUND ) {
+ // add a new entry
+ m_aTypes.Add(strMimeType);
+ m_aEntries.Add(NULL);
+ m_aExtensions.Add(strExtensions);
+ m_aDescriptions.Add(strDesc);
+ }
+ else {
+ // modify an existing one
+ if ( !strDesc.IsEmpty() ) {
+ m_aDescriptions[index] = strDesc; // replace old value
+ }
+ m_aExtensions[index] += ' ' + strExtensions;
+ }
+}
+
+void wxMimeTypesManagerImpl::AddMailcapInfo(const wxString& strType,
+ const wxString& strOpenCmd,
+ const wxString& strPrintCmd,
+ const wxString& strTest,
+ const wxString& strDesc)
+{
+ MailCapEntry *entry = new MailCapEntry(strOpenCmd, strPrintCmd, strTest);
+
+ int nIndex = m_aTypes.Index(strType);
+ if ( nIndex == wxNOT_FOUND ) {
+ // new file type
+ m_aTypes.Add(strType);
+
+ m_aEntries.Add(entry);
+ m_aExtensions.Add(wxT(""));
+ m_aDescriptions.Add(strDesc);
+ }
+ else {
+ // always append the entry in the tail of the list - info added with
+ // this function can only come from AddFallbacks()
+ MailCapEntry *entryOld = m_aEntries[nIndex];
+ if ( entryOld )
+ entry->Append(entryOld);
+ else
+ m_aEntries[nIndex] = entry;
+ }
+}
+
bool wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName)
{
- wxLogTrace("--- Parsing mime.types file '%s' ---", strFileName.c_str());
+ wxLogTrace(wxT("--- Parsing mime.types file '%s' ---"), strFileName.c_str());
wxTextFile file(strFileName);
if ( !file.Open() )
wxString strMimeType, strDesc, strExtensions;
size_t nLineCount = file.GetLineCount();
- const char *pc = NULL;
+ const wxChar *pc = NULL;
for ( size_t nLine = 0; nLine < nLineCount; nLine++ ) {
if ( pc == NULL ) {
// now we're at the start of the line
}
// skip whitespace
- while ( isspace(*pc) )
+ while ( wxIsspace(*pc) )
pc++;
- // comment?
- if ( *pc == '#' ) {
+ // comment or blank line?
+ if ( *pc == wxT('#') || !*pc ) {
// skip the whole line
pc = NULL;
continue;
}
// detect file format
- const char *pEqualSign = strchr(pc, '=');
+ const wxChar *pEqualSign = wxStrchr(pc, wxT('='));
if ( pEqualSign == NULL ) {
// brief format
// ------------
// first field is mime type
- for ( strMimeType.Empty(); !isspace(*pc) && *pc != '\0'; pc++ ) {
+ for ( strMimeType.Empty(); !wxIsspace(*pc) && *pc != wxT('\0'); pc++ ) {
strMimeType += *pc;
}
// skip whitespace
- while ( isspace(*pc) )
+ while ( wxIsspace(*pc) )
pc++;
// take all the rest of the string
wxString strLHS(pc, pEqualSign - pc);
// eat whitespace
- for ( pc = pEqualSign + 1; isspace(*pc); pc++ )
+ for ( pc = pEqualSign + 1; wxIsspace(*pc); pc++ )
;
- const char *pEnd;
- if ( *pc == '"' ) {
+ const wxChar *pEnd;
+ if ( *pc == wxT('"') ) {
// the string is quoted and ends at the matching quote
- pEnd = strchr(++pc, '"');
+ pEnd = wxStrchr(++pc, wxT('"'));
if ( pEnd == NULL ) {
wxLogWarning(_("Mime.types file %s, line %d: unterminated "
"quoted string."),
}
else {
// unquoted string ends at the first space
- for ( pEnd = pc; !isspace(*pEnd); pEnd++ )
+ for ( pEnd = pc; !wxIsspace(*pEnd); pEnd++ )
;
}
wxString strRHS(pc, pEnd - pc);
// check what follows this entry
- if ( *pEnd == '"' ) {
+ if ( *pEnd == wxT('"') ) {
// skip this quote
pEnd++;
}
- for ( pc = pEnd; isspace(*pc); pc++ )
+ for ( pc = pEnd; wxIsspace(*pc); pc++ )
;
// if there is something left, it may be either a '\\' to continue
// the line or the next field of the same entry
- bool entryEnded = *pc == '\0',
+ bool entryEnded = *pc == wxT('\0'),
nextFieldOnSameLine = FALSE;
if ( !entryEnded ) {
- nextFieldOnSameLine = ((*pc != '\\') || (pc[1] != '\0'));
+ nextFieldOnSameLine = ((*pc != wxT('\\')) || (pc[1] != wxT('\0')));
}
// now see what we got
- if ( strLHS == "type" ) {
+ if ( strLHS == wxT("type") ) {
strMimeType = strRHS;
}
- else if ( strLHS == "desc" ) {
+ else if ( strLHS == wxT("desc") ) {
strDesc = strRHS;
}
- else if ( strLHS == "exts" ) {
+ else if ( strLHS == wxT("exts") ) {
strExtensions = strRHS;
}
else {
// although it doesn't seem to be covered by RFCs, some programs
// (notably Netscape) create their entries with several comma
// separated extensions (RFC mention the spaces only)
- strExtensions.Replace(",", " ");
+ strExtensions.Replace(wxT(","), wxT(" "));
// also deal with the leading dot
- if ( !strExtensions.IsEmpty() && strExtensions[0] == '.' ) {
+ if ( !strExtensions.IsEmpty() && strExtensions[0u] == wxT('.') )
+ {
strExtensions.erase(0, 1);
}
- int index = m_aTypes.Index(strMimeType);
- if ( index == wxNOT_FOUND ) {
- // add a new entry
- m_aTypes.Add(strMimeType);
- m_aEntries.Add(NULL);
- m_aExtensions.Add(strExtensions);
- m_aDescriptions.Add(strDesc);
- }
- else {
- // modify an existing one
- if ( !strDesc.IsEmpty() ) {
- m_aDescriptions[index] = strDesc; // replace old value
- }
- m_aExtensions[index] += strExtensions;
- }
+ AddMimeTypeInfo(strMimeType, strExtensions, strDesc);
// finished with this line
pc = NULL;
bool wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName,
bool fallback)
{
- wxLogTrace("--- Parsing mailcap file '%s' ---", strFileName.c_str());
+ wxLogTrace(wxT("--- Parsing mailcap file '%s' ---"), strFileName.c_str());
wxTextFile file(strFileName);
if ( !file.Open() )
size_t nLineCount = file.GetLineCount();
for ( size_t nLine = 0; nLine < nLineCount; nLine++ ) {
// now we're at the start of the line
- const char *pc = file[nLine].c_str();
+ const wxChar *pc = file[nLine].c_str();
// skip whitespace
- while ( isspace(*pc) )
+ while ( wxIsspace(*pc) )
pc++;
// comment or empty string?
- if ( *pc == '#' || *pc == '\0' )
+ if ( *pc == wxT('#') || *pc == wxT('\0') )
continue;
// no, do parse
curField; // accumulator
for ( bool cont = TRUE; cont; pc++ ) {
switch ( *pc ) {
- case '\\':
+ case wxT('\\'):
// interpret the next character literally (notice that
// backslash can be used for line continuation)
- if ( *++pc == '\0' ) {
+ if ( *++pc == wxT('\0') ) {
// fetch the next line.
// pc currently points to nowhere, but after the next
}
break;
- case '\0':
+ case wxT('\0'):
cont = FALSE; // end of line reached, exit the loop
// fall through
- case ';':
+ case wxT(';'):
// store this field and start looking for the next one
// trim whitespaces from both sides
switch ( currentToken ) {
case Field_Type:
strType = curField;
- if ( strType.Find('/') == wxNOT_FOUND ) {
+ if ( strType.Find(wxT('/')) == wxNOT_FOUND ) {
// we interpret "type" as "type/*"
- strType += "/*";
+ strType += wxT("/*");
}
currentToken = Field_OpenCmd;
bool ok = TRUE;
// is this something of the form foo=bar?
- const char *pEq = strchr(curField, '=');
+ const wxChar *pEq = wxStrchr(curField, wxT('='));
if ( pEq != NULL ) {
- wxString lhs = curField.BeforeFirst('='),
- rhs = curField.AfterFirst('=');
+ wxString lhs = curField.BeforeFirst(wxT('=')),
+ rhs = curField.AfterFirst(wxT('='));
lhs.Trim(TRUE); // from right
rhs.Trim(FALSE); // from left
- if ( lhs == "print" )
+ if ( lhs == wxT("print") )
strPrintCmd = rhs;
- else if ( lhs == "test" )
+ else if ( lhs == wxT("test") )
strTest = rhs;
- else if ( lhs == "description" ) {
+ else if ( lhs == wxT("description") ) {
// it might be quoted
- if ( rhs[0u] == '"' &&
- rhs.Last() == '"' ) {
+ if ( rhs[0u] == wxT('"') &&
+ rhs.Last() == wxT('"') ) {
strDesc = wxString(rhs.c_str() + 1,
rhs.Len() - 2);
}
strDesc = rhs;
}
}
- else if ( lhs == "compose" ||
- lhs == "composetyped" ||
- lhs == "notes" ||
- lhs == "edit" )
+ else if ( lhs == wxT("compose") ||
+ lhs == wxT("composetyped") ||
+ lhs == wxT("notes") ||
+ lhs == wxT("edit") )
; // ignore
else
ok = FALSE;
// TODO support the flags:
// 1. create an xterm for 'needsterminal'
// 2. append "| $PAGER" for 'copiousoutput'
- if ( curField == "needsterminal" )
+ if ( curField == wxT("needsterminal") )
needsterminal = TRUE;
- else if ( curField == "copiousoutput" )
+ else if ( curField == wxT("copiousoutput") )
copiousoutput = TRUE;
- else if ( curField == "textualnewlines" )
+ else if ( curField == wxT("textualnewlines") )
; // ignore
else
ok = FALSE;
if ( !ok )
{
- // don't flood the user with error messages
- // if we don't understand something in his
- // mailcap, but give them in debug mode
- // because this might be useful for the
- // programmer
- wxLogDebug
- (
- "Mailcap file %s, line %d: unknown "
- "field '%s' for the MIME type "
- "'%s' ignored.",
- strFileName.c_str(),
- nLine + 1,
- curField.c_str(),
- strType.c_str()
- );
+ // we don't understand this field, but
+ // Netscape stores info in it, so don't warn
+ // about it
+ if ( curField.Left(16u) != "x-mozilla-flags=" )
+ {
+ // don't flood the user with error
+ // messages if we don't understand
+ // something in his mailcap, but give
+ // them in debug mode because this might
+ // be useful for the programmer
+ wxLogDebug
+ (
+ wxT("Mailcap file %s, line %d: "
+ "unknown field '%s' for the "
+ "MIME type '%s' ignored."),
+ strFileName.c_str(),
+ nLine + 1,
+ curField.c_str(),
+ strType.c_str()
+ );
+ }
}
}
break;
default:
- wxFAIL_MSG("unknown field type in mailcap");
+ wxFAIL_MSG(wxT("unknown field type in mailcap"));
}
// next token starts immediately after ';'
strPrintCmd,
strTest);
+ // NB: because of complications below (we must get entries priority
+ // right), we can't use AddMailcapInfo() here, unfortunately.
strType.MakeLower();
int nIndex = m_aTypes.Index(strType);
if ( nIndex == wxNOT_FOUND ) {
m_aTypes.Add(strType);
m_aEntries.Add(entry);
- m_aExtensions.Add("");
+ m_aExtensions.Add(wxT(""));
m_aDescriptions.Add(strDesc);
}
else {
return TRUE;
}
-#endif // OS type
+size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString& mimetypes)
+{
+ mimetypes.Empty();
+
+ wxString type;
+ size_t count = m_aTypes.GetCount();
+ for ( size_t n = 0; n < count; n++ )
+ {
+ // don't return template types from here (i.e. anything containg '*')
+ type = m_aTypes[n];
+ if ( type.Find(_T('*')) == wxNOT_FOUND )
+ {
+ mimetypes.Add(type);
+ }
+ }
+
+ return mimetypes.GetCount();
+}
+
+#endif
+ // OS type
+
+#endif
+ // wxUSE_FILE && wxUSE_TEXTFILE
#endif
// __WIN16__