]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/mimetype.cpp
Small bugfix
[wxWidgets.git] / src / common / mimetype.cpp
index 6ffbf1c33a9615f8e591a09376580418915b2176..ee32feae8883f48af2b9ac0ff1d7b0307dee241d 100644 (file)
 #ifdef __WXMSW__
     #include "wx/msw/registry.h"
     #include "windows.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/textfile.h"
+    #include "wx/dir.h"
+    #include "wx/utils.h"
 #endif // OS
 
 #include "wx/mimetype.h"
 #endif // OS
 
 #include "wx/mimetype.h"
@@ -119,8 +122,8 @@ private:
 
     // we use either m_info or read the data from the registry if m_info == NULL
     const wxFileTypeInfo *m_info;
 
     // we use either m_info or read the data from the registry if m_info == NULL
     const wxFileTypeInfo *m_info;
-    wxString        m_strFileType,
-                    m_ext;
+    wxString m_strFileType,         // may be empty
+             m_ext;
 };
 
 WX_DECLARE_EXPORTED_OBJARRAY(wxFileTypeInfo, wxArrayFileTypeInfo);
 };
 
 WX_DECLARE_EXPORTED_OBJARRAY(wxFileTypeInfo, wxArrayFileTypeInfo);
@@ -138,7 +141,7 @@ public:
     wxFileType *GetFileTypeFromExtension(const wxString& ext);
     wxFileType *GetFileTypeFromMimeType(const wxString& mimeType);
 
     wxFileType *GetFileTypeFromExtension(const wxString& ext);
     wxFileType *GetFileTypeFromMimeType(const wxString& mimeType);
 
-    size_t EnumAllFileTypes(wxFileType **filetypes);
+    size_t EnumAllFileTypes(wxArrayString& mimetypes);
 
     // this are NOPs under Windows
     bool ReadMailcap(const wxString& filename, bool fallback = TRUE)
 
     // this are NOPs under Windows
     bool ReadMailcap(const wxString& filename, bool fallback = TRUE)
@@ -167,7 +170,7 @@ public :
     wxFileType *GetFileTypeFromExtension(const wxString& ext);
     wxFileType *GetFileTypeFromMimeType(const wxString& mimeType);
 
     wxFileType *GetFileTypeFromExtension(const wxString& ext);
     wxFileType *GetFileTypeFromMimeType(const wxString& mimeType);
 
-    size_t EnumAllFileTypes(wxFileType **filetypes);
+    size_t EnumAllFileTypes(wxArrayString& mimetypes);
 
     // this are NOPs under MacOS
     bool ReadMailcap(const wxString& filename, bool fallback = TRUE) { return TRUE; }
 
     // this are NOPs under MacOS
     bool ReadMailcap(const wxString& filename, bool fallback = TRUE) { return TRUE; }
@@ -341,6 +344,54 @@ private:
 
 WX_DEFINE_ARRAY(MailCapEntry *, ArrayTypeEntries);
 
 
 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
 class wxMimeTypesManagerImpl
 {
 friend class wxFileTypeImpl; // give it access to m_aXXX variables
@@ -354,7 +405,7 @@ public:
     wxFileType *GetFileTypeFromExtension(const wxString& ext);
     wxFileType *GetFileTypeFromMimeType(const wxString& mimeType);
 
     wxFileType *GetFileTypeFromExtension(const wxString& ext);
     wxFileType *GetFileTypeFromMimeType(const wxString& mimeType);
 
-    size_t EnumAllFileTypes(wxFileType **filetypes);
+    size_t EnumAllFileTypes(wxArrayString& mimetypes);
 
     bool ReadMailcap(const wxString& filename, bool fallback = FALSE);
     bool ReadMimeTypes(const wxString& filename);
 
     bool ReadMailcap(const wxString& filename, bool fallback = FALSE);
     bool ReadMimeTypes(const wxString& filename);
@@ -376,11 +427,17 @@ public:
         // file type
     wxString GetExtension(size_t index) { return m_aExtensions[index]; }
 
         // 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
 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
 };
 
 class wxFileTypeImpl
@@ -394,8 +451,7 @@ public:
     bool GetExtensions(wxArrayString& extensions);
     bool GetMimeType(wxString *mimeType) const
         { *mimeType = m_manager->m_aTypes[m_index]; return TRUE; }
     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; }
 
     bool GetDescription(wxString *desc) const
         { *desc = m_manager->m_aDescriptions[m_index]; return TRUE; }
 
@@ -654,11 +710,9 @@ void wxMimeTypesManager::AddFallbacks(const wxFileTypeInfo *filetypes)
     }
 }
 
     }
 }
 
-size_t wxMimeTypesManager::EnumAllFileTypes(wxFileType **filetypes)
+size_t wxMimeTypesManager::EnumAllFileTypes(wxArrayString& mimetypes)
 {
 {
-    wxCHECK_MSG( filetypes, 0u, _T("bad pointer in EnumAllFileTypes") );
-
-    return m_impl->EnumAllFileTypes(filetypes);
+    return m_impl->EnumAllFileTypes(mimetypes);
 }
 
 // ============================================================================
 }
 
 // ============================================================================
@@ -672,9 +726,20 @@ wxString wxFileTypeImpl::GetCommand(const wxChar *verb) const
     // suppress possible error messages
     wxLogNull nolog;
     wxString strKey;
     // suppress possible error messages
     wxLogNull nolog;
     wxString strKey;
-    strKey << m_strFileType << wxT("\\shell\\") << verb << wxT("\\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
     wxString command;
     if ( key.Open() ) {
         // it's the default value of the key
@@ -703,8 +768,8 @@ wxString wxFileTypeImpl::GetCommand(const wxChar *verb) const
             }
         }
     }
             }
         }
     }
+    //else: no such file type or no value, will return empty string
 
 
-    // no such file type or no value
     return command;
 }
 
     return command;
 }
 
@@ -777,7 +842,7 @@ bool wxFileTypeImpl::GetMimeType(wxString *mimeType) const
 
     // suppress possible error messages
     wxLogNull nolog;
 
     // suppress possible error messages
     wxLogNull nolog;
-    wxRegKey key(wxRegKey::HKCR, /*m_strFileType*/ wxT(".") + m_ext);
+    wxRegKey key(wxRegKey::HKCR, wxT(".") + m_ext);
     if ( key.Open() && key.QueryValue(wxT("Content Type"), *mimeType) ) {
         return TRUE;
     }
     if ( key.Open() && key.QueryValue(wxT("Content Type"), *mimeType) ) {
         return TRUE;
     }
@@ -879,6 +944,8 @@ wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext)
     // suppress possible error messages
     wxLogNull nolog;
 
     // suppress possible error messages
     wxLogNull nolog;
 
+    bool knownExtension = FALSE;
+
     wxString strFileType;
     wxRegKey key(wxRegKey::HKCR, str);
     if ( key.Open() ) {
     wxString strFileType;
     wxRegKey key(wxRegKey::HKCR, str);
     if ( key.Open() ) {
@@ -890,6 +957,12 @@ wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext)
 
             return fileType;
         }
 
             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
     }
 
     // check the fallbacks
@@ -905,8 +978,18 @@ wxMimeTypesManagerImpl::GetFileTypeFromExtension(const wxString& ext)
         }
     }
 
         }
     }
 
-    // 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
 }
 
 // MIME type -> extension -> file type
@@ -945,12 +1028,22 @@ wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType)
     return NULL;
 }
 
     return NULL;
 }
 
-size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxFileType **filetypes)
+size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString& mimetypes)
 {
     // enumerate all keys under MIME_DATABASE_KEY
     wxRegKey key(wxRegKey::HKCR, MIME_DATABASE_KEY);
 
 {
     // enumerate all keys under MIME_DATABASE_KEY
     wxRegKey key(wxRegKey::HKCR, MIME_DATABASE_KEY);
 
-    return 0;
+    wxString type;
+    long cookie;
+    bool cont = key.GetFirstKey(type, cookie);
+    while ( cont )
+    {
+        mimetypes.Add(type);
+
+        cont = key.GetNextKey(type, cookie);
+    }
+
+    return mimetypes.GetCount();
 }
 
 #elif defined ( __WXMAC__ )
 }
 
 #elif defined ( __WXMAC__ )
@@ -1069,7 +1162,7 @@ wxMimeTypesManagerImpl::GetFileTypeFromMimeType(const wxString& mimeType)
     return NULL;
 }
 
     return NULL;
 }
 
-size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxFileType **filetypes)
+size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString& mimetypes)
 {
     wxFAIL_MSG( _T("TODO") ); // VZ: don't know anything about this for Mac
 
 {
     wxFAIL_MSG( _T("TODO") ); // VZ: don't know anything about this for Mac
 
@@ -1078,6 +1171,386 @@ size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxFileType **filetypes)
 
 #else  // Unix
 
 
 #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
 {
 MailCapEntry *
 wxFileTypeImpl::GetEntry(const wxFileType::MessageParameters& params) const
 {
@@ -1104,6 +1577,22 @@ wxFileTypeImpl::GetEntry(const wxFileType::MessageParameters& params) const
     return entry;
 }
 
     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
 wxFileTypeImpl::GetExpandedCommand(wxString *expandedCmd,
                                    const wxFileType::MessageParameters& params,
@@ -1159,6 +1648,22 @@ bool wxFileTypeImpl::GetExtensions(wxArrayString& extensions)
     return TRUE;
 }
 
     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()
 {
 // read system and user mailcaps (TODO implement mime.types support)
 wxMimeTypesManagerImpl::wxMimeTypesManagerImpl()
 {
@@ -1364,8 +1869,8 @@ bool wxMimeTypesManagerImpl::ReadMimeTypes(const wxString& strFileName)
         while ( wxIsspace(*pc) )
             pc++;
 
         while ( wxIsspace(*pc) )
             pc++;
 
-        // comment?
-        if ( *pc == wxT('#') ) {
+        // comment or blank line?
+        if ( *pc == wxT('#') || !*pc ) {
             // skip the whole line
             pc = NULL;
             continue;
             // skip the whole line
             pc = NULL;
             continue;
@@ -1644,21 +2149,27 @@ bool wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName,
 
                                 if ( !ok )
                                 {
 
                                 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
-                                    (
-                                      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()
-                                    );
+                                    // 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()
+                                        );
+                                    }
                                 }
                             }
 
                                 }
                             }
 
@@ -1762,17 +2273,23 @@ bool wxMimeTypesManagerImpl::ReadMailcap(const wxString& strFileName,
     return TRUE;
 }
 
     return TRUE;
 }
 
-size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxFileType **filetypes)
+size_t wxMimeTypesManagerImpl::EnumAllFileTypes(wxArrayString& mimetypes)
 {
 {
-    size_t count = m_aTypes.GetCount();
+    mimetypes.Empty();
 
 
-    *filetypes = new wxFileType[count];
+    wxString type;
+    size_t count = m_aTypes.GetCount();
     for ( size_t n = 0; n < count; n++ )
     {
     for ( size_t n = 0; n < count; n++ )
     {
-        (*filetypes)[n].m_impl->Init(this, 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 count;
+    return mimetypes.GetCount();
 }
 
 #endif
 }
 
 #endif